@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/cli.mjs CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  __require,
4
4
  analyzeUnified,
5
5
  scoreUnified
6
- } from "./chunk-HUSUJEQJ.mjs";
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 handleCLIError2,
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: loadConfig4 } = await import("@aiready/core");
41
- void loadConfig4;
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 { ToolName } from "@aiready/core";
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(outputData, scoringResult, options, results);
780
+ await handleGatekeeper(
781
+ outputData,
782
+ scoringResult,
783
+ options,
784
+ finalOptions,
785
+ results
786
+ );
717
787
  } catch (error) {
718
- handleCLIError2(error, "Analysis");
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) : void 0;
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
- printTerminalHeader,
1035
- getTerminalDivider,
1036
- prepareActionConfig,
1037
- resolveOutputFormat,
1038
- formatStandardReport,
1039
- handleStandardJSONOutput
1106
+ getTerminalDivider as coreGetDivider
1040
1107
  } from "@aiready/core";
1041
- async function patternsAction(directory, options) {
1042
- console.log(chalk8.blue("\u{1F50D} Analyzing patterns...\n"));
1043
- const startTime = Date.now();
1044
- try {
1045
- const useSmartDefaults = !options.fullScan;
1046
- const defaults = {
1047
- useSmartDefaults,
1048
- include: void 0,
1049
- exclude: void 0,
1050
- output: {
1051
- format: "console",
1052
- file: void 0
1053
- }
1054
- };
1055
- if (!useSmartDefaults) {
1056
- defaults.minSimilarity = 0.4;
1057
- defaults.minLines = 5;
1058
- }
1059
- const cliOptions = {
1060
- minSimilarity: options.similarity ? parseFloat(options.similarity) : void 0,
1061
- minLines: options.minLines ? parseInt(options.minLines) : void 0,
1062
- useSmartDefaults,
1063
- include: options.include?.split(","),
1064
- exclude: options.exclude?.split(",")
1065
- };
1066
- if (options.maxCandidates) {
1067
- cliOptions.maxCandidatesPerBlock = parseInt(options.maxCandidates);
1068
- }
1069
- if (options.minSharedTokens) {
1070
- cliOptions.minSharedTokens = parseInt(options.minSharedTokens);
1071
- }
1072
- const { resolvedDir, finalOptions } = await prepareActionConfig(
1073
- directory,
1074
- defaults,
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
- const { analyzePatterns, generateSummary, calculatePatternScore } = await import("@aiready/pattern-detect");
1078
- const { results, duplicates } = await analyzePatterns(
1079
- finalOptions
1143
+ if (summary.majorIssues > 0)
1144
+ console.log(
1145
+ chalk8.yellow(` \u{1F7E1} Major: ${chalk8.bold(summary.majorIssues)}`)
1080
1146
  );
1081
- const elapsedTime = getElapsedTime(startTime);
1082
- const summary = generateSummary(results);
1083
- let patternScore;
1084
- if (options.score) {
1085
- patternScore = calculatePatternScore(duplicates, results.length);
1086
- }
1087
- const { format: outputFormat, file: userOutputFile } = resolveOutputFormat(
1088
- options,
1089
- finalOptions
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
- if (outputFormat === "json") {
1092
- const outputData = formatStandardReport({
1093
- results,
1094
- summary,
1095
- elapsedTime,
1096
- score: patternScore
1097
- });
1098
- handleStandardJSONOutput({
1099
- outputData,
1100
- outputFile: userOutputFile,
1101
- resolvedDir
1102
- });
1103
- } else {
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
- chalk8.white(`\u{1F4C1} Files analyzed: ${chalk8.bold(results.length)}`)
1206
+ chalk9.white(`\u{1F4C1} Files analyzed: ${chalk9.bold(results.length)}`)
1107
1207
  );
1108
1208
  console.log(
1109
- chalk8.yellow(
1110
- `\u26A0 Duplicate patterns found: ${chalk8.bold(summary.totalPatterns)}`
1209
+ chalk9.yellow(
1210
+ `\u26A0 Duplicate patterns found: ${chalk9.bold(summary.totalPatterns)}`
1111
1211
  )
1112
1212
  );
1113
1213
  console.log(
1114
- chalk8.red(
1115
- `\u{1F4B0} Token cost (wasted): ${chalk8.bold(summary.totalTokenCost.toLocaleString())}`
1214
+ chalk9.red(
1215
+ `\u{1F4B0} Token cost (wasted): ${chalk9.bold(summary.totalTokenCost.toLocaleString())}`
1116
1216
  )
1117
1217
  );
1118
1218
  console.log(
1119
- chalk8.gray(`\u23F1 Analysis time: ${chalk8.bold(elapsedTime + "s")}`)
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
- console.log("\n" + getTerminalDivider());
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(` ${chalk8.white(type.padEnd(15))} ${chalk8.bold(count)}`);
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
- console.log("\n" + getTerminalDivider());
1132
- console.log(chalk8.bold.white(" TOP DUPLICATE PATTERNS"));
1133
- console.log(getTerminalDivider() + "\n");
1134
- const topDuplicates = [...duplicates].sort((a, b) => b.similarity - a.similarity).slice(0, 10);
1135
- topDuplicates.forEach((dup) => {
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
- `${severityIcon} ${severity}: ${chalk8.bold(file1Name)} \u2194 ${chalk8.bold(file2Name)}`
1235
+ `${icon} ${label}: ${chalk9.bold(dup.file1.split("/").pop())} \u2194 ${chalk9.bold(dup.file2.split("/").pop())}`
1142
1236
  );
1143
1237
  console.log(
1144
- ` Similarity: ${chalk8.bold(Math.round(dup.similarity * 100) + "%")} | Wasted: ${chalk8.bold(dup.tokenCost.toLocaleString())} tokens each`
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: ${chalk8.cyan(dup.line1 + "-" + dup.endLine1)} \u2194 ${chalk8.cyan(dup.line2 + "-" + dup.endLine2)}
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
- chalk8.green("\n\u2728 Great! No duplicate patterns detected.\n")
1247
+ chalk9.green("\n\u2728 Great! No duplicate patterns detected.\n")
1154
1248
  );
1155
1249
  }
1156
- if (patternScore) {
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
- } catch (error) {
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 chalk9 from "chalk";
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
- console.log(chalk9.blue("\u{1F9E0} Analyzing context costs...\n"));
1188
- const startTime = Date.now();
1189
- try {
1190
- const defaults = {
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
- format: "console",
1197
- file: void 0
1198
- }
1199
- };
1200
- const { resolvedDir, finalOptions: baseOptions } = await prepareActionConfig2(directory, defaults, {
1201
- maxDepth: options.maxDepth ? parseInt(options.maxDepth) : void 0,
1202
- maxContextBudget: options.maxContext ? parseInt(options.maxContext) : void 0,
1203
- include: options.include?.split(","),
1204
- exclude: options.exclude?.split(",")
1205
- });
1206
- let finalOptions = { ...baseOptions };
1207
- const { getSmartDefaults } = await import("@aiready/context-analyzer");
1208
- const contextSmartDefaults = await getSmartDefaults(
1209
- resolvedDir,
1210
- baseOptions
1211
- );
1212
- finalOptions = { ...contextSmartDefaults, ...finalOptions };
1213
- console.log("\u{1F4CB} Configuration:");
1214
- console.log(` Max depth: ${finalOptions.maxDepth}`);
1215
- console.log(` Max context budget: ${finalOptions.maxContextBudget}`);
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
- chalk9.white(`\u{1F4C1} Files analyzed: ${chalk9.bold(summary.totalFiles)}`)
1296
+ chalk10.white(`\u{1F4C1} Files analyzed: ${chalk10.bold(summary.totalFiles)}`)
1257
1297
  );
1258
1298
  console.log(
1259
- chalk9.white(
1260
- `\u{1F4CA} Total tokens: ${chalk9.bold(summary.totalTokens.toLocaleString())}`
1299
+ chalk10.white(
1300
+ `\u{1F4CA} Total tokens: ${chalk10.bold(summary.totalTokens.toLocaleString())}`
1261
1301
  )
1262
1302
  );
1263
1303
  console.log(
1264
- chalk9.yellow(
1265
- `\u{1F4B0} Avg context budget: ${chalk9.bold(summary.avgContextBudget.toFixed(0))} tokens/file`
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
- chalk9.white(`\u23F1 Analysis time: ${chalk9.bold(elapsedTime + "s")}
1309
+ chalk10.white(`\u23F1 Analysis time: ${chalk10.bold(elapsedTime + "s")}
1270
1310
  `)
1271
1311
  );
1272
- const totalIssues = summary.criticalIssues + summary.majorIssues + summary.minorIssues;
1273
- if (totalIssues > 0) {
1274
- console.log(chalk9.bold("\u26A0\uFE0F Issues Found:\n"));
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
- ` ${chalk9.cyan("\u2192")} ${chalk9.white(fileName)} ${chalk9.dim(`(depth: ${item.depth})`)}`
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
- console.log(chalk9.bold("\u{1F9E9} Fragmented Modules:\n"));
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
- ` ${chalk9.yellow("\u25CF")} ${chalk9.white(module.domain)} - ${chalk9.dim(`${module.files.length} files, ${(module.fragmentationScore * 100).toFixed(0)}% scattered`)}`
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
- chalk9.dim(
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
- } catch (error) {
1375
- handleCLIError4(error, "Context analysis");
1376
- }
1337
+ });
1377
1338
  }
1378
1339
 
1379
1340
  // src/commands/consistency.ts
1380
- import chalk10 from "chalk";
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 formatToolScore3,
1387
- prepareActionConfig as prepareActionConfig3,
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
- console.log(chalk10.blue("\u{1F50D} Analyzing consistency...\n"));
1394
- const startTime = Date.now();
1395
- try {
1396
- const defaults = {
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
- format: "console",
1404
- file: void 0
1405
- }
1406
- };
1407
- const { resolvedDir, finalOptions } = await prepareActionConfig3(
1408
- directory,
1409
- defaults,
1410
- {
1411
- checkNaming: options.naming !== false,
1412
- checkPatterns: options.patterns !== false,
1413
- minSeverity: options.minSeverity,
1414
- include: options.include?.split(","),
1415
- exclude: options.exclude?.split(",")
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
- const { analyzeConsistency, calculateConsistencyScore } = await import("@aiready/consistency");
1419
- const report = await analyzeConsistency(finalOptions);
1420
- const elapsedTime = getElapsedTime3(startTime);
1421
- let consistencyScore;
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
- `Files Analyzed: ${chalk10.cyan(report.summary.filesAnalyzed)}`
1399
+ ` Architecture: ${chalk11.yellow(summary.architectureIssues ?? 0)}`
1458
1400
  );
1459
- console.log(`Total Issues: ${chalk10.yellow(report.summary.totalIssues)}`);
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 (report.summary.totalIssues === 0) {
1403
+ if (summary.totalIssues === 0) {
1468
1404
  console.log(
1469
- chalk10.green(
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(chalk10.bold("\u{1F3F7}\uFE0F Naming Issues\n"));
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" ? chalk10.red : issue.severity === "major" ? chalk10.yellow : issue.severity === "minor" ? chalk10.blue : chalk10.gray;
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())} ${chalk10.dim(`${issue.location.file}:${issue.location.line}`)}`
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
- ` ${chalk10.dim("\u2192")} ${chalk10.italic(issue.suggestion)}`
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(chalk10.bold("\u{1F504} Pattern Issues\n"));
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" ? chalk10.red : issue.severity === "major" ? chalk10.yellow : issue.severity === "minor" ? chalk10.blue : chalk10.gray;
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())} ${chalk10.dim(`${issue.location.file}:${issue.location.line}`)}`
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
- ` ${chalk10.dim("\u2192")} ${chalk10.italic(issue.suggestion)}`
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.length > 0) {
1535
- console.log(chalk10.bold("\u{1F4A1} Recommendations\n"));
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 (consistencyScore) {
1543
- console.log(chalk10.bold("\n\u{1F4CA} AI Readiness Score (Consistency)\n"));
1544
- console.log(formatToolScore3(consistencyScore));
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
- } catch (error) {
1549
- handleCLIError5(error, "Consistency analysis");
1550
- }
1474
+ });
1551
1475
  }
1552
1476
 
1553
1477
  // src/commands/visualize.ts
1554
- import chalk11 from "chalk";
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 handleCLIError6 } from "@aiready/core";
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
- chalk11.dim(`Found latest report: ${latestScan.split("/").pop()}`)
1493
+ chalk12.dim(`Found latest report: ${latestScan.split("/").pop()}`)
1570
1494
  );
1571
1495
  } else {
1572
- console.error(chalk11.red("\u274C No AI readiness report found"));
1496
+ console.error(chalk12.red("\u274C No AI readiness report found"));
1573
1497
  console.log(
1574
- chalk11.dim(
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
- chalk11.yellow(
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
- chalk11.cyan(" Falling back to static HTML generation...\n")
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
- chalk11.cyan(" Falling back to static HTML generation...\n")
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(chalk11.green(`\u2705 Visualization written to: ${outPath}`));
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
- chalk11.cyan(`\u{1F310} Local visualization server running at ${addr}`)
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
- handleCLIError6(err, "Visualization");
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 chalk12 from "chalk";
1727
+ import chalk13 from "chalk";
1804
1728
 
1805
1729
  // src/commands/agent-grounding.ts
1806
- import chalk13 from "chalk";
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 chalk14 from "chalk";
1811
- import { loadConfig as loadConfig3, mergeConfigWithDefaults as mergeConfigWithDefaults3 } from "@aiready/core";
1733
+ import chalk15 from "chalk";
1812
1734
  async function testabilityAction(directory, options) {
1813
- const { analyzeTestability, calculateTestabilityScore } = await import("@aiready/testability");
1814
- const config = await loadConfig3(directory);
1815
- const merged = mergeConfigWithDefaults3(config, {
1816
- minCoverageRatio: 0.3
1817
- });
1818
- const report = await analyzeTestability({
1819
- rootDir: directory,
1820
- minCoverageRatio: options.minCoverageRatio ?? merged.minCoverageRatio,
1821
- include: options.include,
1822
- exclude: options.exclude
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 chalk15 from "chalk";
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(chalk15.blue("\u{1F680} Submitting issue via GitHub CLI...\n"));
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(chalk15.green("\u2705 Issue Created Successfully!"));
1892
- console.log(chalk15.cyan(output));
1806
+ console.log(chalk16.green("\u2705 Issue Created Successfully!"));
1807
+ console.log(chalk16.cyan(output));
1893
1808
  return;
1894
1809
  } catch {
1895
- console.error(chalk15.red("\n\u274C Failed to submit via gh CLI."));
1810
+ console.error(chalk16.red("\n\u274C Failed to submit via gh CLI."));
1896
1811
  console.log(
1897
- chalk15.yellow(
1812
+ chalk16.yellow(
1898
1813
  ' Make sure gh is installed and run "gh auth login".\n'
1899
1814
  )
1900
1815
  );
1901
- console.log(chalk15.dim(" Falling back to URL generation..."));
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(chalk15.green("\u{1F680} Issue Draft Prepared!\n"));
1907
- console.log(chalk15.bold("Title: ") + title);
1908
- console.log(chalk15.bold("Type: ") + type);
1909
- console.log(chalk15.bold("\nClick the link below to submit this issue:"));
1910
- console.log(chalk15.cyan(fullUrl));
1911
- console.log(chalk15.bold("\n\u{1F916} [FOR AI AGENTS]:"));
1912
- console.log(chalk15.dim(" You have successfully prepared a report."));
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
- chalk15.dim(
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(chalk15.blue("\u{1F4AC} Feedback & Bug Reports\n"));
1924
- console.log(` Report a Bug: ${chalk15.cyan(bugUrl)}`);
1925
- console.log(` Request a Feature: ${chalk15.cyan(featureUrl)}`);
1926
- console.log(` Suggest a Metric: ${chalk15.cyan(metricUrl)}`);
1927
- console.log(chalk15.bold("\n\u{1F916} [FOR AI AGENTS]:"));
1928
- console.log(chalk15.dim(" To prepare a specific report, run:"));
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
- chalk15.cyan(
1845
+ chalk16.cyan(
1931
1846
  ' aiready bug "your description here" --type bug|feature|metric'
1932
1847
  )
1933
1848
  );