@aiready/cli 0.15.0 → 0.15.2
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/README.md +10 -8
- package/dist/cli.js +194 -276
- package/dist/cli.mjs +183 -269
- package/package.json +13 -13
package/dist/cli.mjs
CHANGED
|
@@ -88,38 +88,6 @@ async function warnIfGraphCapExceeded(report, dirPath) {
|
|
|
88
88
|
void err;
|
|
89
89
|
}
|
|
90
90
|
}
|
|
91
|
-
function generateMarkdownReport(report, elapsedTime) {
|
|
92
|
-
let markdown = `# Consistency Analysis Report
|
|
93
|
-
|
|
94
|
-
`;
|
|
95
|
-
markdown += `**Generated:** ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
96
|
-
`;
|
|
97
|
-
markdown += `**Analysis Time:** ${elapsedTime}s
|
|
98
|
-
|
|
99
|
-
`;
|
|
100
|
-
markdown += `## Summary
|
|
101
|
-
|
|
102
|
-
`;
|
|
103
|
-
markdown += `- **Files Analyzed:** ${report.summary.filesAnalyzed}
|
|
104
|
-
`;
|
|
105
|
-
markdown += `- **Total Issues:** ${report.summary.totalIssues}
|
|
106
|
-
`;
|
|
107
|
-
markdown += ` - Naming: ${report.summary.namingIssues}
|
|
108
|
-
`;
|
|
109
|
-
markdown += ` - Patterns: ${report.summary.patternIssues}
|
|
110
|
-
|
|
111
|
-
`;
|
|
112
|
-
if (report.recommendations.length > 0) {
|
|
113
|
-
markdown += `## Recommendations
|
|
114
|
-
|
|
115
|
-
`;
|
|
116
|
-
report.recommendations.forEach((rec, i) => {
|
|
117
|
-
markdown += `${i + 1}. ${rec}
|
|
118
|
-
`;
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
return markdown;
|
|
122
|
-
}
|
|
123
91
|
|
|
124
92
|
// src/commands/report-formatter.ts
|
|
125
93
|
import chalk2 from "chalk";
|
|
@@ -476,7 +444,8 @@ function getProfileTools(profile) {
|
|
|
476
444
|
return [
|
|
477
445
|
ToolName.AiSignalClarity,
|
|
478
446
|
ToolName.AgentGrounding,
|
|
479
|
-
ToolName.TestabilityIndex
|
|
447
|
+
ToolName.TestabilityIndex,
|
|
448
|
+
ToolName.ContractEnforcement
|
|
480
449
|
];
|
|
481
450
|
case "cost":
|
|
482
451
|
return [ToolName.PatternDetect, ToolName.ContextAnalyzer];
|
|
@@ -486,7 +455,8 @@ function getProfileTools(profile) {
|
|
|
486
455
|
ToolName.NamingConsistency,
|
|
487
456
|
ToolName.ContextAnalyzer,
|
|
488
457
|
ToolName.PatternDetect,
|
|
489
|
-
ToolName.ChangeAmplification
|
|
458
|
+
ToolName.ChangeAmplification,
|
|
459
|
+
ToolName.ContractEnforcement
|
|
490
460
|
];
|
|
491
461
|
case "ui":
|
|
492
462
|
return [
|
|
@@ -497,7 +467,11 @@ function getProfileTools(profile) {
|
|
|
497
467
|
ToolName.AiSignalClarity
|
|
498
468
|
];
|
|
499
469
|
case "security":
|
|
500
|
-
return [
|
|
470
|
+
return [
|
|
471
|
+
ToolName.NamingConsistency,
|
|
472
|
+
ToolName.TestabilityIndex,
|
|
473
|
+
ToolName.ContractEnforcement
|
|
474
|
+
];
|
|
501
475
|
case "onboarding":
|
|
502
476
|
return [
|
|
503
477
|
ToolName.ContextAnalyzer,
|
|
@@ -870,6 +844,38 @@ ${chalk6.bold("CI/CD Integration:")}
|
|
|
870
844
|
Use --threshold and --fail-on to use AIReady as a quality gate in your CI pipelines.
|
|
871
845
|
When running in GitHub Actions, it will automatically emit annotations for found issues.
|
|
872
846
|
`;
|
|
847
|
+
function defineScanCommand(program2) {
|
|
848
|
+
program2.command("scan").description(
|
|
849
|
+
"Run comprehensive AI-readiness analysis (patterns + context + consistency)"
|
|
850
|
+
).argument("[directory]", "Directory to analyze", ".").option(
|
|
851
|
+
"-t, --tools <tools>",
|
|
852
|
+
"Tools to run (comma-separated: patterns,context,consistency,doc-drift,deps-health,aiSignalClarity,grounding,testability,changeAmplification)"
|
|
853
|
+
).option(
|
|
854
|
+
"--profile <type>",
|
|
855
|
+
"Scan profile to use (agentic, cost, logic, ui, security, onboarding)"
|
|
856
|
+
).option(
|
|
857
|
+
"--compare-to <path>",
|
|
858
|
+
"Compare results against a previous AIReady report JSON"
|
|
859
|
+
).option(
|
|
860
|
+
"--include <patterns>",
|
|
861
|
+
"File patterns to include (comma-separated)"
|
|
862
|
+
).option(
|
|
863
|
+
"--exclude <patterns>",
|
|
864
|
+
"File patterns to exclude (comma-separated)"
|
|
865
|
+
).option("-o, --output <format>", "Output format: console, json", "console").option("--output-file <path>", "Output file path (for json)").option("--score", "Calculate and display AI Readiness Score (0-100)").option("--no-score", "Disable calculating AI Readiness Score").option("--weights <weights>", "Custom scoring weights").option(
|
|
866
|
+
"--threshold <score>",
|
|
867
|
+
"Fail CI/CD if score below threshold (0-100)"
|
|
868
|
+
).option(
|
|
869
|
+
"--ci",
|
|
870
|
+
"CI mode: GitHub Actions annotations, no colors, fail on threshold"
|
|
871
|
+
).option(
|
|
872
|
+
"--fail-on <level>",
|
|
873
|
+
"Fail on issues: critical, major, any",
|
|
874
|
+
"critical"
|
|
875
|
+
).option("--api-key <key>", "Platform API key for automatic upload").option("--upload", "Automatically upload results to the platform").option("--server <url>", "Custom platform URL").addHelpText("after", SCAN_HELP_TEXT).action(async (directory, options) => {
|
|
876
|
+
await scanAction(directory, options);
|
|
877
|
+
});
|
|
878
|
+
}
|
|
873
879
|
|
|
874
880
|
// src/commands/init.ts
|
|
875
881
|
import { writeFileSync as writeFileSync2, existsSync as existsSync2 } from "fs";
|
|
@@ -1152,33 +1158,6 @@ function renderSafetyRating(safety) {
|
|
|
1152
1158
|
` AI Change Safety: ${color(`${icon} ${safety.toUpperCase()}`)}`
|
|
1153
1159
|
);
|
|
1154
1160
|
}
|
|
1155
|
-
function renderIssueSummaryBlock(summary) {
|
|
1156
|
-
const total = (summary.criticalIssues || 0) + (summary.majorIssues || 0) + (summary.minorIssues || 0);
|
|
1157
|
-
if (total === 0) {
|
|
1158
|
-
console.log(chalk8.green("\u2705 No significant issues found!\n"));
|
|
1159
|
-
return;
|
|
1160
|
-
}
|
|
1161
|
-
console.log(chalk8.bold("\u26A0\uFE0F Issues Found:\n"));
|
|
1162
|
-
if (summary.criticalIssues > 0)
|
|
1163
|
-
console.log(
|
|
1164
|
-
chalk8.red(` \u{1F534} Critical: ${chalk8.bold(summary.criticalIssues)}`)
|
|
1165
|
-
);
|
|
1166
|
-
if (summary.majorIssues > 0)
|
|
1167
|
-
console.log(
|
|
1168
|
-
chalk8.yellow(` \u{1F7E1} Major: ${chalk8.bold(summary.majorIssues)}`)
|
|
1169
|
-
);
|
|
1170
|
-
if (summary.minorIssues > 0)
|
|
1171
|
-
console.log(chalk8.blue(` \u{1F535} Minor: ${chalk8.bold(summary.minorIssues)}`));
|
|
1172
|
-
if (summary.totalPotentialSavings) {
|
|
1173
|
-
console.log(
|
|
1174
|
-
chalk8.green(
|
|
1175
|
-
`
|
|
1176
|
-
\u{1F4A1} Potential savings: ${chalk8.bold(summary.totalPotentialSavings.toLocaleString())} tokens
|
|
1177
|
-
`
|
|
1178
|
-
)
|
|
1179
|
-
);
|
|
1180
|
-
}
|
|
1181
|
-
}
|
|
1182
1161
|
function renderSubSection(title) {
|
|
1183
1162
|
console.log("\n" + coreGetDivider());
|
|
1184
1163
|
console.log(chalk8.bold.white(` ${title.toUpperCase()}`));
|
|
@@ -1195,6 +1174,36 @@ function renderToolScoreFooter(score) {
|
|
|
1195
1174
|
}
|
|
1196
1175
|
|
|
1197
1176
|
// src/commands/patterns.ts
|
|
1177
|
+
var PATTERNS_HELP_TEXT = `
|
|
1178
|
+
EXAMPLES:
|
|
1179
|
+
$ aiready patterns # Default analysis
|
|
1180
|
+
$ aiready patterns --similarity 0.6 # Stricter matching
|
|
1181
|
+
$ aiready patterns --min-lines 10 # Larger patterns only
|
|
1182
|
+
`;
|
|
1183
|
+
function definePatternsCommand(program2) {
|
|
1184
|
+
program2.command("patterns").description("Detect duplicate code patterns that confuse AI models").argument("[directory]", "Directory to analyze", ".").option(
|
|
1185
|
+
"-s, --similarity <number>",
|
|
1186
|
+
"Minimum similarity score (0-1)",
|
|
1187
|
+
"0.40"
|
|
1188
|
+
).option("-l, --min-lines <number>", "Minimum lines to consider", "5").option(
|
|
1189
|
+
"--max-candidates <number>",
|
|
1190
|
+
"Maximum candidates per block (performance tuning)"
|
|
1191
|
+
).option(
|
|
1192
|
+
"--min-shared-tokens <number>",
|
|
1193
|
+
"Minimum shared tokens for candidates (performance tuning)"
|
|
1194
|
+
).option(
|
|
1195
|
+
"--full-scan",
|
|
1196
|
+
"Disable smart defaults for comprehensive analysis (slower)"
|
|
1197
|
+
).option(
|
|
1198
|
+
"--include <patterns>",
|
|
1199
|
+
"File patterns to include (comma-separated)"
|
|
1200
|
+
).option(
|
|
1201
|
+
"--exclude <patterns>",
|
|
1202
|
+
"File patterns to exclude (comma-separated)"
|
|
1203
|
+
).option("-o, --output <format>", "Output format: console, json", "console").option("--output-file <path>", "Output file path (for json)").option("--score", "Calculate and display AI Readiness Score (0-100)").option("--no-score", "Disable calculating AI Readiness Score").addHelpText("after", PATTERNS_HELP_TEXT).action(async (directory, options) => {
|
|
1204
|
+
await patternsAction(directory, options);
|
|
1205
|
+
});
|
|
1206
|
+
}
|
|
1198
1207
|
async function patternsAction(directory, options) {
|
|
1199
1208
|
return await executeToolAction(directory, options, {
|
|
1200
1209
|
toolName: "pattern-detect",
|
|
@@ -1274,21 +1283,30 @@ async function patternsAction(directory, options) {
|
|
|
1274
1283
|
}
|
|
1275
1284
|
});
|
|
1276
1285
|
}
|
|
1277
|
-
var PATTERNS_HELP_TEXT = `
|
|
1278
|
-
EXAMPLES:
|
|
1279
|
-
$ aiready patterns # Default analysis
|
|
1280
|
-
$ aiready patterns --similarity 0.6 # Stricter matching
|
|
1281
|
-
$ aiready patterns --min-lines 10 # Larger patterns only
|
|
1282
|
-
`;
|
|
1283
1286
|
|
|
1284
1287
|
// src/commands/context.ts
|
|
1285
1288
|
import chalk10 from "chalk";
|
|
1286
1289
|
import { printTerminalHeader as printTerminalHeader2 } from "@aiready/core";
|
|
1290
|
+
function defineContextCommand(program2) {
|
|
1291
|
+
program2.command("context").description("Analyze context window costs and dependency fragmentation").argument("[directory]", "Directory to analyze", ".").option("--max-depth <number>", "Maximum acceptable import depth", "5").option(
|
|
1292
|
+
"--max-context <number>",
|
|
1293
|
+
"Maximum acceptable context budget (tokens)",
|
|
1294
|
+
"10000"
|
|
1295
|
+
).option(
|
|
1296
|
+
"--include <patterns>",
|
|
1297
|
+
"File patterns to include (comma-separated)"
|
|
1298
|
+
).option(
|
|
1299
|
+
"--exclude <patterns>",
|
|
1300
|
+
"File patterns to exclude (comma-separated)"
|
|
1301
|
+
).option("-o, --output <format>", "Output format: console, json", "console").option("--output-file <path>", "Output file path (for json)").option("--score", "Calculate and display AI Readiness Score (0-100)", true).option("--no-score", "Disable calculating AI Readiness Score").action(async (directory, options) => {
|
|
1302
|
+
await contextAction(directory, options);
|
|
1303
|
+
});
|
|
1304
|
+
}
|
|
1287
1305
|
async function contextAction(directory, options) {
|
|
1288
1306
|
return await executeToolAction(directory, options, {
|
|
1289
1307
|
toolName: "context-analyzer",
|
|
1290
1308
|
label: "Context analysis",
|
|
1291
|
-
emoji: "\u{
|
|
1309
|
+
emoji: "\u{1F9E9}",
|
|
1292
1310
|
defaults: {
|
|
1293
1311
|
maxDepth: 5,
|
|
1294
1312
|
maxContextBudget: 1e4,
|
|
@@ -1300,11 +1318,6 @@ async function contextAction(directory, options) {
|
|
|
1300
1318
|
maxDepth: opts.maxDepth ? parseInt(opts.maxDepth) : void 0,
|
|
1301
1319
|
maxContextBudget: opts.maxContext ? parseInt(opts.maxContext) : void 0
|
|
1302
1320
|
}),
|
|
1303
|
-
preAnalyze: async (resolvedDir, baseOptions) => {
|
|
1304
|
-
const { getSmartDefaults } = await import("@aiready/context-analyzer");
|
|
1305
|
-
const smartDefaults = await getSmartDefaults(resolvedDir, baseOptions);
|
|
1306
|
-
return { ...smartDefaults, ...baseOptions };
|
|
1307
|
-
},
|
|
1308
1321
|
importTool: async () => {
|
|
1309
1322
|
const { analyzeContext, generateSummary, calculateContextScore } = await import("@aiready/context-analyzer");
|
|
1310
1323
|
return {
|
|
@@ -1313,45 +1326,40 @@ async function contextAction(directory, options) {
|
|
|
1313
1326
|
calculateScore: calculateContextScore
|
|
1314
1327
|
};
|
|
1315
1328
|
},
|
|
1316
|
-
renderConsole: ({ summary, elapsedTime, score }) => {
|
|
1329
|
+
renderConsole: ({ results: _results, summary, elapsedTime, score }) => {
|
|
1317
1330
|
printTerminalHeader2("CONTEXT ANALYSIS SUMMARY");
|
|
1318
1331
|
console.log(
|
|
1319
|
-
chalk10.white(`\u{1F4C1}
|
|
1332
|
+
chalk10.white(`\u{1F4C1} Total files: ${chalk10.bold(summary.totalFiles)}`)
|
|
1320
1333
|
);
|
|
1321
1334
|
console.log(
|
|
1322
1335
|
chalk10.white(
|
|
1323
|
-
`\u{
|
|
1336
|
+
`\u{1F4B8} Total tokens (context budget): ${chalk10.bold(summary.totalTokens.toLocaleString())}`
|
|
1324
1337
|
)
|
|
1325
1338
|
);
|
|
1326
1339
|
console.log(
|
|
1327
|
-
chalk10.
|
|
1328
|
-
`\u{
|
|
1340
|
+
chalk10.cyan(
|
|
1341
|
+
`\u{1F4CA} Average context budget: ${chalk10.bold(summary.avgContextBudget.toFixed(0))} tokens`
|
|
1329
1342
|
)
|
|
1330
1343
|
);
|
|
1331
1344
|
console.log(
|
|
1332
|
-
chalk10.
|
|
1333
|
-
`)
|
|
1345
|
+
chalk10.gray(`\u23F1 Analysis time: ${chalk10.bold(elapsedTime + "s")}`)
|
|
1334
1346
|
);
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
const fileName = item.file.split("/").slice(-2).join("/");
|
|
1347
|
+
if (summary.fragmentedModules.length > 0) {
|
|
1348
|
+
renderSubSection("Top Fragmented Modules");
|
|
1349
|
+
summary.fragmentedModules.slice(0, 5).forEach((mod) => {
|
|
1350
|
+
const scoreColor = mod.fragmentationScore > 0.7 ? chalk10.red : mod.fragmentationScore > 0.4 ? chalk10.yellow : chalk10.green;
|
|
1340
1351
|
console.log(
|
|
1341
|
-
`
|
|
1352
|
+
` ${scoreColor("\u25A0")} ${chalk10.white(mod.domain.padEnd(20))} ${chalk10.bold((mod.fragmentationScore * 100).toFixed(0) + "%")} fragmentation`
|
|
1342
1353
|
);
|
|
1343
1354
|
});
|
|
1344
1355
|
}
|
|
1345
|
-
if (summary.
|
|
1346
|
-
renderSubSection("
|
|
1347
|
-
summary.
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
);
|
|
1356
|
+
if (summary.topExpensiveFiles.length > 0) {
|
|
1357
|
+
renderSubSection("Top Context-Expensive Files");
|
|
1358
|
+
summary.topExpensiveFiles.slice(0, 5).forEach((item) => {
|
|
1359
|
+
const icon = item.severity === "critical" ? "\u{1F534}" : item.severity === "major" ? "\u{1F7E1}" : "\u{1F535}";
|
|
1360
|
+
const color = item.severity === "critical" ? chalk10.red : item.severity === "major" ? chalk10.yellow : chalk10.blue;
|
|
1351
1361
|
console.log(
|
|
1352
|
-
chalk10.dim(
|
|
1353
|
-
` Token cost: ${module.totalTokens.toLocaleString()}, Cohesion: ${(module.avgCohesion * 100).toFixed(0)}%`
|
|
1354
|
-
)
|
|
1362
|
+
` ${icon} ${color(item.severity.toUpperCase())}: ${chalk10.white(item.file.split("/").pop())} ${chalk10.dim(`(${item.contextBudget.toLocaleString()} tokens)`)}`
|
|
1355
1363
|
);
|
|
1356
1364
|
});
|
|
1357
1365
|
}
|
|
@@ -1362,21 +1370,35 @@ async function contextAction(directory, options) {
|
|
|
1362
1370
|
|
|
1363
1371
|
// src/commands/consistency.ts
|
|
1364
1372
|
import chalk11 from "chalk";
|
|
1365
|
-
import {
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1373
|
+
import { printTerminalHeader as printTerminalHeader3 } from "@aiready/core";
|
|
1374
|
+
function defineConsistencyCommand(program2) {
|
|
1375
|
+
program2.command("consistency").description("Check naming conventions and architectural consistency").argument("[directory]", "Directory to analyze", ".").option("--naming", "Check naming conventions (default: true)").option("--no-naming", "Skip naming analysis").option("--patterns", "Check code patterns (default: true)").option("--no-patterns", "Skip pattern analysis").option(
|
|
1376
|
+
"--min-severity <level>",
|
|
1377
|
+
"Minimum severity: info|minor|major|critical",
|
|
1378
|
+
"info"
|
|
1379
|
+
).option(
|
|
1380
|
+
"--include <patterns>",
|
|
1381
|
+
"File patterns to include (comma-separated)"
|
|
1382
|
+
).option(
|
|
1383
|
+
"--exclude <patterns>",
|
|
1384
|
+
"File patterns to exclude (comma-separated)"
|
|
1385
|
+
).option(
|
|
1386
|
+
"-o, --output <format>",
|
|
1387
|
+
"Output format: console, json, markdown",
|
|
1388
|
+
"console"
|
|
1389
|
+
).option("--output-file <path>", "Output file path (for json/markdown)").option("--score", "Calculate and display AI Readiness Score (0-100)", true).option("--no-score", "Disable calculating AI Readiness Score").action(async (directory, options) => {
|
|
1390
|
+
await consistencyAction(directory, options);
|
|
1391
|
+
});
|
|
1392
|
+
}
|
|
1371
1393
|
async function consistencyAction(directory, options) {
|
|
1372
1394
|
return await executeToolAction(directory, options, {
|
|
1373
1395
|
toolName: "naming-consistency",
|
|
1374
1396
|
label: "Consistency analysis",
|
|
1375
|
-
emoji: "\u{
|
|
1397
|
+
emoji: "\u{1F4CF}",
|
|
1376
1398
|
defaults: {
|
|
1377
|
-
checkNaming:
|
|
1378
|
-
checkPatterns:
|
|
1379
|
-
minSeverity: "info",
|
|
1399
|
+
checkNaming: options.naming !== false,
|
|
1400
|
+
checkPatterns: options.patterns !== false,
|
|
1401
|
+
minSeverity: options.minSeverity || "info",
|
|
1380
1402
|
include: void 0,
|
|
1381
1403
|
exclude: void 0,
|
|
1382
1404
|
output: { format: "console", file: void 0 }
|
|
@@ -1387,119 +1409,68 @@ async function consistencyAction(directory, options) {
|
|
|
1387
1409
|
minSeverity: opts.minSeverity
|
|
1388
1410
|
}),
|
|
1389
1411
|
importTool: async () => {
|
|
1390
|
-
const { analyzeConsistency, calculateConsistencyScore } = await import("@aiready/consistency");
|
|
1412
|
+
const { analyzeConsistency, generateSummary, calculateConsistencyScore } = await import("@aiready/consistency");
|
|
1391
1413
|
return {
|
|
1392
|
-
analyze:
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
);
|
|
1399
|
-
}
|
|
1414
|
+
analyze: async (opts) => {
|
|
1415
|
+
const report = await analyzeConsistency(opts);
|
|
1416
|
+
return report;
|
|
1417
|
+
},
|
|
1418
|
+
generateSummary,
|
|
1419
|
+
calculateScore: calculateConsistencyScore
|
|
1400
1420
|
};
|
|
1401
1421
|
},
|
|
1402
|
-
renderConsole: ({ results, summary, elapsedTime, score
|
|
1403
|
-
|
|
1404
|
-
const { format: outputFormat, file: userOutputFile } = resolveOutputFormat2(options, finalOptions);
|
|
1405
|
-
if (outputFormat === "markdown") {
|
|
1406
|
-
const markdown = generateMarkdownReport(report, elapsedTime);
|
|
1407
|
-
const outputPath = resolveOutputPath2(
|
|
1408
|
-
userOutputFile,
|
|
1409
|
-
`aiready-report-${getReportTimestamp()}.md`,
|
|
1410
|
-
directory
|
|
1411
|
-
);
|
|
1412
|
-
writeFileSync3(outputPath, markdown);
|
|
1413
|
-
console.log(chalk11.green(`\u2705 Report saved to ${outputPath}`));
|
|
1414
|
-
return;
|
|
1415
|
-
}
|
|
1416
|
-
console.log(chalk11.bold("\n\u{1F4CA} Summary\n"));
|
|
1417
|
-
console.log(`Files Analyzed: ${chalk11.cyan(summary.filesAnalyzed)}`);
|
|
1418
|
-
console.log(`Total Issues: ${chalk11.yellow(summary.totalIssues)}`);
|
|
1419
|
-
console.log(` Naming: ${chalk11.yellow(summary.namingIssues)}`);
|
|
1420
|
-
console.log(` Patterns: ${chalk11.yellow(summary.patternIssues)}`);
|
|
1422
|
+
renderConsole: ({ results: report, summary, elapsedTime, score }) => {
|
|
1423
|
+
printTerminalHeader3("CONSISTENCY ANALYSIS SUMMARY");
|
|
1421
1424
|
console.log(
|
|
1422
|
-
|
|
1425
|
+
chalk11.white(`\u{1F4C1} Files analyzed: ${chalk11.bold(summary.filesAnalyzed)}`)
|
|
1423
1426
|
);
|
|
1424
|
-
console.log(
|
|
1425
|
-
`)
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
);
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
}
|
|
1456
|
-
console.log();
|
|
1457
|
-
shown++;
|
|
1458
|
-
}
|
|
1459
|
-
}
|
|
1460
|
-
}
|
|
1461
|
-
if (patternResults.length > 0) {
|
|
1462
|
-
console.log(chalk11.bold("\u{1F504} Pattern Issues\n"));
|
|
1463
|
-
let shown = 0;
|
|
1464
|
-
for (const patternFileResult of patternResults) {
|
|
1465
|
-
if (shown >= 5) break;
|
|
1466
|
-
for (const issue of patternFileResult.issues) {
|
|
1467
|
-
if (shown >= 5) break;
|
|
1468
|
-
const severityColor = issue.severity === "critical" ? chalk11.red : issue.severity === "major" ? chalk11.yellow : issue.severity === "minor" ? chalk11.blue : chalk11.gray;
|
|
1469
|
-
console.log(
|
|
1470
|
-
`${severityColor(issue.severity.toUpperCase())} ${chalk11.dim(`${issue.location.file}:${issue.location.line}`)}`
|
|
1471
|
-
);
|
|
1472
|
-
console.log(` ${issue.message}`);
|
|
1473
|
-
if (issue.suggestion) {
|
|
1474
|
-
console.log(
|
|
1475
|
-
` ${chalk11.dim("\u2192")} ${chalk11.italic(issue.suggestion)}`
|
|
1476
|
-
);
|
|
1477
|
-
}
|
|
1478
|
-
console.log();
|
|
1479
|
-
shown++;
|
|
1480
|
-
}
|
|
1427
|
+
console.log(
|
|
1428
|
+
chalk11.white(`\u26A0 Total issues: ${chalk11.bold(summary.totalIssues)}`)
|
|
1429
|
+
);
|
|
1430
|
+
console.log(
|
|
1431
|
+
chalk11.gray(`\u23F1 Analysis time: ${chalk11.bold(elapsedTime + "s")}`)
|
|
1432
|
+
);
|
|
1433
|
+
if (summary.totalIssues > 0 && report.results) {
|
|
1434
|
+
renderSubSection("Issues Breakdown");
|
|
1435
|
+
const sortedIssues = [...report.results].flatMap(
|
|
1436
|
+
(file) => (file.issues || []).map((issue) => ({
|
|
1437
|
+
...issue,
|
|
1438
|
+
file: file.fileName
|
|
1439
|
+
}))
|
|
1440
|
+
).sort((a, b) => {
|
|
1441
|
+
const levels = {
|
|
1442
|
+
critical: 4,
|
|
1443
|
+
major: 3,
|
|
1444
|
+
minor: 2,
|
|
1445
|
+
info: 1
|
|
1446
|
+
};
|
|
1447
|
+
return (levels[b.severity] || 0) - (levels[a.severity] || 0);
|
|
1448
|
+
}).slice(0, 10);
|
|
1449
|
+
sortedIssues.forEach((issue) => {
|
|
1450
|
+
const icon = issue.severity === "critical" ? "\u{1F534}" : issue.severity === "major" ? "\u{1F7E1}" : "\u{1F535}";
|
|
1451
|
+
const color = issue.severity === "critical" ? chalk11.red : issue.severity === "major" ? chalk11.yellow : chalk11.blue;
|
|
1452
|
+
console.log(
|
|
1453
|
+
` ${icon} ${color(issue.severity.toUpperCase())}: ${chalk11.white(issue.file)}${issue.line ? `:${issue.line}` : ""}`
|
|
1454
|
+
);
|
|
1455
|
+
console.log(` ${issue.message}`);
|
|
1456
|
+
if (issue.suggestion) {
|
|
1457
|
+
console.log(chalk11.dim(` \u{1F4A1} ${issue.suggestion}`));
|
|
1481
1458
|
}
|
|
1482
|
-
}
|
|
1483
|
-
if (report.recommendations?.length > 0) {
|
|
1484
|
-
console.log(chalk11.bold("\u{1F4A1} Recommendations\n"));
|
|
1485
|
-
report.recommendations.forEach((rec, i) => {
|
|
1486
|
-
console.log(`${i + 1}. ${rec}`);
|
|
1487
|
-
});
|
|
1488
1459
|
console.log();
|
|
1489
|
-
}
|
|
1490
|
-
}
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
console.log();
|
|
1460
|
+
});
|
|
1461
|
+
} else {
|
|
1462
|
+
console.log(
|
|
1463
|
+
chalk11.green("\n\u2728 Great! No consistency issues detected.\n")
|
|
1464
|
+
);
|
|
1495
1465
|
}
|
|
1466
|
+
renderToolScoreFooter(score);
|
|
1496
1467
|
}
|
|
1497
1468
|
});
|
|
1498
1469
|
}
|
|
1499
1470
|
|
|
1500
1471
|
// src/commands/visualize.ts
|
|
1501
1472
|
import chalk12 from "chalk";
|
|
1502
|
-
import { writeFileSync as
|
|
1473
|
+
import { writeFileSync as writeFileSync3, readFileSync as readFileSync3, existsSync as existsSync3, copyFileSync } from "fs";
|
|
1503
1474
|
import { resolve as resolvePath5 } from "path";
|
|
1504
1475
|
import { spawn } from "child_process";
|
|
1505
1476
|
import { handleCLIError as handleCLIError4 } from "@aiready/core";
|
|
@@ -1669,7 +1640,7 @@ Or specify a custom report:
|
|
|
1669
1640
|
const html = generateHTML(graph);
|
|
1670
1641
|
const defaultOutput = "visualization.html";
|
|
1671
1642
|
const outPath = resolvePath5(dirPath, options.output ?? defaultOutput);
|
|
1672
|
-
|
|
1643
|
+
writeFileSync3(outPath, html, "utf8");
|
|
1673
1644
|
console.log(chalk12.green(`\u2705 Visualization written to: ${outPath}`));
|
|
1674
1645
|
if (options.open || options.serve) {
|
|
1675
1646
|
const opener = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
@@ -1953,11 +1924,11 @@ EXAMPLES:
|
|
|
1953
1924
|
import chalk18 from "chalk";
|
|
1954
1925
|
import { resolve as resolvePath6 } from "path";
|
|
1955
1926
|
import { existsSync as existsSync4, readdirSync } from "fs";
|
|
1956
|
-
import { printTerminalHeader as
|
|
1927
|
+
import { printTerminalHeader as printTerminalHeader4 } from "@aiready/core";
|
|
1957
1928
|
async function remediateAction(directory, options) {
|
|
1958
1929
|
const resolvedDir = resolvePath6(process.cwd(), directory || ".");
|
|
1959
1930
|
const serverUrl = options.server || "https://platform.getaiready.dev";
|
|
1960
|
-
|
|
1931
|
+
printTerminalHeader4("AIREADY REMEDIATION SWARM");
|
|
1961
1932
|
console.log(chalk18.cyan("\u{1F916} Initializing local remediation agent..."));
|
|
1962
1933
|
let reportPath = options.report;
|
|
1963
1934
|
if (!reportPath) {
|
|
@@ -2075,42 +2046,15 @@ CONFIGURATION:
|
|
|
2075
2046
|
Config files (searched upward): aiready.json, .aiready.json, aiready.config.*
|
|
2076
2047
|
CLI options override config file settings
|
|
2077
2048
|
|
|
2078
|
-
Example aiready.json:
|
|
2079
|
-
{
|
|
2080
|
-
"scan": { "exclude": ["**/dist/**", "**/node_modules/**"] },
|
|
2081
|
-
"tools": {
|
|
2082
|
-
"pattern-detect": { "minSimilarity": 0.5 },
|
|
2083
|
-
"context-analyzer": { "maxContextBudget": 15000 }
|
|
2084
|
-
},
|
|
2085
|
-
"output": { "format": "json", "directory": ".aiready" }
|
|
2086
|
-
}
|
|
2087
|
-
|
|
2088
2049
|
VERSION: ${packageJson.version}
|
|
2089
2050
|
DOCUMENTATION: https://aiready.dev/docs/cli
|
|
2090
2051
|
GITHUB: https://github.com/caopengau/aiready-cli
|
|
2091
2052
|
LANDING: https://github.com/caopengau/aiready-landing`
|
|
2092
2053
|
);
|
|
2093
|
-
program
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
"Tools to run (comma-separated: patterns,context,consistency,doc-drift,deps-health,aiSignalClarity,grounding,testability,changeAmplification)"
|
|
2098
|
-
).option(
|
|
2099
|
-
"--profile <type>",
|
|
2100
|
-
"Scan profile to use (agentic, cost, logic, ui, security, onboarding)"
|
|
2101
|
-
).option(
|
|
2102
|
-
"--compare-to <path>",
|
|
2103
|
-
"Compare results against a previous AIReady report JSON"
|
|
2104
|
-
).option("--include <patterns>", "File patterns to include (comma-separated)").option("--exclude <patterns>", "File patterns to exclude (comma-separated)").option("-o, --output <format>", "Output format: console, json", "console").option("--output-file <path>", "Output file path (for json)").option("--score", "Calculate and display AI Readiness Score (0-100)").option("--no-score", "Disable calculating AI Readiness Score").option("--weights <weights>", "Custom scoring weights").option("--threshold <score>", "Fail CI/CD if score below threshold (0-100)").option(
|
|
2105
|
-
"--ci",
|
|
2106
|
-
"CI mode: GitHub Actions annotations, no colors, fail on threshold"
|
|
2107
|
-
).option(
|
|
2108
|
-
"--fail-on <level>",
|
|
2109
|
-
"Fail on issues: critical, major, any",
|
|
2110
|
-
"critical"
|
|
2111
|
-
).option("--api-key <key>", "Platform API key for automatic upload").option("--upload", "Automatically upload results to the platform").option("--server <url>", "Custom platform URL").addHelpText("after", SCAN_HELP_TEXT).action(async (directory, options) => {
|
|
2112
|
-
await scanAction(directory, options);
|
|
2113
|
-
});
|
|
2054
|
+
defineScanCommand(program);
|
|
2055
|
+
definePatternsCommand(program);
|
|
2056
|
+
defineContextCommand(program);
|
|
2057
|
+
defineConsistencyCommand(program);
|
|
2114
2058
|
program.command("init").description("Generate a default configuration (aiready.json)").option("-f, --force", "Overwrite existing configuration file").option(
|
|
2115
2059
|
"--js",
|
|
2116
2060
|
"Generate configuration as a JavaScript file (aiready.config.js)"
|
|
@@ -2118,36 +2062,6 @@ program.command("init").description("Generate a default configuration (aiready.j
|
|
|
2118
2062
|
const format = options.js ? "js" : "json";
|
|
2119
2063
|
await initAction({ force: options.force, format, full: options.full });
|
|
2120
2064
|
});
|
|
2121
|
-
program.command("patterns").description("Detect duplicate code patterns that confuse AI models").argument("[directory]", "Directory to analyze", ".").option("-s, --similarity <number>", "Minimum similarity score (0-1)", "0.40").option("-l, --min-lines <number>", "Minimum lines to consider", "5").option(
|
|
2122
|
-
"--max-candidates <number>",
|
|
2123
|
-
"Maximum candidates per block (performance tuning)"
|
|
2124
|
-
).option(
|
|
2125
|
-
"--min-shared-tokens <number>",
|
|
2126
|
-
"Minimum shared tokens for candidates (performance tuning)"
|
|
2127
|
-
).option(
|
|
2128
|
-
"--full-scan",
|
|
2129
|
-
"Disable smart defaults for comprehensive analysis (slower)"
|
|
2130
|
-
).option("--include <patterns>", "File patterns to include (comma-separated)").option("--exclude <patterns>", "File patterns to exclude (comma-separated)").option("-o, --output <format>", "Output format: console, json", "console").option("--output-file <path>", "Output file path (for json)").option("--score", "Calculate and display AI Readiness Score (0-100)").option("--no-score", "Disable calculating AI Readiness Score").addHelpText("after", PATTERNS_HELP_TEXT).action(async (directory, options) => {
|
|
2131
|
-
await patternsAction(directory, options);
|
|
2132
|
-
});
|
|
2133
|
-
program.command("context").description("Analyze context window costs and dependency fragmentation").argument("[directory]", "Directory to analyze", ".").option("--max-depth <number>", "Maximum acceptable import depth", "5").option(
|
|
2134
|
-
"--max-context <number>",
|
|
2135
|
-
"Maximum acceptable context budget (tokens)",
|
|
2136
|
-
"10000"
|
|
2137
|
-
).option("--include <patterns>", "File patterns to include (comma-separated)").option("--exclude <patterns>", "File patterns to exclude (comma-separated)").option("-o, --output <format>", "Output format: console, json", "console").option("--output-file <path>", "Output file path (for json)").option("--score", "Calculate and display AI Readiness Score (0-100)", true).option("--no-score", "Disable calculating AI Readiness Score").action(async (directory, options) => {
|
|
2138
|
-
await contextAction(directory, options);
|
|
2139
|
-
});
|
|
2140
|
-
program.command("consistency").description("Check naming conventions and architectural consistency").argument("[directory]", "Directory to analyze", ".").option("--naming", "Check naming conventions (default: true)").option("--no-naming", "Skip naming analysis").option("--patterns", "Check code patterns (default: true)").option("--no-patterns", "Skip pattern analysis").option(
|
|
2141
|
-
"--min-severity <level>",
|
|
2142
|
-
"Minimum severity: info|minor|major|critical",
|
|
2143
|
-
"info"
|
|
2144
|
-
).option("--include <patterns>", "File patterns to include (comma-separated)").option("--exclude <patterns>", "File patterns to exclude (comma-separated)").option(
|
|
2145
|
-
"-o, --output <format>",
|
|
2146
|
-
"Output format: console, json, markdown",
|
|
2147
|
-
"console"
|
|
2148
|
-
).option("--output-file <path>", "Output file path (for json/markdown)").option("--score", "Calculate and display AI Readiness Score (0-100)", true).option("--no-score", "Disable calculating AI Readiness Score").action(async (directory, options) => {
|
|
2149
|
-
await consistencyAction(directory, options);
|
|
2150
|
-
});
|
|
2151
2065
|
program.command("visualise").description("Alias for visualize (British spelling)").argument("[directory]", "Directory to analyze", ".").option(
|
|
2152
2066
|
"--report <path>",
|
|
2153
2067
|
"Report path (auto-detects latest .aiready/aiready-report-*.json if not provided)"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aiready/cli",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.2",
|
|
4
4
|
"description": "Assess and improve your codebase's AI-readiness. Get an AI Readiness Score (0-100) and detect semantic duplicates, context fragmentation, and naming inconsistencies.",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -24,18 +24,18 @@
|
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"chalk": "^5.3.0",
|
|
26
26
|
"commander": "^14.0.0",
|
|
27
|
-
"@aiready/agent-grounding": "0.14.
|
|
28
|
-
"@aiready/consistency": "0.21.
|
|
29
|
-
"@aiready/
|
|
30
|
-
"@aiready/
|
|
31
|
-
"@aiready/
|
|
32
|
-
"@aiready/doc-drift": "0.14.
|
|
33
|
-
"@aiready/change-amplification": "0.14.
|
|
34
|
-
"@aiready/contract-enforcement": "0.2.
|
|
35
|
-
"@aiready/ai-signal-clarity": "0.14.
|
|
36
|
-
"@aiready/pattern-detect": "0.17.
|
|
37
|
-
"@aiready/testability": "0.7.
|
|
38
|
-
"@aiready/visualizer": "0.7.
|
|
27
|
+
"@aiready/agent-grounding": "0.14.2",
|
|
28
|
+
"@aiready/consistency": "0.21.2",
|
|
29
|
+
"@aiready/context-analyzer": "0.22.2",
|
|
30
|
+
"@aiready/core": "0.24.2",
|
|
31
|
+
"@aiready/deps": "0.14.2",
|
|
32
|
+
"@aiready/doc-drift": "0.14.2",
|
|
33
|
+
"@aiready/change-amplification": "0.14.2",
|
|
34
|
+
"@aiready/contract-enforcement": "0.2.2",
|
|
35
|
+
"@aiready/ai-signal-clarity": "0.14.2",
|
|
36
|
+
"@aiready/pattern-detect": "0.17.2",
|
|
37
|
+
"@aiready/testability": "0.7.2",
|
|
38
|
+
"@aiready/visualizer": "0.7.2"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"@types/node": "^24.0.0",
|