@aiready/cli 0.14.9 → 0.14.11

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.js CHANGED
@@ -95,7 +95,7 @@ function sanitizeToolConfig(config) {
95
95
  async function analyzeUnified(options) {
96
96
  await (0, import_core.initializeParsers)();
97
97
  const startTime = Date.now();
98
- const requestedTools = options.tools || [
98
+ const requestedTools = options.tools ?? [
99
99
  "patterns",
100
100
  "context",
101
101
  "consistency"
@@ -117,7 +117,7 @@ async function analyzeUnified(options) {
117
117
  for (const toolName of requestedTools) {
118
118
  let provider = import_core.ToolRegistry.find(toolName);
119
119
  if (!provider) {
120
- const packageName = TOOL_PACKAGE_MAP[toolName] || (toolName.startsWith("@aiready/") ? toolName : `@aiready/${toolName}`);
120
+ const packageName = TOOL_PACKAGE_MAP[toolName] ?? (toolName.startsWith("@aiready/") ? toolName : `@aiready/${toolName}`);
121
121
  try {
122
122
  await import(packageName);
123
123
  provider = import_core.ToolRegistry.find(toolName);
@@ -195,29 +195,15 @@ async function analyzeUnified(options) {
195
195
  } else {
196
196
  result.summary.toolConfigs[provider.id] = sanitizeToolConfig(toolOptions);
197
197
  }
198
- const toolFiles = output.summary?.totalFiles || output.summary?.filesAnalyzed || 0;
198
+ const toolFiles = output.summary?.totalFiles ?? output.summary?.filesAnalyzed ?? 0;
199
199
  if (toolFiles > result.summary.totalFiles) {
200
200
  result.summary.totalFiles = toolFiles;
201
201
  }
202
202
  const issueCount = output.results.reduce(
203
- (sum, file) => sum + (file.issues?.length || 0),
203
+ (sum, file) => sum + (file.issues?.length ?? 0),
204
204
  0
205
205
  );
206
206
  result.summary.totalIssues += issueCount;
207
- if (provider.alias && Array.isArray(provider.alias)) {
208
- for (const alias of provider.alias) {
209
- if (!result[alias]) {
210
- result[alias] = output;
211
- }
212
- }
213
- }
214
- const camelCaseId = provider.id.replace(
215
- /-([a-z])/g,
216
- (g) => g[1].toUpperCase()
217
- );
218
- if (camelCaseId !== provider.id && !result[camelCaseId]) {
219
- result[camelCaseId] = output;
220
- }
221
207
  } catch (err) {
222
208
  console.error(`\u274C Error running tool '${provider.id}':`, err);
223
209
  }
@@ -232,6 +218,24 @@ async function analyzeUnified(options) {
232
218
  tools: result.summary.toolConfigs
233
219
  });
234
220
  result.summary.executionTime = Date.now() - startTime;
221
+ const keyMappings = {
222
+ "pattern-detect": ["patternDetect", "patterns"],
223
+ "context-analyzer": ["contextAnalyzer", "context"],
224
+ "naming-consistency": ["namingConsistency", "consistency"],
225
+ "ai-signal-clarity": ["aiSignalClarity"],
226
+ "agent-grounding": ["agentGrounding"],
227
+ "testability-index": ["testabilityIndex", "testability"],
228
+ "doc-drift": ["docDrift"],
229
+ "dependency-health": ["dependencyHealth", "deps"],
230
+ "change-amplification": ["changeAmplification"]
231
+ };
232
+ for (const [kebabKey, aliases] of Object.entries(keyMappings)) {
233
+ if (result[kebabKey]) {
234
+ for (const alias of aliases) {
235
+ result[alias] = result[kebabKey];
236
+ }
237
+ }
238
+ }
235
239
  return result;
236
240
  }
237
241
  async function scoreUnified(results, options) {
@@ -246,7 +250,7 @@ async function scoreUnified(results, options) {
246
250
  if (!toolScore.tokenBudget) {
247
251
  if (toolId === import_core.ToolName.PatternDetect && output.duplicates) {
248
252
  const wastedTokens = output.duplicates.reduce(
249
- (sum, d) => sum + (d.tokenCost || 0),
253
+ (sum, d) => sum + (d.tokenCost ?? 0),
250
254
  0
251
255
  );
252
256
  toolScore.tokenBudget = (0, import_core.calculateTokenBudget)({
@@ -262,7 +266,7 @@ async function scoreUnified(results, options) {
262
266
  totalContextTokens: output.summary.totalTokens,
263
267
  wastedTokens: {
264
268
  duplication: 0,
265
- fragmentation: output.summary.totalPotentialSavings || 0,
269
+ fragmentation: output.summary.totalPotentialSavings ?? 0,
266
270
  chattiness: 0
267
271
  }
268
272
  });
@@ -390,13 +394,91 @@ function generateMarkdownReport(report, elapsedTime) {
390
394
  // src/commands/report-formatter.ts
391
395
  var import_chalk2 = __toESM(require("chalk"));
392
396
  var import_core4 = require("@aiready/core");
397
+ function generateProgressBar(score, width = 20) {
398
+ const filled = Math.round(score / 100 * width);
399
+ const empty = width - filled;
400
+ let color = import_chalk2.default.red;
401
+ if (score >= 90) color = import_chalk2.default.green;
402
+ else if (score >= 75) color = import_chalk2.default.cyan;
403
+ else if (score >= 60) color = import_chalk2.default.yellow;
404
+ const bar = "\u2588".repeat(filled) + "\u2591".repeat(empty);
405
+ return color(bar);
406
+ }
407
+ function countIssuesBySeverity(results) {
408
+ let critical = 0;
409
+ let major = 0;
410
+ let minor = 0;
411
+ if (results.summary?.toolsRun) {
412
+ for (const toolId of results.summary.toolsRun) {
413
+ const toolRes = results[toolId];
414
+ if (toolRes?.results) {
415
+ for (const fileRes of toolRes.results) {
416
+ if (fileRes.issues) {
417
+ for (const issue of fileRes.issues) {
418
+ const sev = issue.severity?.toLowerCase();
419
+ if (sev === "critical") critical++;
420
+ else if (sev === "major") major++;
421
+ else minor++;
422
+ }
423
+ }
424
+ }
425
+ }
426
+ }
427
+ }
428
+ return { critical, major, minor };
429
+ }
430
+ function getTopFilesWithIssues(results, limit = 5) {
431
+ const fileCounts = /* @__PURE__ */ new Map();
432
+ if (results.summary?.toolsRun) {
433
+ for (const toolId of results.summary.toolsRun) {
434
+ const toolRes = results[toolId];
435
+ if (toolRes?.results) {
436
+ for (const fileRes of toolRes.results) {
437
+ if (fileRes.issues?.length > 0) {
438
+ const current = fileCounts.get(fileRes.fileName) || 0;
439
+ fileCounts.set(fileRes.fileName, current + fileRes.issues.length);
440
+ }
441
+ }
442
+ }
443
+ }
444
+ }
445
+ return Array.from(fileCounts.entries()).map(([file, count]) => ({ file, count })).sort((a, b) => b.count - a.count).slice(0, limit);
446
+ }
393
447
  function printScanSummary(results, startTime) {
448
+ const severity = countIssuesBySeverity(results);
449
+ const totalIssues = severity.critical + severity.major + severity.minor;
450
+ const topFiles = getTopFilesWithIssues(results);
394
451
  console.log(import_chalk2.default.cyan("\n=== AIReady Run Summary ==="));
452
+ console.log(` Total issues: ${import_chalk2.default.bold(String(totalIssues))}`);
453
+ if (totalIssues > 0) {
454
+ console.log(import_chalk2.default.dim(" Severity breakdown:"));
455
+ if (severity.critical > 0) {
456
+ console.log(
457
+ ` ${import_chalk2.default.red("\u25CF")} Critical: ${import_chalk2.default.bold(severity.critical)}`
458
+ );
459
+ }
460
+ if (severity.major > 0) {
461
+ console.log(
462
+ ` ${import_chalk2.default.yellow("\u25CF")} Major: ${import_chalk2.default.bold(severity.major)}`
463
+ );
464
+ }
465
+ if (severity.minor > 0) {
466
+ console.log(
467
+ ` ${import_chalk2.default.blue("\u25CF")} Minor: ${import_chalk2.default.bold(severity.minor)}`
468
+ );
469
+ }
470
+ }
471
+ if (topFiles.length > 0) {
472
+ console.log(import_chalk2.default.dim("\n Top files with issues:"));
473
+ topFiles.forEach((item) => {
474
+ console.log(
475
+ ` ${import_chalk2.default.yellow("\u2192")} ${item.file}: ${import_chalk2.default.bold(item.count)} issues`
476
+ );
477
+ });
478
+ }
395
479
  console.log(
396
- ` Total issues (all tools): ${import_chalk2.default.bold(String(results.summary.totalIssues || 0))}`
397
- );
398
- console.log(
399
- ` Execution time: ${import_chalk2.default.bold(((Date.now() - startTime) / 1e3).toFixed(2) + "s")}`
480
+ `
481
+ Execution time: ${import_chalk2.default.bold(((Date.now() - startTime) / 1e3).toFixed(2) + "s")}`
400
482
  );
401
483
  }
402
484
  function printBusinessImpact(roi, unifiedBudget) {
@@ -423,13 +505,14 @@ function printScoring(scoringResult, scoringProfile) {
423
505
  scoringResult.breakdown.forEach((tool) => {
424
506
  const rating = (0, import_core4.getRating)(tool.score);
425
507
  const emoji = (0, import_core4.getRatingDisplay)(rating).emoji;
508
+ const progressBar = generateProgressBar(tool.score, 15);
426
509
  console.log(
427
- ` - ${tool.toolName}: ${tool.score}/100 (${rating}) ${emoji}`
510
+ ` ${progressBar} ${tool.score}/100 (${rating}) ${emoji} ${tool.toolName}`
428
511
  );
429
512
  });
430
513
  const allRecs = scoringResult.breakdown.flatMap(
431
- (t) => (t.recommendations || []).map((r) => ({ ...r, tool: t.toolName }))
432
- ).sort((a, b) => b.estimatedImpact - a.estimatedImpact).slice(0, 3);
514
+ (t) => (t.recommendations ?? []).map((r) => ({ ...r, tool: t.toolName }))
515
+ ).sort((a, b) => b.estimatedImpact - a.estimatedImpact).slice(0, 5);
433
516
  if (allRecs.length > 0) {
434
517
  console.log(import_chalk2.default.bold("\n\u{1F3AF} Top Actionable Recommendations:"));
435
518
  allRecs.forEach((rec, i) => {
@@ -482,8 +565,8 @@ var import_core5 = require("@aiready/core");
482
565
  async function uploadAction(file, options) {
483
566
  const startTime = Date.now();
484
567
  const filePath = (0, import_path2.resolve)(process.cwd(), file);
485
- const serverUrl = options.server || process.env.AIREADY_SERVER || "https://dev.platform.getaiready.dev";
486
- const apiKey = options.apiKey || process.env.AIREADY_API_KEY;
568
+ const serverUrl = options.server ?? process.env.AIREADY_SERVER ?? "https://dev.platform.getaiready.dev";
569
+ const apiKey = options.apiKey ?? process.env.AIREADY_API_KEY;
487
570
  if (!apiKey) {
488
571
  console.error(import_chalk3.default.red("\u274C API Key is required for upload."));
489
572
  console.log(
@@ -508,7 +591,7 @@ async function uploadAction(file, options) {
508
591
  const reportContent = import_fs2.default.readFileSync(filePath, "utf-8");
509
592
  const reportData = JSON.parse(reportContent);
510
593
  console.log(import_chalk3.default.dim(` Successfully parsed report JSON.`));
511
- const repoId = options.repoId || reportData.repository?.repoId;
594
+ const repoId = options.repoId ?? reportData.repository?.repoId;
512
595
  const response = await fetch(`${serverUrl}/api/analysis/upload`, {
513
596
  method: "POST",
514
597
  headers: {
@@ -527,12 +610,12 @@ async function uploadAction(file, options) {
527
610
  uploadResult = await response.json();
528
611
  } else {
529
612
  const text = await response.text();
530
- uploadResult = { error: text || response.statusText };
613
+ uploadResult = { error: text ?? response.statusText };
531
614
  }
532
615
  if (!response.ok) {
533
616
  console.error(
534
617
  import_chalk3.default.red(
535
- `\u274C Upload failed: ${uploadResult.error || response.statusText}`
618
+ `\u274C Upload failed: ${uploadResult.error ?? response.statusText}`
536
619
  )
537
620
  );
538
621
  if (contentType?.includes("text/html")) {
@@ -583,7 +666,7 @@ ENVIRONMENT VARIABLES:
583
666
  async function scanAction(directory, options) {
584
667
  console.log(import_chalk4.default.blue("\u{1F680} Starting AIReady unified analysis...\n"));
585
668
  const startTime = Date.now();
586
- const resolvedDir = (0, import_path3.resolve)(process.cwd(), directory || ".");
669
+ const resolvedDir = (0, import_path3.resolve)(process.cwd(), directory ?? ".");
587
670
  const repoMetadata = (0, import_core6.getRepoMetadata)(resolvedDir);
588
671
  try {
589
672
  const defaults = {
@@ -673,7 +756,7 @@ async function scanAction(directory, options) {
673
756
  const { getSmartDefaults } = await import("@aiready/pattern-detect");
674
757
  const patternSmartDefaults = await getSmartDefaults(
675
758
  resolvedDir,
676
- finalOptions.toolConfigs?.[import_core6.ToolName.PatternDetect] || {}
759
+ finalOptions.toolConfigs?.[import_core6.ToolName.PatternDetect] ?? {}
677
760
  );
678
761
  if (!finalOptions.toolConfigs) finalOptions.toolConfigs = {};
679
762
  finalOptions.toolConfigs[import_core6.ToolName.PatternDetect] = {
@@ -684,7 +767,7 @@ async function scanAction(directory, options) {
684
767
  console.log(import_chalk4.default.cyan("\n=== AIReady Run Preview ==="));
685
768
  console.log(
686
769
  import_chalk4.default.white("Tools to run:"),
687
- (finalOptions.tools || []).join(", ")
770
+ (finalOptions.tools ?? []).join(", ")
688
771
  );
689
772
  const progressCallback = (event) => {
690
773
  if (event.message) {
@@ -705,7 +788,7 @@ async function scanAction(directory, options) {
705
788
  );
706
789
  }
707
790
  };
708
- const scoringProfile = options.profile || baseOptions.scoring?.profile || "default";
791
+ const scoringProfile = options.profile ?? baseOptions.scoring?.profile ?? "default";
709
792
  const results = await analyzeUnified({
710
793
  ...finalOptions,
711
794
  progressCallback,
@@ -729,7 +812,7 @@ async function scanAction(directory, options) {
729
812
  const prevReport = JSON.parse(
730
813
  (0, import_fs3.readFileSync)((0, import_path3.resolve)(process.cwd(), options.compareTo), "utf8")
731
814
  );
732
- const prevScore = prevReport.scoring?.overall || prevReport.scoring?.score;
815
+ const prevScore = prevReport.scoring?.overall ?? prevReport.scoring?.score;
733
816
  if (typeof prevScore === "number") {
734
817
  const diff = scoringResult.overall - prevScore;
735
818
  const diffStr = diff > 0 ? `+${diff}` : String(diff);
@@ -756,17 +839,17 @@ async function scanAction(directory, options) {
756
839
  void e;
757
840
  }
758
841
  }
759
- const totalWastedDuplication = (scoringResult.breakdown || []).reduce(
760
- (sum, s) => sum + (s.tokenBudget?.wastedTokens.bySource.duplication || 0),
842
+ const totalWastedDuplication = (scoringResult.breakdown ?? []).reduce(
843
+ (sum, s) => sum + (s.tokenBudget?.wastedTokens?.bySource?.duplication ?? 0),
761
844
  0
762
845
  );
763
- const totalWastedFragmentation = (scoringResult.breakdown || []).reduce(
764
- (sum, s) => sum + (s.tokenBudget?.wastedTokens.bySource.fragmentation || 0),
846
+ const totalWastedFragmentation = (scoringResult.breakdown ?? []).reduce(
847
+ (sum, s) => sum + (s.tokenBudget?.wastedTokens?.bySource?.fragmentation ?? 0),
765
848
  0
766
849
  );
767
850
  const totalContext = Math.max(
768
- ...(scoringResult.breakdown || []).map(
769
- (s) => s.tokenBudget?.totalContextTokens || 0
851
+ ...(scoringResult.breakdown ?? []).map(
852
+ (s) => s.tokenBudget?.totalContextTokens ?? 0
770
853
  ),
771
854
  0
772
855
  );
@@ -790,7 +873,7 @@ async function scanAction(directory, options) {
790
873
  });
791
874
  }
792
875
  }
793
- const modelId = options.model || "claude-3-5-sonnet";
876
+ const modelId = options.model ?? "gpt-5.4-mini";
794
877
  const roi = (await import("@aiready/core")).calculateBusinessROI({
795
878
  tokenWaste: unifiedBudget.wastedTokens.total,
796
879
  issues: allIssues,
@@ -827,9 +910,9 @@ async function scanAction(directory, options) {
827
910
  ...mapToUnifiedReport(results, scoringResult),
828
911
  repository: repoMetadata
829
912
  };
830
- const outputFormat = options.output || finalOptions.output?.format || "console";
913
+ const outputFormat = options.output ?? finalOptions.output?.format ?? "console";
831
914
  const outputPath = (0, import_core6.resolveOutputPath)(
832
- options.outputFile || finalOptions.output?.file,
915
+ options.outputFile ?? finalOptions.output?.file,
833
916
  `aiready-report-${getReportTimestamp()}.json`,
834
917
  resolvedDir
835
918
  );
@@ -856,8 +939,8 @@ async function scanAction(directory, options) {
856
939
  await warnIfGraphCapExceeded(outputData, resolvedDir);
857
940
  if (scoringResult) {
858
941
  const threshold = options.threshold ? parseInt(options.threshold) : void 0;
859
- const failOnLevel = options.failOn || "critical";
860
- const isCI = options.ci || process.env.CI === "true";
942
+ const failOnLevel = options.failOn ?? "critical";
943
+ const isCI = options.ci ?? process.env.CI === "true";
861
944
  let shouldFail = false;
862
945
  let failReason = "";
863
946
  const report = mapToUnifiedReport(results, scoringResult);
@@ -913,6 +996,9 @@ async function initAction(options) {
913
996
  process.exit(1);
914
997
  }
915
998
  const baseConfig = {
999
+ // Target quality score threshold (0-100)
1000
+ threshold: 75,
1001
+ // Global scan settings
916
1002
  scan: {
917
1003
  include: [
918
1004
  "src/**/*.ts",
@@ -939,6 +1025,17 @@ async function initAction(options) {
939
1025
  import_core7.ToolName.ChangeAmplification
940
1026
  ]
941
1027
  },
1028
+ // Output preferences
1029
+ output: {
1030
+ format: "console",
1031
+ showBreakdown: true,
1032
+ saveTo: "aiready-report.json"
1033
+ },
1034
+ // Scoring profile and weights
1035
+ scoring: {
1036
+ profile: "balanced"
1037
+ },
1038
+ // Tool-specific configurations
942
1039
  tools: {
943
1040
  [import_core7.ToolName.PatternDetect]: {
944
1041
  minSimilarity: 0.8,
@@ -962,7 +1059,33 @@ async function initAction(options) {
962
1059
  },
963
1060
  [import_core7.ToolName.NamingConsistency]: {
964
1061
  shortWords: ["id", "db", "ui", "ai"],
965
- ...options.full ? { acceptedAbbreviations: [], disableChecks: [] } : {}
1062
+ acceptedAbbreviations: [
1063
+ "API",
1064
+ "JSON",
1065
+ "CSV",
1066
+ "HTML",
1067
+ "CSS",
1068
+ "HTTP",
1069
+ "URL",
1070
+ "SDK",
1071
+ "CLI",
1072
+ "AI",
1073
+ "ML",
1074
+ "ID",
1075
+ "DB",
1076
+ "UI",
1077
+ "UX",
1078
+ "DOM",
1079
+ "UUID",
1080
+ "GUID",
1081
+ "DEFAULT",
1082
+ "MAX",
1083
+ "MIN",
1084
+ "config",
1085
+ "INIT",
1086
+ "SKILL"
1087
+ ],
1088
+ ...options.full ? { disableChecks: [] } : {}
966
1089
  },
967
1090
  [import_core7.ToolName.AiSignalClarity]: {
968
1091
  checkMagicLiterals: true,
@@ -971,48 +1094,42 @@ async function initAction(options) {
971
1094
  checkUndocumentedExports: true,
972
1095
  ...options.full ? { checkImplicitSideEffects: false, checkDeepCallbacks: false } : {}
973
1096
  },
974
- ...options.full ? {
975
- [import_core7.ToolName.AgentGrounding]: {
976
- maxRecommendedDepth: 5,
977
- readmeStaleDays: 30
978
- },
979
- [import_core7.ToolName.TestabilityIndex]: {
980
- minCoverageRatio: 0.7,
981
- testPatterns: ["**/*.test.ts", "**/__tests__/**"]
982
- },
983
- [import_core7.ToolName.DocDrift]: {
984
- maxCommits: 50,
985
- staleMonths: 3
986
- },
987
- [import_core7.ToolName.DependencyHealth]: {
988
- trainingCutoffYear: 2023
989
- }
990
- } : {}
991
- },
992
- scoring: {
993
- threshold: 70,
994
- showBreakdown: true,
995
- ...options.full ? { profile: "default" } : {}
1097
+ [import_core7.ToolName.AgentGrounding]: {
1098
+ maxRecommendedDepth: 5,
1099
+ readmeStaleDays: 30
1100
+ },
1101
+ [import_core7.ToolName.TestabilityIndex]: {
1102
+ minCoverageRatio: 0.7,
1103
+ testPatterns: ["**/*.test.ts", "**/__tests__/**"]
1104
+ },
1105
+ [import_core7.ToolName.DocDrift]: {
1106
+ maxCommits: 50,
1107
+ staleMonths: 3
1108
+ },
1109
+ [import_core7.ToolName.DependencyHealth]: {
1110
+ trainingCutoffYear: 2023
1111
+ },
1112
+ [import_core7.ToolName.ChangeAmplification]: {
1113
+ // No specific options yet, uses global scan settings
1114
+ }
996
1115
  },
997
- ...options.full ? {
998
- visualizer: {
999
- groupingDirs: ["packages", "src", "lib"],
1000
- graph: {
1001
- maxNodes: 5e3,
1002
- maxEdges: 1e4
1003
- }
1116
+ // Visualizer settings (interactive graph)
1117
+ visualizer: {
1118
+ groupingDirs: ["packages", "src", "lib"],
1119
+ graph: {
1120
+ maxNodes: 5e3,
1121
+ maxEdges: 1e4
1004
1122
  }
1005
- } : {}
1123
+ }
1006
1124
  };
1007
1125
  const defaultConfig = baseConfig;
1008
1126
  let content;
1009
1127
  if (fileExt === "js") {
1010
- content = `/** @type {import('@aiready/core').AIReadyConfig} */
1011
- module.exports = ${JSON.stringify(
1012
- defaultConfig,
1013
- null,
1014
- 2
1015
- )};
1128
+ content = `/**
1129
+ * AIReady Configuration
1130
+ * @type {import('@aiready/core').AIReadyConfig}
1131
+ */
1132
+ module.exports = ${JSON.stringify(defaultConfig, null, 2)};
1016
1133
  `;
1017
1134
  } else {
1018
1135
  content = JSON.stringify(defaultConfig, null, 2);
@@ -1041,7 +1158,7 @@ var import_core8 = require("@aiready/core");
1041
1158
  async function patternsAction(directory, options) {
1042
1159
  console.log(import_chalk6.default.blue("\u{1F50D} Analyzing patterns...\n"));
1043
1160
  const startTime = Date.now();
1044
- const resolvedDir = (0, import_path5.resolve)(process.cwd(), directory || ".");
1161
+ const resolvedDir = (0, import_path5.resolve)(process.cwd(), directory ?? ".");
1045
1162
  try {
1046
1163
  const useSmartDefaults = !options.fullScan;
1047
1164
  const defaults = {
@@ -1085,8 +1202,8 @@ async function patternsAction(directory, options) {
1085
1202
  if (options.score) {
1086
1203
  patternScore = calculatePatternScore(duplicates, results.length);
1087
1204
  }
1088
- const outputFormat = options.output || finalOptions.output?.format || "console";
1089
- const userOutputFile = options.outputFile || finalOptions.output?.file;
1205
+ const outputFormat = options.output ?? finalOptions.output?.format ?? "console";
1206
+ const userOutputFile = options.outputFile ?? finalOptions.output?.file;
1090
1207
  if (outputFormat === "json") {
1091
1208
  const outputData = {
1092
1209
  results,
@@ -1187,7 +1304,7 @@ var import_core9 = require("@aiready/core");
1187
1304
  async function contextAction(directory, options) {
1188
1305
  console.log(import_chalk7.default.blue("\u{1F9E0} Analyzing context costs...\n"));
1189
1306
  const startTime = Date.now();
1190
- const resolvedDir = (0, import_path6.resolve)(process.cwd(), directory || ".");
1307
+ const resolvedDir = (0, import_path6.resolve)(process.cwd(), directory ?? ".");
1191
1308
  try {
1192
1309
  const defaults = {
1193
1310
  maxDepth: 5,
@@ -1231,8 +1348,8 @@ async function contextAction(directory, options) {
1231
1348
  if (options.score) {
1232
1349
  contextScore = calculateContextScore(summary);
1233
1350
  }
1234
- const outputFormat = options.output || finalOptions.output?.format || "console";
1235
- const userOutputFile = options.outputFile || finalOptions.output?.file;
1351
+ const outputFormat = options.output ?? finalOptions.output?.format ?? "console";
1352
+ const userOutputFile = options.outputFile ?? finalOptions.output?.file;
1236
1353
  if (outputFormat === "json") {
1237
1354
  const outputData = {
1238
1355
  results,
@@ -1250,7 +1367,7 @@ async function contextAction(directory, options) {
1250
1367
  `\u2705 Results saved to ${outputPath}`
1251
1368
  );
1252
1369
  } else {
1253
- const terminalWidth = process.stdout.columns || 80;
1370
+ const terminalWidth = process.stdout.columns ?? 80;
1254
1371
  const dividerWidth = Math.min(60, terminalWidth - 2);
1255
1372
  const divider = "\u2501".repeat(dividerWidth);
1256
1373
  console.log(import_chalk7.default.cyan(divider));
@@ -1388,7 +1505,7 @@ var import_core10 = require("@aiready/core");
1388
1505
  async function consistencyAction(directory, options) {
1389
1506
  console.log(import_chalk8.default.blue("\u{1F50D} Analyzing consistency...\n"));
1390
1507
  const startTime = Date.now();
1391
- const resolvedDir = (0, import_path7.resolve)(process.cwd(), directory || ".");
1508
+ const resolvedDir = (0, import_path7.resolve)(process.cwd(), directory ?? ".");
1392
1509
  try {
1393
1510
  const defaults = {
1394
1511
  checkNaming: true,
@@ -1413,14 +1530,14 @@ async function consistencyAction(directory, options) {
1413
1530
  const elapsedTime = (0, import_core10.getElapsedTime)(startTime);
1414
1531
  let consistencyScore;
1415
1532
  if (options.score) {
1416
- const issues = report.results?.flatMap((r) => r.issues) || [];
1533
+ const issues = report.results?.flatMap((r) => r.issues) ?? [];
1417
1534
  consistencyScore = calculateConsistencyScore(
1418
1535
  issues,
1419
1536
  report.summary.filesAnalyzed
1420
1537
  );
1421
1538
  }
1422
- const outputFormat = options.output || finalOptions.output?.format || "console";
1423
- const userOutputFile = options.outputFile || finalOptions.output?.file;
1539
+ const outputFormat = options.output ?? finalOptions.output?.format ?? "console";
1540
+ const userOutputFile = options.outputFile ?? finalOptions.output?.file;
1424
1541
  if (outputFormat === "json") {
1425
1542
  const outputData = {
1426
1543
  ...report,
@@ -1458,7 +1575,7 @@ async function consistencyAction(directory, options) {
1458
1575
  console.log(` Naming: ${import_chalk8.default.yellow(report.summary.namingIssues)}`);
1459
1576
  console.log(` Patterns: ${import_chalk8.default.yellow(report.summary.patternIssues)}`);
1460
1577
  console.log(
1461
- ` Architecture: ${import_chalk8.default.yellow(report.summary.architectureIssues || 0)}`
1578
+ ` Architecture: ${import_chalk8.default.yellow(report.summary.architectureIssues ?? 0)}`
1462
1579
  );
1463
1580
  console.log(`Analysis Time: ${import_chalk8.default.gray(elapsedTime + "s")}
1464
1581
  `);
@@ -1557,7 +1674,7 @@ var import_core11 = require("@aiready/core");
1557
1674
  var import_core12 = require("@aiready/core");
1558
1675
  async function visualizeAction(directory, options) {
1559
1676
  try {
1560
- const dirPath = (0, import_path8.resolve)(process.cwd(), directory || ".");
1677
+ const dirPath = (0, import_path8.resolve)(process.cwd(), directory ?? ".");
1561
1678
  let reportPath = options.report ? (0, import_path8.resolve)(dirPath, options.report) : null;
1562
1679
  if (!reportPath || !(0, import_fs6.existsSync)(reportPath)) {
1563
1680
  const latestScan = (0, import_core12.findLatestReport)(dirPath);
@@ -1603,7 +1720,7 @@ Or specify a custom report:
1603
1720
  console.log("Building graph from report...");
1604
1721
  const { GraphBuilder } = await import("@aiready/visualizer/graph");
1605
1722
  const graph = GraphBuilder.buildFromReport(report, dirPath);
1606
- let useDevMode = options.dev || false;
1723
+ let useDevMode = options.dev ?? false;
1607
1724
  let devServerStarted = false;
1608
1725
  if (useDevMode) {
1609
1726
  try {
@@ -1719,7 +1836,7 @@ Or specify a custom report:
1719
1836
  console.log("Generating HTML...");
1720
1837
  const html = (0, import_core12.generateHTML)(graph);
1721
1838
  const defaultOutput = "visualization.html";
1722
- const outPath = (0, import_path8.resolve)(dirPath, options.output || defaultOutput);
1839
+ const outPath = (0, import_path8.resolve)(dirPath, options.output ?? defaultOutput);
1723
1840
  (0, import_fs6.writeFileSync)(outPath, html, "utf8");
1724
1841
  console.log(import_chalk9.default.green(`\u2705 Visualization written to: ${outPath}`));
1725
1842
  if (options.open || options.serve) {
@@ -1731,7 +1848,7 @@ Or specify a custom report:
1731
1848
  const fsp = await import("fs/promises");
1732
1849
  const server = http.createServer(async (req, res) => {
1733
1850
  try {
1734
- const urlPath = req.url || "/";
1851
+ const urlPath = req.url ?? "/";
1735
1852
  if (urlPath === "/" || urlPath === "/index.html") {
1736
1853
  const content = await fsp.readFile(outPath, "utf8");
1737
1854
  res.writeHead(200, {
@@ -1869,7 +1986,7 @@ async function bugAction(message, options) {
1869
1986
  const repoUrl = "https://github.com/caopengau/aiready-cli";
1870
1987
  const repoSlug = "caopengau/aiready-cli";
1871
1988
  if (message) {
1872
- const type = options.type || "bug";
1989
+ const type = options.type ?? "bug";
1873
1990
  const title = `[${type.toUpperCase()}] ${message}`;
1874
1991
  const label = type === "bug" ? "bug" : type === "feature" ? "enhancement" : "metric";
1875
1992
  const body = `