@aiready/cli 0.14.24 → 0.14.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-L4VXALJD.mjs +280 -0
- package/dist/chunk-SK6WW6HW.mjs +325 -0
- package/dist/cli.js +633 -662
- package/dist/cli.mjs +382 -467
- package/dist/index.js +242 -213
- package/dist/index.mjs +7 -1
- package/package.json +12 -12
package/dist/cli.mjs
CHANGED
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
__require,
|
|
4
4
|
analyzeUnified,
|
|
5
5
|
scoreUnified
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-SK6WW6HW.mjs";
|
|
7
7
|
|
|
8
8
|
// src/cli.ts
|
|
9
9
|
import { Command } from "commander";
|
|
@@ -17,7 +17,7 @@ import { writeFileSync } from "fs";
|
|
|
17
17
|
import { resolve as resolvePath4 } from "path";
|
|
18
18
|
import {
|
|
19
19
|
handleJSONOutput as handleJSONOutput2,
|
|
20
|
-
handleCLIError as
|
|
20
|
+
handleCLIError as handleCLIError3,
|
|
21
21
|
resolveOutputPath,
|
|
22
22
|
getRepoMetadata,
|
|
23
23
|
emitIssuesAsAnnotations
|
|
@@ -37,8 +37,8 @@ import chalk from "chalk";
|
|
|
37
37
|
import { loadConfig, mergeConfigWithDefaults } from "@aiready/core";
|
|
38
38
|
async function warnIfGraphCapExceeded(report, dirPath) {
|
|
39
39
|
try {
|
|
40
|
-
const { loadConfig:
|
|
41
|
-
void
|
|
40
|
+
const { loadConfig: loadConfig2 } = await import("@aiready/core");
|
|
41
|
+
void loadConfig2;
|
|
42
42
|
let graphConfig = { maxNodes: 400, maxEdges: 600 };
|
|
43
43
|
const configPath = resolvePath(dirPath, "aiready.json");
|
|
44
44
|
if (existsSync(configPath)) {
|
|
@@ -405,7 +405,71 @@ import { loadMergedConfig, ToolName as ToolName2 } from "@aiready/core";
|
|
|
405
405
|
|
|
406
406
|
// src/commands/scan-helpers.ts
|
|
407
407
|
import chalk4 from "chalk";
|
|
408
|
-
import {
|
|
408
|
+
import {
|
|
409
|
+
handleCLIError as handleCLIError2,
|
|
410
|
+
getElapsedTime,
|
|
411
|
+
prepareActionConfig,
|
|
412
|
+
resolveOutputFormat,
|
|
413
|
+
formatStandardReport,
|
|
414
|
+
handleStandardJSONOutput,
|
|
415
|
+
ToolName
|
|
416
|
+
} from "@aiready/core";
|
|
417
|
+
async function executeToolAction(directory, options, config) {
|
|
418
|
+
console.log(chalk4.blue(`${config.emoji} ${config.label}...
|
|
419
|
+
`));
|
|
420
|
+
const startTime = Date.now();
|
|
421
|
+
try {
|
|
422
|
+
const { resolvedDir, finalOptions: baseOptions } = await prepareActionConfig(
|
|
423
|
+
directory,
|
|
424
|
+
config.defaults,
|
|
425
|
+
config.getCliOptions(options)
|
|
426
|
+
);
|
|
427
|
+
let finalOptions = baseOptions;
|
|
428
|
+
if (config.preAnalyze) {
|
|
429
|
+
finalOptions = await config.preAnalyze(resolvedDir, finalOptions);
|
|
430
|
+
}
|
|
431
|
+
const { analyze, generateSummary, calculateScore } = await config.importTool();
|
|
432
|
+
const results = await analyze(finalOptions);
|
|
433
|
+
const elapsedTime = getElapsedTime(startTime);
|
|
434
|
+
const summary = generateSummary(results);
|
|
435
|
+
let toolScore;
|
|
436
|
+
if (options.score && calculateScore) {
|
|
437
|
+
const resultsAny = results;
|
|
438
|
+
const scoreData = resultsAny.duplicates || resultsAny.issues || results;
|
|
439
|
+
const filesCount = resultsAny.length || resultsAny.summary?.filesAnalyzed || resultsAny.summary?.totalFiles;
|
|
440
|
+
toolScore = calculateScore(scoreData, filesCount);
|
|
441
|
+
}
|
|
442
|
+
const { format: outputFormat, file: userOutputFile } = resolveOutputFormat(
|
|
443
|
+
options,
|
|
444
|
+
finalOptions
|
|
445
|
+
);
|
|
446
|
+
const outputData = formatStandardReport({
|
|
447
|
+
results,
|
|
448
|
+
summary,
|
|
449
|
+
elapsedTime,
|
|
450
|
+
score: toolScore
|
|
451
|
+
});
|
|
452
|
+
if (outputFormat === "json") {
|
|
453
|
+
handleStandardJSONOutput({
|
|
454
|
+
outputData,
|
|
455
|
+
outputFile: userOutputFile,
|
|
456
|
+
resolvedDir
|
|
457
|
+
});
|
|
458
|
+
} else {
|
|
459
|
+
config.renderConsole({
|
|
460
|
+
results,
|
|
461
|
+
summary,
|
|
462
|
+
elapsedTime,
|
|
463
|
+
score: toolScore,
|
|
464
|
+
finalOptions
|
|
465
|
+
});
|
|
466
|
+
}
|
|
467
|
+
return outputData;
|
|
468
|
+
} catch (error) {
|
|
469
|
+
handleCLIError2(error, config.label);
|
|
470
|
+
return void 0;
|
|
471
|
+
}
|
|
472
|
+
}
|
|
409
473
|
function getProfileTools(profile) {
|
|
410
474
|
switch (profile.toLowerCase()) {
|
|
411
475
|
case "agentic":
|
|
@@ -713,15 +777,21 @@ async function scanAction(directory, options) {
|
|
|
713
777
|
});
|
|
714
778
|
}
|
|
715
779
|
await warnIfGraphCapExceeded(outputData, resolvedDir);
|
|
716
|
-
await handleGatekeeper(
|
|
780
|
+
await handleGatekeeper(
|
|
781
|
+
outputData,
|
|
782
|
+
scoringResult,
|
|
783
|
+
options,
|
|
784
|
+
finalOptions,
|
|
785
|
+
results
|
|
786
|
+
);
|
|
717
787
|
} catch (error) {
|
|
718
|
-
|
|
788
|
+
handleCLIError3(error, "Analysis");
|
|
719
789
|
}
|
|
720
790
|
}
|
|
721
|
-
async function handleGatekeeper(outputData, scoringResult, options, results) {
|
|
791
|
+
async function handleGatekeeper(outputData, scoringResult, options, finalOptions, results) {
|
|
722
792
|
if (!scoringResult) return;
|
|
723
|
-
const threshold = options.threshold ? parseInt(options.threshold) :
|
|
724
|
-
const failOnLevel = options.failOn ?? "critical";
|
|
793
|
+
const threshold = options.threshold ? parseInt(options.threshold) : finalOptions.threshold;
|
|
794
|
+
const failOnLevel = options.failOn ?? finalOptions.failOn ?? "critical";
|
|
725
795
|
const isCI = options.ci ?? process.env.CI === "true";
|
|
726
796
|
let shouldFail = false;
|
|
727
797
|
let failReason = "";
|
|
@@ -1026,144 +1096,160 @@ module.exports = ${JSON.stringify(defaultConfig, null, 2)};
|
|
|
1026
1096
|
}
|
|
1027
1097
|
|
|
1028
1098
|
// src/commands/patterns.ts
|
|
1099
|
+
import chalk9 from "chalk";
|
|
1100
|
+
import { printTerminalHeader } from "@aiready/core";
|
|
1101
|
+
|
|
1102
|
+
// src/utils/terminal-renderers.ts
|
|
1029
1103
|
import chalk8 from "chalk";
|
|
1030
1104
|
import {
|
|
1031
|
-
handleCLIError as handleCLIError3,
|
|
1032
|
-
getElapsedTime,
|
|
1033
1105
|
formatToolScore,
|
|
1034
|
-
|
|
1035
|
-
getTerminalDivider,
|
|
1036
|
-
prepareActionConfig,
|
|
1037
|
-
resolveOutputFormat,
|
|
1038
|
-
formatStandardReport,
|
|
1039
|
-
handleStandardJSONOutput
|
|
1106
|
+
getTerminalDivider as coreGetDivider
|
|
1040
1107
|
} from "@aiready/core";
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
cliOptions
|
|
1108
|
+
var SAFETY_ICONS = {
|
|
1109
|
+
safe: "\u2705",
|
|
1110
|
+
"moderate-risk": "\u26A0\uFE0F ",
|
|
1111
|
+
"high-risk": "\u{1F534}",
|
|
1112
|
+
"blind-risk": "\u{1F480}"
|
|
1113
|
+
};
|
|
1114
|
+
var SAFETY_COLORS = {
|
|
1115
|
+
safe: chalk8.green,
|
|
1116
|
+
"moderate-risk": chalk8.yellow,
|
|
1117
|
+
"high-risk": chalk8.red,
|
|
1118
|
+
"blind-risk": chalk8.bgRed.white
|
|
1119
|
+
};
|
|
1120
|
+
function renderToolHeader(label, emoji, score, rating) {
|
|
1121
|
+
console.log(
|
|
1122
|
+
` ${emoji} ${label}: ${chalk8.bold(score + "/100")} (${rating})`
|
|
1123
|
+
);
|
|
1124
|
+
}
|
|
1125
|
+
function renderSafetyRating(safety) {
|
|
1126
|
+
const icon = SAFETY_ICONS[safety] ?? "\u2753";
|
|
1127
|
+
const color = SAFETY_COLORS[safety] ?? chalk8.white;
|
|
1128
|
+
console.log(
|
|
1129
|
+
` AI Change Safety: ${color(`${icon} ${safety.toUpperCase()}`)}`
|
|
1130
|
+
);
|
|
1131
|
+
}
|
|
1132
|
+
function renderIssueSummaryBlock(summary) {
|
|
1133
|
+
const total = (summary.criticalIssues || 0) + (summary.majorIssues || 0) + (summary.minorIssues || 0);
|
|
1134
|
+
if (total === 0) {
|
|
1135
|
+
console.log(chalk8.green("\u2705 No significant issues found!\n"));
|
|
1136
|
+
return;
|
|
1137
|
+
}
|
|
1138
|
+
console.log(chalk8.bold("\u26A0\uFE0F Issues Found:\n"));
|
|
1139
|
+
if (summary.criticalIssues > 0)
|
|
1140
|
+
console.log(
|
|
1141
|
+
chalk8.red(` \u{1F534} Critical: ${chalk8.bold(summary.criticalIssues)}`)
|
|
1076
1142
|
);
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1143
|
+
if (summary.majorIssues > 0)
|
|
1144
|
+
console.log(
|
|
1145
|
+
chalk8.yellow(` \u{1F7E1} Major: ${chalk8.bold(summary.majorIssues)}`)
|
|
1080
1146
|
);
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1147
|
+
if (summary.minorIssues > 0)
|
|
1148
|
+
console.log(chalk8.blue(` \u{1F535} Minor: ${chalk8.bold(summary.minorIssues)}`));
|
|
1149
|
+
if (summary.totalPotentialSavings) {
|
|
1150
|
+
console.log(
|
|
1151
|
+
chalk8.green(
|
|
1152
|
+
`
|
|
1153
|
+
\u{1F4A1} Potential savings: ${chalk8.bold(summary.totalPotentialSavings.toLocaleString())} tokens
|
|
1154
|
+
`
|
|
1155
|
+
)
|
|
1090
1156
|
);
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1159
|
+
function renderSubSection(title) {
|
|
1160
|
+
console.log("\n" + coreGetDivider());
|
|
1161
|
+
console.log(chalk8.bold.white(` ${title.toUpperCase()}`));
|
|
1162
|
+
console.log(coreGetDivider() + "\n");
|
|
1163
|
+
}
|
|
1164
|
+
function renderToolScoreFooter(score) {
|
|
1165
|
+
if (score) {
|
|
1166
|
+
console.log(`
|
|
1167
|
+
\u{1F4CA} AI Readiness Score (${score.toolName || "Tool"})
|
|
1168
|
+
`);
|
|
1169
|
+
console.log(formatToolScore(score));
|
|
1170
|
+
console.log();
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
// src/commands/patterns.ts
|
|
1175
|
+
async function patternsAction(directory, options) {
|
|
1176
|
+
return await executeToolAction(directory, options, {
|
|
1177
|
+
toolName: "pattern-detect",
|
|
1178
|
+
label: "Pattern analysis",
|
|
1179
|
+
emoji: "\u{1F50D}",
|
|
1180
|
+
defaults: {
|
|
1181
|
+
useSmartDefaults: !options.fullScan,
|
|
1182
|
+
include: void 0,
|
|
1183
|
+
exclude: void 0,
|
|
1184
|
+
output: { format: "console", file: void 0 },
|
|
1185
|
+
minSimilarity: options.fullScan ? 0.4 : void 0,
|
|
1186
|
+
minLines: options.fullScan ? 5 : void 0
|
|
1187
|
+
},
|
|
1188
|
+
getCliOptions: (opts) => ({
|
|
1189
|
+
minSimilarity: opts.similarity ? parseFloat(opts.similarity) : void 0,
|
|
1190
|
+
minLines: opts.minLines ? parseInt(opts.minLines) : void 0,
|
|
1191
|
+
maxCandidatesPerBlock: opts.maxCandidates ? parseInt(opts.maxCandidates) : void 0,
|
|
1192
|
+
minSharedTokens: opts.minSharedTokens ? parseInt(opts.minSharedTokens) : void 0
|
|
1193
|
+
}),
|
|
1194
|
+
importTool: async () => {
|
|
1195
|
+
const { analyzePatterns, generateSummary, calculatePatternScore } = await import("@aiready/pattern-detect");
|
|
1196
|
+
return {
|
|
1197
|
+
analyze: analyzePatterns,
|
|
1198
|
+
generateSummary,
|
|
1199
|
+
calculateScore: calculatePatternScore
|
|
1200
|
+
};
|
|
1201
|
+
},
|
|
1202
|
+
renderConsole: ({ results, summary, elapsedTime, score }) => {
|
|
1203
|
+
const duplicates = results.duplicates || [];
|
|
1104
1204
|
printTerminalHeader("PATTERN ANALYSIS SUMMARY");
|
|
1105
1205
|
console.log(
|
|
1106
|
-
|
|
1206
|
+
chalk9.white(`\u{1F4C1} Files analyzed: ${chalk9.bold(results.length)}`)
|
|
1107
1207
|
);
|
|
1108
1208
|
console.log(
|
|
1109
|
-
|
|
1110
|
-
`\u26A0 Duplicate patterns found: ${
|
|
1209
|
+
chalk9.yellow(
|
|
1210
|
+
`\u26A0 Duplicate patterns found: ${chalk9.bold(summary.totalPatterns)}`
|
|
1111
1211
|
)
|
|
1112
1212
|
);
|
|
1113
1213
|
console.log(
|
|
1114
|
-
|
|
1115
|
-
`\u{1F4B0} Token cost (wasted): ${
|
|
1214
|
+
chalk9.red(
|
|
1215
|
+
`\u{1F4B0} Token cost (wasted): ${chalk9.bold(summary.totalTokenCost.toLocaleString())}`
|
|
1116
1216
|
)
|
|
1117
1217
|
);
|
|
1118
1218
|
console.log(
|
|
1119
|
-
|
|
1219
|
+
chalk9.gray(`\u23F1 Analysis time: ${chalk9.bold(elapsedTime + "s")}`)
|
|
1120
1220
|
);
|
|
1121
1221
|
const sortedTypes = Object.entries(summary.patternsByType || {}).filter(([, count]) => count > 0).sort(([, a], [, b]) => b - a);
|
|
1122
1222
|
if (sortedTypes.length > 0) {
|
|
1123
|
-
|
|
1124
|
-
console.log(chalk8.bold.white(" PATTERNS BY TYPE"));
|
|
1125
|
-
console.log(getTerminalDivider() + "\n");
|
|
1223
|
+
renderSubSection("Patterns By Type");
|
|
1126
1224
|
sortedTypes.forEach(([type, count]) => {
|
|
1127
|
-
console.log(` ${
|
|
1225
|
+
console.log(` ${chalk9.white(type.padEnd(15))} ${chalk9.bold(count)}`);
|
|
1128
1226
|
});
|
|
1129
1227
|
}
|
|
1130
1228
|
if (summary.totalPatterns > 0 && duplicates.length > 0) {
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
const severity = dup.similarity > 0.95 ? "CRITICAL" : dup.similarity > 0.9 ? "HIGH" : "MEDIUM";
|
|
1137
|
-
const severityIcon = dup.similarity > 0.95 ? "\u{1F534}" : dup.similarity > 0.9 ? "\u{1F7E1}" : "\u{1F535}";
|
|
1138
|
-
const file1Name = dup.file1.split("/").pop() || dup.file1;
|
|
1139
|
-
const file2Name = dup.file2.split("/").pop() || dup.file2;
|
|
1229
|
+
renderSubSection("Top Duplicate Patterns");
|
|
1230
|
+
[...duplicates].sort((a, b) => b.similarity - a.similarity).slice(0, 10).forEach((dup) => {
|
|
1231
|
+
const isHigh = dup.similarity > 0.9;
|
|
1232
|
+
const icon = dup.similarity > 0.95 ? "\u{1F534}" : isHigh ? "\u{1F7E1}" : "\u{1F535}";
|
|
1233
|
+
const label = dup.similarity > 0.95 ? "CRITICAL" : isHigh ? "HIGH" : "MEDIUM";
|
|
1140
1234
|
console.log(
|
|
1141
|
-
`${
|
|
1235
|
+
`${icon} ${label}: ${chalk9.bold(dup.file1.split("/").pop())} \u2194 ${chalk9.bold(dup.file2.split("/").pop())}`
|
|
1142
1236
|
);
|
|
1143
1237
|
console.log(
|
|
1144
|
-
` Similarity: ${
|
|
1238
|
+
` Similarity: ${chalk9.bold(Math.round(dup.similarity * 100) + "%")} | Wasted: ${chalk9.bold(dup.tokenCost.toLocaleString())} tokens each`
|
|
1145
1239
|
);
|
|
1146
1240
|
console.log(
|
|
1147
|
-
` Lines: ${
|
|
1241
|
+
` Lines: ${chalk9.cyan(dup.line1 + "-" + dup.endLine1)} \u2194 ${chalk9.cyan(dup.line2 + "-" + dup.endLine2)}
|
|
1148
1242
|
`
|
|
1149
1243
|
);
|
|
1150
1244
|
});
|
|
1151
1245
|
} else {
|
|
1152
1246
|
console.log(
|
|
1153
|
-
|
|
1247
|
+
chalk9.green("\n\u2728 Great! No duplicate patterns detected.\n")
|
|
1154
1248
|
);
|
|
1155
1249
|
}
|
|
1156
|
-
|
|
1157
|
-
console.log(getTerminalDivider());
|
|
1158
|
-
console.log(chalk8.bold.white(" AI READINESS SCORE (Patterns)"));
|
|
1159
|
-
console.log(getTerminalDivider() + "\n");
|
|
1160
|
-
console.log(formatToolScore(patternScore));
|
|
1161
|
-
console.log();
|
|
1162
|
-
}
|
|
1250
|
+
renderToolScoreFooter(score);
|
|
1163
1251
|
}
|
|
1164
|
-
}
|
|
1165
|
-
handleCLIError3(error, "Pattern analysis");
|
|
1166
|
-
}
|
|
1252
|
+
});
|
|
1167
1253
|
}
|
|
1168
1254
|
var PATTERNS_HELP_TEXT = `
|
|
1169
1255
|
EXAMPLES:
|
|
@@ -1173,300 +1259,150 @@ EXAMPLES:
|
|
|
1173
1259
|
`;
|
|
1174
1260
|
|
|
1175
1261
|
// src/commands/context.ts
|
|
1176
|
-
import
|
|
1177
|
-
import {
|
|
1178
|
-
handleCLIError as handleCLIError4,
|
|
1179
|
-
getElapsedTime as getElapsedTime2,
|
|
1180
|
-
formatToolScore as formatToolScore2,
|
|
1181
|
-
prepareActionConfig as prepareActionConfig2,
|
|
1182
|
-
resolveOutputFormat as resolveOutputFormat2,
|
|
1183
|
-
formatStandardReport as formatStandardReport2,
|
|
1184
|
-
handleStandardJSONOutput as handleStandardJSONOutput2
|
|
1185
|
-
} from "@aiready/core";
|
|
1262
|
+
import chalk10 from "chalk";
|
|
1263
|
+
import { printTerminalHeader as printTerminalHeader2 } from "@aiready/core";
|
|
1186
1264
|
async function contextAction(directory, options) {
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1265
|
+
return await executeToolAction(directory, options, {
|
|
1266
|
+
toolName: "context-analyzer",
|
|
1267
|
+
label: "Context analysis",
|
|
1268
|
+
emoji: "\u{1F9E0}",
|
|
1269
|
+
defaults: {
|
|
1191
1270
|
maxDepth: 5,
|
|
1192
1271
|
maxContextBudget: 1e4,
|
|
1193
1272
|
include: void 0,
|
|
1194
1273
|
exclude: void 0,
|
|
1195
|
-
output: {
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
}
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
console.log(
|
|
1217
|
-
` Min cohesion: ${(finalOptions.minCohesion * 100).toFixed(1)}%`
|
|
1218
|
-
);
|
|
1219
|
-
console.log(
|
|
1220
|
-
` Max fragmentation: ${(finalOptions.maxFragmentation * 100).toFixed(1)}%`
|
|
1221
|
-
);
|
|
1222
|
-
console.log(` Analysis focus: ${finalOptions.focus}`);
|
|
1223
|
-
console.log("");
|
|
1224
|
-
const { analyzeContext, generateSummary, calculateContextScore } = await import("@aiready/context-analyzer");
|
|
1225
|
-
const results = await analyzeContext(finalOptions);
|
|
1226
|
-
const elapsedTime = getElapsedTime2(startTime);
|
|
1227
|
-
const summary = generateSummary(results);
|
|
1228
|
-
let contextScore;
|
|
1229
|
-
if (options.score) {
|
|
1230
|
-
contextScore = calculateContextScore(summary);
|
|
1231
|
-
}
|
|
1232
|
-
const { format: outputFormat, file: userOutputFile } = resolveOutputFormat2(
|
|
1233
|
-
options,
|
|
1234
|
-
finalOptions
|
|
1235
|
-
);
|
|
1236
|
-
if (outputFormat === "json") {
|
|
1237
|
-
const outputData = formatStandardReport2({
|
|
1238
|
-
results,
|
|
1239
|
-
summary,
|
|
1240
|
-
elapsedTime,
|
|
1241
|
-
score: contextScore
|
|
1242
|
-
});
|
|
1243
|
-
handleStandardJSONOutput2({
|
|
1244
|
-
outputData,
|
|
1245
|
-
outputFile: userOutputFile,
|
|
1246
|
-
resolvedDir
|
|
1247
|
-
});
|
|
1248
|
-
} else {
|
|
1249
|
-
const terminalWidth = process.stdout.columns ?? 80;
|
|
1250
|
-
const dividerWidth = Math.min(60, terminalWidth - 2);
|
|
1251
|
-
const divider = "\u2501".repeat(dividerWidth);
|
|
1252
|
-
console.log(chalk9.cyan(divider));
|
|
1253
|
-
console.log(chalk9.bold.white(" CONTEXT ANALYSIS SUMMARY"));
|
|
1254
|
-
console.log(chalk9.cyan(divider) + "\n");
|
|
1274
|
+
output: { format: "console", file: void 0 }
|
|
1275
|
+
},
|
|
1276
|
+
getCliOptions: (opts) => ({
|
|
1277
|
+
maxDepth: opts.maxDepth ? parseInt(opts.maxDepth) : void 0,
|
|
1278
|
+
maxContextBudget: opts.maxContext ? parseInt(opts.maxContext) : void 0
|
|
1279
|
+
}),
|
|
1280
|
+
preAnalyze: async (resolvedDir, baseOptions) => {
|
|
1281
|
+
const { getSmartDefaults } = await import("@aiready/context-analyzer");
|
|
1282
|
+
const smartDefaults = await getSmartDefaults(resolvedDir, baseOptions);
|
|
1283
|
+
return { ...smartDefaults, ...baseOptions };
|
|
1284
|
+
},
|
|
1285
|
+
importTool: async () => {
|
|
1286
|
+
const { analyzeContext, generateSummary, calculateContextScore } = await import("@aiready/context-analyzer");
|
|
1287
|
+
return {
|
|
1288
|
+
analyze: analyzeContext,
|
|
1289
|
+
generateSummary,
|
|
1290
|
+
calculateScore: calculateContextScore
|
|
1291
|
+
};
|
|
1292
|
+
},
|
|
1293
|
+
renderConsole: ({ summary, elapsedTime, score }) => {
|
|
1294
|
+
printTerminalHeader2("CONTEXT ANALYSIS SUMMARY");
|
|
1255
1295
|
console.log(
|
|
1256
|
-
|
|
1296
|
+
chalk10.white(`\u{1F4C1} Files analyzed: ${chalk10.bold(summary.totalFiles)}`)
|
|
1257
1297
|
);
|
|
1258
1298
|
console.log(
|
|
1259
|
-
|
|
1260
|
-
`\u{1F4CA} Total tokens: ${
|
|
1299
|
+
chalk10.white(
|
|
1300
|
+
`\u{1F4CA} Total tokens: ${chalk10.bold(summary.totalTokens.toLocaleString())}`
|
|
1261
1301
|
)
|
|
1262
1302
|
);
|
|
1263
1303
|
console.log(
|
|
1264
|
-
|
|
1265
|
-
`\u{1F4B0} Avg context budget: ${
|
|
1304
|
+
chalk10.yellow(
|
|
1305
|
+
`\u{1F4B0} Avg context budget: ${chalk10.bold(summary.avgContextBudget.toFixed(0))} tokens/file`
|
|
1266
1306
|
)
|
|
1267
1307
|
);
|
|
1268
1308
|
console.log(
|
|
1269
|
-
|
|
1309
|
+
chalk10.white(`\u23F1 Analysis time: ${chalk10.bold(elapsedTime + "s")}
|
|
1270
1310
|
`)
|
|
1271
1311
|
);
|
|
1272
|
-
|
|
1273
|
-
if (
|
|
1274
|
-
|
|
1275
|
-
if (summary.criticalIssues > 0) {
|
|
1276
|
-
console.log(
|
|
1277
|
-
chalk9.red(` \u{1F534} Critical: ${chalk9.bold(summary.criticalIssues)}`)
|
|
1278
|
-
);
|
|
1279
|
-
}
|
|
1280
|
-
if (summary.majorIssues > 0) {
|
|
1281
|
-
console.log(
|
|
1282
|
-
chalk9.yellow(` \u{1F7E1} Major: ${chalk9.bold(summary.majorIssues)}`)
|
|
1283
|
-
);
|
|
1284
|
-
}
|
|
1285
|
-
if (summary.minorIssues > 0) {
|
|
1286
|
-
console.log(
|
|
1287
|
-
chalk9.blue(` \u{1F535} Minor: ${chalk9.bold(summary.minorIssues)}`)
|
|
1288
|
-
);
|
|
1289
|
-
}
|
|
1290
|
-
console.log(
|
|
1291
|
-
chalk9.green(
|
|
1292
|
-
`
|
|
1293
|
-
\u{1F4A1} Potential savings: ${chalk9.bold(summary.totalPotentialSavings.toLocaleString())} tokens
|
|
1294
|
-
`
|
|
1295
|
-
)
|
|
1296
|
-
);
|
|
1297
|
-
} else {
|
|
1298
|
-
console.log(chalk9.green("\u2705 No significant issues found!\n"));
|
|
1299
|
-
}
|
|
1300
|
-
if (summary.deepFiles.length > 0) {
|
|
1301
|
-
console.log(chalk9.bold("\u{1F4CF} Deep Import Chains:\n"));
|
|
1302
|
-
console.log(
|
|
1303
|
-
chalk9.gray(` Average depth: ${summary.avgImportDepth.toFixed(1)}`)
|
|
1304
|
-
);
|
|
1305
|
-
console.log(
|
|
1306
|
-
chalk9.gray(` Maximum depth: ${summary.maxImportDepth}
|
|
1307
|
-
`)
|
|
1308
|
-
);
|
|
1312
|
+
renderIssueSummaryBlock(summary);
|
|
1313
|
+
if (summary.deepFiles && summary.deepFiles.length > 0) {
|
|
1314
|
+
renderSubSection("Deep Import Chains");
|
|
1309
1315
|
summary.deepFiles.slice(0, 10).forEach((item) => {
|
|
1310
1316
|
const fileName = item.file.split("/").slice(-2).join("/");
|
|
1311
1317
|
console.log(
|
|
1312
|
-
` ${
|
|
1318
|
+
` ${chalk10.cyan("\u2192")} ${chalk10.white(fileName)} ${chalk10.dim(`(depth: ${item.depth})`)}`
|
|
1313
1319
|
);
|
|
1314
1320
|
});
|
|
1315
|
-
console.log();
|
|
1316
1321
|
}
|
|
1317
|
-
if (summary.fragmentedModules.length > 0) {
|
|
1318
|
-
|
|
1319
|
-
console.log(
|
|
1320
|
-
chalk9.gray(
|
|
1321
|
-
` Average fragmentation: ${(summary.avgFragmentation * 100).toFixed(0)}%
|
|
1322
|
-
`
|
|
1323
|
-
)
|
|
1324
|
-
);
|
|
1322
|
+
if (summary.fragmentedModules && summary.fragmentedModules.length > 0) {
|
|
1323
|
+
renderSubSection("Fragmented Modules");
|
|
1325
1324
|
summary.fragmentedModules.slice(0, 10).forEach((module) => {
|
|
1326
1325
|
console.log(
|
|
1327
|
-
` ${
|
|
1326
|
+
` ${chalk10.yellow("\u25CF")} ${chalk10.white(module.domain)} - ${chalk10.dim(`${module.files.length} files, ${(module.fragmentationScore * 100).toFixed(0)}% scattered`)}`
|
|
1328
1327
|
);
|
|
1329
1328
|
console.log(
|
|
1330
|
-
|
|
1329
|
+
chalk10.dim(
|
|
1331
1330
|
` Token cost: ${module.totalTokens.toLocaleString()}, Cohesion: ${(module.avgCohesion * 100).toFixed(0)}%`
|
|
1332
1331
|
)
|
|
1333
1332
|
);
|
|
1334
1333
|
});
|
|
1335
|
-
console.log();
|
|
1336
|
-
}
|
|
1337
|
-
if (summary.lowCohesionFiles.length > 0) {
|
|
1338
|
-
console.log(chalk9.bold("\u{1F500} Low Cohesion Files:\n"));
|
|
1339
|
-
console.log(
|
|
1340
|
-
chalk9.gray(
|
|
1341
|
-
` Average cohesion: ${(summary.avgCohesion * 100).toFixed(0)}%
|
|
1342
|
-
`
|
|
1343
|
-
)
|
|
1344
|
-
);
|
|
1345
|
-
summary.lowCohesionFiles.slice(0, 10).forEach((item) => {
|
|
1346
|
-
const fileName = item.file.split("/").slice(-2).join("/");
|
|
1347
|
-
const scorePercent = (item.score * 100).toFixed(0);
|
|
1348
|
-
const color = item.score < 0.4 ? chalk9.red : chalk9.yellow;
|
|
1349
|
-
console.log(
|
|
1350
|
-
` ${color("\u25CB")} ${chalk9.white(fileName)} ${chalk9.dim(`(${scorePercent}% cohesion)`)}`
|
|
1351
|
-
);
|
|
1352
|
-
});
|
|
1353
|
-
console.log();
|
|
1354
|
-
}
|
|
1355
|
-
if (summary.topExpensiveFiles.length > 0) {
|
|
1356
|
-
console.log(chalk9.bold("\u{1F4B8} Most Expensive Files (Context Budget):\n"));
|
|
1357
|
-
summary.topExpensiveFiles.slice(0, 10).forEach((item) => {
|
|
1358
|
-
const fileName = item.file.split("/").slice(-2).join("/");
|
|
1359
|
-
const severityColor = item.severity === "critical" ? chalk9.red : item.severity === "major" ? chalk9.yellow : chalk9.blue;
|
|
1360
|
-
console.log(
|
|
1361
|
-
` ${severityColor("\u25CF")} ${chalk9.white(fileName)} ${chalk9.dim(`(${item.contextBudget.toLocaleString()} tokens)`)}`
|
|
1362
|
-
);
|
|
1363
|
-
});
|
|
1364
|
-
console.log();
|
|
1365
|
-
}
|
|
1366
|
-
if (contextScore) {
|
|
1367
|
-
console.log(chalk9.cyan(divider));
|
|
1368
|
-
console.log(chalk9.bold.white(" AI READINESS SCORE (Context)"));
|
|
1369
|
-
console.log(chalk9.cyan(divider) + "\n");
|
|
1370
|
-
console.log(formatToolScore2(contextScore));
|
|
1371
|
-
console.log();
|
|
1372
1334
|
}
|
|
1335
|
+
renderToolScoreFooter(score);
|
|
1373
1336
|
}
|
|
1374
|
-
}
|
|
1375
|
-
handleCLIError4(error, "Context analysis");
|
|
1376
|
-
}
|
|
1337
|
+
});
|
|
1377
1338
|
}
|
|
1378
1339
|
|
|
1379
1340
|
// src/commands/consistency.ts
|
|
1380
|
-
import
|
|
1341
|
+
import chalk11 from "chalk";
|
|
1381
1342
|
import { writeFileSync as writeFileSync3 } from "fs";
|
|
1382
1343
|
import {
|
|
1383
|
-
handleCLIError as handleCLIError5,
|
|
1384
|
-
getElapsedTime as getElapsedTime3,
|
|
1385
1344
|
resolveOutputPath as resolveOutputPath2,
|
|
1386
|
-
formatToolScore as
|
|
1387
|
-
|
|
1388
|
-
resolveOutputFormat as resolveOutputFormat3,
|
|
1389
|
-
formatStandardReport as formatStandardReport3,
|
|
1390
|
-
handleStandardJSONOutput as handleStandardJSONOutput3
|
|
1345
|
+
formatToolScore as formatToolScore2,
|
|
1346
|
+
resolveOutputFormat as resolveOutputFormat2
|
|
1391
1347
|
} from "@aiready/core";
|
|
1392
1348
|
async function consistencyAction(directory, options) {
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1349
|
+
return await executeToolAction(directory, options, {
|
|
1350
|
+
toolName: "naming-consistency",
|
|
1351
|
+
label: "Consistency analysis",
|
|
1352
|
+
emoji: "\u{1F50D}",
|
|
1353
|
+
defaults: {
|
|
1397
1354
|
checkNaming: true,
|
|
1398
1355
|
checkPatterns: true,
|
|
1399
1356
|
minSeverity: "info",
|
|
1400
1357
|
include: void 0,
|
|
1401
1358
|
exclude: void 0,
|
|
1402
|
-
output: {
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
{
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1359
|
+
output: { format: "console", file: void 0 }
|
|
1360
|
+
},
|
|
1361
|
+
getCliOptions: (opts) => ({
|
|
1362
|
+
checkNaming: opts.naming !== false,
|
|
1363
|
+
checkPatterns: opts.patterns !== false,
|
|
1364
|
+
minSeverity: opts.minSeverity
|
|
1365
|
+
}),
|
|
1366
|
+
importTool: async () => {
|
|
1367
|
+
const { analyzeConsistency, calculateConsistencyScore } = await import("@aiready/consistency");
|
|
1368
|
+
return {
|
|
1369
|
+
analyze: analyzeConsistency,
|
|
1370
|
+
generateSummary: (report) => report.summary,
|
|
1371
|
+
calculateScore: (summary, _resultsCount) => {
|
|
1372
|
+
return calculateConsistencyScore(
|
|
1373
|
+
summary.results?.flatMap((r) => r.issues) ?? [],
|
|
1374
|
+
summary.summary.filesAnalyzed
|
|
1375
|
+
);
|
|
1376
|
+
}
|
|
1377
|
+
};
|
|
1378
|
+
},
|
|
1379
|
+
renderConsole: ({ results, summary, elapsedTime, score, finalOptions }) => {
|
|
1380
|
+
const report = results;
|
|
1381
|
+
const { format: outputFormat, file: userOutputFile } = resolveOutputFormat2(options, finalOptions);
|
|
1382
|
+
if (outputFormat === "markdown") {
|
|
1383
|
+
const markdown = generateMarkdownReport(report, elapsedTime);
|
|
1384
|
+
const outputPath = resolveOutputPath2(
|
|
1385
|
+
userOutputFile,
|
|
1386
|
+
`aiready-report-${getReportTimestamp()}.md`,
|
|
1387
|
+
directory
|
|
1388
|
+
);
|
|
1389
|
+
writeFileSync3(outputPath, markdown);
|
|
1390
|
+
console.log(chalk11.green(`\u2705 Report saved to ${outputPath}`));
|
|
1391
|
+
return;
|
|
1416
1392
|
}
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
if (options.score) {
|
|
1423
|
-
const issues = report.results?.flatMap((r) => r.issues) ?? [];
|
|
1424
|
-
consistencyScore = calculateConsistencyScore(
|
|
1425
|
-
issues,
|
|
1426
|
-
report.summary.filesAnalyzed
|
|
1427
|
-
);
|
|
1428
|
-
}
|
|
1429
|
-
const { format: outputFormat, file: userOutputFile } = resolveOutputFormat3(
|
|
1430
|
-
options,
|
|
1431
|
-
finalOptions
|
|
1432
|
-
);
|
|
1433
|
-
if (outputFormat === "json") {
|
|
1434
|
-
const outputData = formatStandardReport3({
|
|
1435
|
-
report,
|
|
1436
|
-
summary: report.summary,
|
|
1437
|
-
elapsedTime,
|
|
1438
|
-
score: consistencyScore
|
|
1439
|
-
});
|
|
1440
|
-
handleStandardJSONOutput3({
|
|
1441
|
-
outputData,
|
|
1442
|
-
outputFile: userOutputFile,
|
|
1443
|
-
resolvedDir
|
|
1444
|
-
});
|
|
1445
|
-
} else if (outputFormat === "markdown") {
|
|
1446
|
-
const markdown = generateMarkdownReport(report, elapsedTime);
|
|
1447
|
-
const outputPath = resolveOutputPath2(
|
|
1448
|
-
userOutputFile,
|
|
1449
|
-
`aiready-report-${getReportTimestamp()}.md`,
|
|
1450
|
-
resolvedDir
|
|
1451
|
-
);
|
|
1452
|
-
writeFileSync3(outputPath, markdown);
|
|
1453
|
-
console.log(chalk10.green(`\u2705 Report saved to ${outputPath}`));
|
|
1454
|
-
} else {
|
|
1455
|
-
console.log(chalk10.bold("\n\u{1F4CA} Summary\n"));
|
|
1393
|
+
console.log(chalk11.bold("\n\u{1F4CA} Summary\n"));
|
|
1394
|
+
console.log(`Files Analyzed: ${chalk11.cyan(summary.filesAnalyzed)}`);
|
|
1395
|
+
console.log(`Total Issues: ${chalk11.yellow(summary.totalIssues)}`);
|
|
1396
|
+
console.log(` Naming: ${chalk11.yellow(summary.namingIssues)}`);
|
|
1397
|
+
console.log(` Patterns: ${chalk11.yellow(summary.patternIssues)}`);
|
|
1456
1398
|
console.log(
|
|
1457
|
-
`
|
|
1399
|
+
` Architecture: ${chalk11.yellow(summary.architectureIssues ?? 0)}`
|
|
1458
1400
|
);
|
|
1459
|
-
console.log(`
|
|
1460
|
-
console.log(` Naming: ${chalk10.yellow(report.summary.namingIssues)}`);
|
|
1461
|
-
console.log(` Patterns: ${chalk10.yellow(report.summary.patternIssues)}`);
|
|
1462
|
-
console.log(
|
|
1463
|
-
` Architecture: ${chalk10.yellow(report.summary.architectureIssues ?? 0)}`
|
|
1464
|
-
);
|
|
1465
|
-
console.log(`Analysis Time: ${chalk10.gray(elapsedTime + "s")}
|
|
1401
|
+
console.log(`Analysis Time: ${chalk11.gray(elapsedTime + "s")}
|
|
1466
1402
|
`);
|
|
1467
|
-
if (
|
|
1403
|
+
if (summary.totalIssues === 0) {
|
|
1468
1404
|
console.log(
|
|
1469
|
-
|
|
1405
|
+
chalk11.green(
|
|
1470
1406
|
"\u2728 No consistency issues found! Your codebase is well-maintained.\n"
|
|
1471
1407
|
)
|
|
1472
1408
|
);
|
|
@@ -1478,84 +1414,72 @@ async function consistencyAction(directory, options) {
|
|
|
1478
1414
|
(r) => r.issues.some((i) => i.category === "patterns")
|
|
1479
1415
|
);
|
|
1480
1416
|
if (namingResults.length > 0) {
|
|
1481
|
-
console.log(
|
|
1417
|
+
console.log(chalk11.bold("\u{1F3F7}\uFE0F Naming Issues\n"));
|
|
1482
1418
|
let shown = 0;
|
|
1483
1419
|
for (const namingFileResult of namingResults) {
|
|
1484
1420
|
if (shown >= 5) break;
|
|
1485
1421
|
for (const issue of namingFileResult.issues) {
|
|
1486
1422
|
if (shown >= 5) break;
|
|
1487
|
-
const severityColor = issue.severity === "critical" ?
|
|
1423
|
+
const severityColor = issue.severity === "critical" ? chalk11.red : issue.severity === "major" ? chalk11.yellow : issue.severity === "minor" ? chalk11.blue : chalk11.gray;
|
|
1488
1424
|
console.log(
|
|
1489
|
-
`${severityColor(issue.severity.toUpperCase())} ${
|
|
1425
|
+
`${severityColor(issue.severity.toUpperCase())} ${chalk11.dim(`${issue.location.file}:${issue.location.line}`)}`
|
|
1490
1426
|
);
|
|
1491
1427
|
console.log(` ${issue.message}`);
|
|
1492
1428
|
if (issue.suggestion) {
|
|
1493
1429
|
console.log(
|
|
1494
|
-
` ${
|
|
1430
|
+
` ${chalk11.dim("\u2192")} ${chalk11.italic(issue.suggestion)}`
|
|
1495
1431
|
);
|
|
1496
1432
|
}
|
|
1497
1433
|
console.log();
|
|
1498
1434
|
shown++;
|
|
1499
1435
|
}
|
|
1500
1436
|
}
|
|
1501
|
-
const remaining = namingResults.reduce((sum, r) => sum + r.issues.length, 0) - shown;
|
|
1502
|
-
if (remaining > 0) {
|
|
1503
|
-
console.log(chalk10.dim(` ... and ${remaining} more issues
|
|
1504
|
-
`));
|
|
1505
|
-
}
|
|
1506
1437
|
}
|
|
1507
1438
|
if (patternResults.length > 0) {
|
|
1508
|
-
console.log(
|
|
1439
|
+
console.log(chalk11.bold("\u{1F504} Pattern Issues\n"));
|
|
1509
1440
|
let shown = 0;
|
|
1510
1441
|
for (const patternFileResult of patternResults) {
|
|
1511
1442
|
if (shown >= 5) break;
|
|
1512
1443
|
for (const issue of patternFileResult.issues) {
|
|
1513
1444
|
if (shown >= 5) break;
|
|
1514
|
-
const severityColor = issue.severity === "critical" ?
|
|
1445
|
+
const severityColor = issue.severity === "critical" ? chalk11.red : issue.severity === "major" ? chalk11.yellow : issue.severity === "minor" ? chalk11.blue : chalk11.gray;
|
|
1515
1446
|
console.log(
|
|
1516
|
-
`${severityColor(issue.severity.toUpperCase())} ${
|
|
1447
|
+
`${severityColor(issue.severity.toUpperCase())} ${chalk11.dim(`${issue.location.file}:${issue.location.line}`)}`
|
|
1517
1448
|
);
|
|
1518
1449
|
console.log(` ${issue.message}`);
|
|
1519
1450
|
if (issue.suggestion) {
|
|
1520
1451
|
console.log(
|
|
1521
|
-
` ${
|
|
1452
|
+
` ${chalk11.dim("\u2192")} ${chalk11.italic(issue.suggestion)}`
|
|
1522
1453
|
);
|
|
1523
1454
|
}
|
|
1524
1455
|
console.log();
|
|
1525
1456
|
shown++;
|
|
1526
1457
|
}
|
|
1527
1458
|
}
|
|
1528
|
-
const remaining = patternResults.reduce((sum, r) => sum + r.issues.length, 0) - shown;
|
|
1529
|
-
if (remaining > 0) {
|
|
1530
|
-
console.log(chalk10.dim(` ... and ${remaining} more issues
|
|
1531
|
-
`));
|
|
1532
|
-
}
|
|
1533
1459
|
}
|
|
1534
|
-
if (report.recommendations
|
|
1535
|
-
console.log(
|
|
1460
|
+
if (report.recommendations?.length > 0) {
|
|
1461
|
+
console.log(chalk11.bold("\u{1F4A1} Recommendations\n"));
|
|
1536
1462
|
report.recommendations.forEach((rec, i) => {
|
|
1537
1463
|
console.log(`${i + 1}. ${rec}`);
|
|
1538
1464
|
});
|
|
1539
1465
|
console.log();
|
|
1540
1466
|
}
|
|
1541
1467
|
}
|
|
1542
|
-
if (
|
|
1543
|
-
console.log(
|
|
1544
|
-
console.log(
|
|
1468
|
+
if (score) {
|
|
1469
|
+
console.log(chalk11.bold("\n\u{1F4CA} AI Readiness Score (Consistency)\n"));
|
|
1470
|
+
console.log(formatToolScore2(score));
|
|
1545
1471
|
console.log();
|
|
1546
1472
|
}
|
|
1547
1473
|
}
|
|
1548
|
-
}
|
|
1549
|
-
handleCLIError5(error, "Consistency analysis");
|
|
1550
|
-
}
|
|
1474
|
+
});
|
|
1551
1475
|
}
|
|
1552
1476
|
|
|
1553
1477
|
// src/commands/visualize.ts
|
|
1554
|
-
import
|
|
1478
|
+
import chalk12 from "chalk";
|
|
1555
1479
|
import { writeFileSync as writeFileSync4, readFileSync as readFileSync3, existsSync as existsSync3, copyFileSync } from "fs";
|
|
1556
1480
|
import { resolve as resolvePath5 } from "path";
|
|
1557
1481
|
import { spawn } from "child_process";
|
|
1558
|
-
import { handleCLIError as
|
|
1482
|
+
import { handleCLIError as handleCLIError4 } from "@aiready/core";
|
|
1559
1483
|
import { generateHTML, findLatestReport as findLatestReport2 } from "@aiready/core";
|
|
1560
1484
|
async function visualizeAction(directory, options) {
|
|
1561
1485
|
try {
|
|
@@ -1566,12 +1490,12 @@ async function visualizeAction(directory, options) {
|
|
|
1566
1490
|
if (latestScan) {
|
|
1567
1491
|
reportPath = latestScan;
|
|
1568
1492
|
console.log(
|
|
1569
|
-
|
|
1493
|
+
chalk12.dim(`Found latest report: ${latestScan.split("/").pop()}`)
|
|
1570
1494
|
);
|
|
1571
1495
|
} else {
|
|
1572
|
-
console.error(
|
|
1496
|
+
console.error(chalk12.red("\u274C No AI readiness report found"));
|
|
1573
1497
|
console.log(
|
|
1574
|
-
|
|
1498
|
+
chalk12.dim(
|
|
1575
1499
|
`
|
|
1576
1500
|
Generate a report with:
|
|
1577
1501
|
aiready scan --output json
|
|
@@ -1701,19 +1625,19 @@ Or specify a custom report:
|
|
|
1701
1625
|
return;
|
|
1702
1626
|
} else {
|
|
1703
1627
|
console.log(
|
|
1704
|
-
|
|
1628
|
+
chalk12.yellow(
|
|
1705
1629
|
"\u26A0\uFE0F Dev server not available (requires local @aiready/visualizer with web assets)."
|
|
1706
1630
|
)
|
|
1707
1631
|
);
|
|
1708
1632
|
console.log(
|
|
1709
|
-
|
|
1633
|
+
chalk12.cyan(" Falling back to static HTML generation...\n")
|
|
1710
1634
|
);
|
|
1711
1635
|
useDevMode = false;
|
|
1712
1636
|
}
|
|
1713
1637
|
} catch (err) {
|
|
1714
1638
|
console.error("Failed to start dev server:", err);
|
|
1715
1639
|
console.log(
|
|
1716
|
-
|
|
1640
|
+
chalk12.cyan(" Falling back to static HTML generation...\n")
|
|
1717
1641
|
);
|
|
1718
1642
|
useDevMode = false;
|
|
1719
1643
|
}
|
|
@@ -1723,7 +1647,7 @@ Or specify a custom report:
|
|
|
1723
1647
|
const defaultOutput = "visualization.html";
|
|
1724
1648
|
const outPath = resolvePath5(dirPath, options.output ?? defaultOutput);
|
|
1725
1649
|
writeFileSync4(outPath, html, "utf8");
|
|
1726
|
-
console.log(
|
|
1650
|
+
console.log(chalk12.green(`\u2705 Visualization written to: ${outPath}`));
|
|
1727
1651
|
if (options.open || options.serve) {
|
|
1728
1652
|
const opener = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
1729
1653
|
if (options.serve) {
|
|
@@ -1753,7 +1677,7 @@ Or specify a custom report:
|
|
|
1753
1677
|
server.listen(port, () => {
|
|
1754
1678
|
const addr = `http://localhost:${port}/`;
|
|
1755
1679
|
console.log(
|
|
1756
|
-
|
|
1680
|
+
chalk12.cyan(`\u{1F310} Local visualization server running at ${addr}`)
|
|
1757
1681
|
);
|
|
1758
1682
|
spawn(opener, [`"${addr}"`], { shell: true });
|
|
1759
1683
|
});
|
|
@@ -1769,7 +1693,7 @@ Or specify a custom report:
|
|
|
1769
1693
|
}
|
|
1770
1694
|
}
|
|
1771
1695
|
} catch (err) {
|
|
1772
|
-
|
|
1696
|
+
handleCLIError4(err, "Visualization");
|
|
1773
1697
|
}
|
|
1774
1698
|
}
|
|
1775
1699
|
var VISUALIZE_HELP_TEXT = `
|
|
@@ -1800,72 +1724,63 @@ NOTES:
|
|
|
1800
1724
|
`;
|
|
1801
1725
|
|
|
1802
1726
|
// src/commands/shared/standard-tool-actions.ts
|
|
1803
|
-
import
|
|
1727
|
+
import chalk13 from "chalk";
|
|
1804
1728
|
|
|
1805
1729
|
// src/commands/agent-grounding.ts
|
|
1806
|
-
import
|
|
1807
|
-
import { loadConfig as loadConfig2, mergeConfigWithDefaults as mergeConfigWithDefaults2 } from "@aiready/core";
|
|
1730
|
+
import chalk14 from "chalk";
|
|
1808
1731
|
|
|
1809
1732
|
// src/commands/testability.ts
|
|
1810
|
-
import
|
|
1811
|
-
import { loadConfig as loadConfig3, mergeConfigWithDefaults as mergeConfigWithDefaults3 } from "@aiready/core";
|
|
1733
|
+
import chalk15 from "chalk";
|
|
1812
1734
|
async function testabilityAction(directory, options) {
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1735
|
+
return await executeToolAction(directory, options, {
|
|
1736
|
+
toolName: "testability-index",
|
|
1737
|
+
label: "Testability analysis",
|
|
1738
|
+
emoji: "\u{1F9EA}",
|
|
1739
|
+
defaults: {
|
|
1740
|
+
minCoverageRatio: 0.3,
|
|
1741
|
+
include: void 0,
|
|
1742
|
+
exclude: void 0,
|
|
1743
|
+
output: { format: "console", file: void 0 }
|
|
1744
|
+
},
|
|
1745
|
+
getCliOptions: (opts) => ({
|
|
1746
|
+
minCoverageRatio: opts.minCoverage ? parseFloat(opts.minCoverage) : void 0
|
|
1747
|
+
}),
|
|
1748
|
+
importTool: async () => {
|
|
1749
|
+
const tool = await import("@aiready/testability");
|
|
1750
|
+
return {
|
|
1751
|
+
analyze: tool.analyzeTestability,
|
|
1752
|
+
generateSummary: (report) => report.summary,
|
|
1753
|
+
calculateScore: tool.calculateTestabilityScore
|
|
1754
|
+
};
|
|
1755
|
+
},
|
|
1756
|
+
renderConsole: ({ results, summary, score }) => {
|
|
1757
|
+
renderToolHeader("Testability", "\u{1F9EA}", score?.score || 0, summary.rating);
|
|
1758
|
+
renderSafetyRating(summary.aiChangeSafetyRating);
|
|
1759
|
+
const rawData = results.rawData || results;
|
|
1760
|
+
console.log(
|
|
1761
|
+
chalk15.dim(
|
|
1762
|
+
` Coverage: ${Math.round(summary.coverageRatio * 100)}% (${rawData.testFiles} test / ${rawData.sourceFiles} source files)`
|
|
1763
|
+
)
|
|
1764
|
+
);
|
|
1765
|
+
if (summary.aiChangeSafetyRating === "blind-risk") {
|
|
1766
|
+
console.log(
|
|
1767
|
+
chalk15.red.bold(
|
|
1768
|
+
"\n \u26A0\uFE0F NO TESTS \u2014 AI changes to this codebase are completely unverifiable!\n"
|
|
1769
|
+
)
|
|
1770
|
+
);
|
|
1771
|
+
}
|
|
1772
|
+
if (score) {
|
|
1773
|
+
renderToolScoreFooter(score);
|
|
1774
|
+
}
|
|
1775
|
+
}
|
|
1823
1776
|
});
|
|
1824
|
-
const scoring = calculateTestabilityScore(report);
|
|
1825
|
-
if (options.output === "json") {
|
|
1826
|
-
return scoring;
|
|
1827
|
-
}
|
|
1828
|
-
const safetyIcons = {
|
|
1829
|
-
safe: "\u2705",
|
|
1830
|
-
"moderate-risk": "\u26A0\uFE0F ",
|
|
1831
|
-
"high-risk": "\u{1F534}",
|
|
1832
|
-
"blind-risk": "\u{1F480}"
|
|
1833
|
-
};
|
|
1834
|
-
const safetyColors = {
|
|
1835
|
-
safe: chalk14.green,
|
|
1836
|
-
"moderate-risk": chalk14.yellow,
|
|
1837
|
-
"high-risk": chalk14.red,
|
|
1838
|
-
"blind-risk": chalk14.bgRed.white
|
|
1839
|
-
};
|
|
1840
|
-
const safety = report.summary.aiChangeSafetyRating;
|
|
1841
|
-
const icon = safetyIcons[safety] ?? "\u2753";
|
|
1842
|
-
const color = safetyColors[safety] ?? chalk14.white;
|
|
1843
|
-
console.log(
|
|
1844
|
-
` \u{1F9EA} Testability: ${chalk14.bold(scoring.score + "/100")} (${report.summary.rating})`
|
|
1845
|
-
);
|
|
1846
|
-
console.log(
|
|
1847
|
-
` AI Change Safety: ${color(`${icon} ${safety.toUpperCase()}`)}`
|
|
1848
|
-
);
|
|
1849
|
-
console.log(
|
|
1850
|
-
chalk14.dim(
|
|
1851
|
-
` Coverage: ${Math.round(report.summary.coverageRatio * 100)}% (${report.rawData.testFiles} test / ${report.rawData.sourceFiles} source files)`
|
|
1852
|
-
)
|
|
1853
|
-
);
|
|
1854
|
-
if (safety === "blind-risk") {
|
|
1855
|
-
console.log(
|
|
1856
|
-
chalk14.red.bold(
|
|
1857
|
-
"\n \u26A0\uFE0F NO TESTS \u2014 AI changes to this codebase are completely unverifiable!\n"
|
|
1858
|
-
)
|
|
1859
|
-
);
|
|
1860
|
-
}
|
|
1861
|
-
return scoring;
|
|
1862
1777
|
}
|
|
1863
1778
|
|
|
1864
1779
|
// src/commands/change-amplification.ts
|
|
1865
1780
|
import { changeAmplificationAction } from "@aiready/change-amplification/dist/cli.js";
|
|
1866
1781
|
|
|
1867
1782
|
// src/commands/bug.ts
|
|
1868
|
-
import
|
|
1783
|
+
import chalk16 from "chalk";
|
|
1869
1784
|
import { execSync } from "child_process";
|
|
1870
1785
|
async function bugAction(message, options) {
|
|
1871
1786
|
const repoUrl = "https://github.com/caopengau/aiready-cli";
|
|
@@ -1883,35 +1798,35 @@ Generated via AIReady CLI 'bug' command.
|
|
|
1883
1798
|
Type: ${type}
|
|
1884
1799
|
`.trim();
|
|
1885
1800
|
if (options.submit) {
|
|
1886
|
-
console.log(
|
|
1801
|
+
console.log(chalk16.blue("\u{1F680} Submitting issue via GitHub CLI...\n"));
|
|
1887
1802
|
try {
|
|
1888
1803
|
execSync("gh auth status", { stdio: "ignore" });
|
|
1889
1804
|
const command = `gh issue create --repo ${repoSlug} --title ${JSON.stringify(title)} --body ${JSON.stringify(body)} --label ${label}`;
|
|
1890
1805
|
const output = execSync(command, { encoding: "utf8" }).trim();
|
|
1891
|
-
console.log(
|
|
1892
|
-
console.log(
|
|
1806
|
+
console.log(chalk16.green("\u2705 Issue Created Successfully!"));
|
|
1807
|
+
console.log(chalk16.cyan(output));
|
|
1893
1808
|
return;
|
|
1894
1809
|
} catch {
|
|
1895
|
-
console.error(
|
|
1810
|
+
console.error(chalk16.red("\n\u274C Failed to submit via gh CLI."));
|
|
1896
1811
|
console.log(
|
|
1897
|
-
|
|
1812
|
+
chalk16.yellow(
|
|
1898
1813
|
' Make sure gh is installed and run "gh auth login".\n'
|
|
1899
1814
|
)
|
|
1900
1815
|
);
|
|
1901
|
-
console.log(
|
|
1816
|
+
console.log(chalk16.dim(" Falling back to URL generation..."));
|
|
1902
1817
|
}
|
|
1903
1818
|
}
|
|
1904
1819
|
const template = type === "bug" ? "bug_report.md" : type === "feature" ? "feature_request.md" : "new_metric_idea.md";
|
|
1905
1820
|
const fullUrl = `${repoUrl}/issues/new?title=${encodeURIComponent(title)}&body=${encodeURIComponent(body)}&labels=${label}&template=${template}`;
|
|
1906
|
-
console.log(
|
|
1907
|
-
console.log(
|
|
1908
|
-
console.log(
|
|
1909
|
-
console.log(
|
|
1910
|
-
console.log(
|
|
1911
|
-
console.log(
|
|
1912
|
-
console.log(
|
|
1821
|
+
console.log(chalk16.green("\u{1F680} Issue Draft Prepared!\n"));
|
|
1822
|
+
console.log(chalk16.bold("Title: ") + title);
|
|
1823
|
+
console.log(chalk16.bold("Type: ") + type);
|
|
1824
|
+
console.log(chalk16.bold("\nClick the link below to submit this issue:"));
|
|
1825
|
+
console.log(chalk16.cyan(fullUrl));
|
|
1826
|
+
console.log(chalk16.bold("\n\u{1F916} [FOR AI AGENTS]:"));
|
|
1827
|
+
console.log(chalk16.dim(" You have successfully prepared a report."));
|
|
1913
1828
|
console.log(
|
|
1914
|
-
|
|
1829
|
+
chalk16.dim(
|
|
1915
1830
|
" Please present the URL above to the user so they can finalize the submission."
|
|
1916
1831
|
)
|
|
1917
1832
|
);
|
|
@@ -1920,14 +1835,14 @@ Type: ${type}
|
|
|
1920
1835
|
const bugUrl = `${repoUrl}/issues/new?template=bug_report.md`;
|
|
1921
1836
|
const featureUrl = `${repoUrl}/issues/new?template=feature_request.md`;
|
|
1922
1837
|
const metricUrl = `${repoUrl}/issues/new?template=new_metric_idea.md`;
|
|
1923
|
-
console.log(
|
|
1924
|
-
console.log(` Report a Bug: ${
|
|
1925
|
-
console.log(` Request a Feature: ${
|
|
1926
|
-
console.log(` Suggest a Metric: ${
|
|
1927
|
-
console.log(
|
|
1928
|
-
console.log(
|
|
1838
|
+
console.log(chalk16.blue("\u{1F4AC} Feedback & Bug Reports\n"));
|
|
1839
|
+
console.log(` Report a Bug: ${chalk16.cyan(bugUrl)}`);
|
|
1840
|
+
console.log(` Request a Feature: ${chalk16.cyan(featureUrl)}`);
|
|
1841
|
+
console.log(` Suggest a Metric: ${chalk16.cyan(metricUrl)}`);
|
|
1842
|
+
console.log(chalk16.bold("\n\u{1F916} [FOR AI AGENTS]:"));
|
|
1843
|
+
console.log(chalk16.dim(" To prepare a specific report, run:"));
|
|
1929
1844
|
console.log(
|
|
1930
|
-
|
|
1845
|
+
chalk16.cyan(
|
|
1931
1846
|
' aiready bug "your description here" --type bug|feature|metric'
|
|
1932
1847
|
)
|
|
1933
1848
|
);
|