@aiready/consistency 0.8.30 → 0.8.32

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
@@ -49,6 +49,7 @@ function parseFile(filePath, content) {
49
49
  filePath: isTypeScript ? filePath : void 0
50
50
  });
51
51
  } catch (error) {
52
+ void error;
52
53
  return null;
53
54
  }
54
55
  }
@@ -287,6 +288,7 @@ var ScopeTracker = class {
287
288
 
288
289
  // src/utils/context-detector.ts
289
290
  function detectFileType(filePath, ast) {
291
+ void ast;
290
292
  const path = filePath.toLowerCase();
291
293
  if (path.match(/\.(test|spec)\.(ts|tsx|js|jsx)$/) || path.includes("__tests__")) {
292
294
  return "test";
@@ -317,7 +319,9 @@ function detectCodeLayer(ast) {
317
319
  }
318
320
  if (node.type === "FunctionDeclaration" && node.id) {
319
321
  const name = node.id.name;
320
- if (name.match(/^(get|post|put|delete|patch|handle|api|route|controller)/i)) {
322
+ if (name.match(
323
+ /^(get|post|put|delete|patch|handle|api|route|controller)/i
324
+ )) {
321
325
  hasAPIIndicators++;
322
326
  }
323
327
  if (name.match(/^(calculate|process|validate|transform|compute|analyze)/i)) {
@@ -326,7 +330,9 @@ function detectCodeLayer(ast) {
326
330
  if (name.match(/^(find|create|update|delete|save|fetch|query|insert)/i)) {
327
331
  hasDataIndicators++;
328
332
  }
329
- if (name.match(/^(format|parse|convert|normalize|sanitize|encode|decode)/i)) {
333
+ if (name.match(
334
+ /^(format|parse|convert|normalize|sanitize|encode|decode)/i
335
+ )) {
330
336
  hasUtilityIndicators++;
331
337
  }
332
338
  }
@@ -845,10 +851,15 @@ async function loadNamingConfig(files) {
845
851
  const rootDir = files.length > 0 ? (0, import_path.dirname)(files[0]) : process.cwd();
846
852
  const config = await (0, import_core.loadConfig)(rootDir);
847
853
  const consistencyConfig = config?.tools?.["consistency"];
848
- const customAbbreviations = new Set(consistencyConfig?.acceptedAbbreviations || []);
854
+ const customAbbreviations = new Set(
855
+ consistencyConfig?.acceptedAbbreviations || []
856
+ );
849
857
  const customShortWords = new Set(consistencyConfig?.shortWords || []);
850
858
  const disabledChecks = new Set(consistencyConfig?.disableChecks || []);
851
- const allAbbreviations = /* @__PURE__ */ new Set([...ACCEPTABLE_ABBREVIATIONS, ...customAbbreviations]);
859
+ const allAbbreviations = /* @__PURE__ */ new Set([
860
+ ...ACCEPTABLE_ABBREVIATIONS,
861
+ ...customAbbreviations
862
+ ]);
852
863
  const allShortWords = /* @__PURE__ */ new Set([...COMMON_SHORT_WORDS, ...customShortWords]);
853
864
  return {
854
865
  customAbbreviations,
@@ -897,9 +908,14 @@ function analyzeFileNamingAST(file, ast, allAbbreviations, allShortWords, disabl
897
908
  if ("params" in node) {
898
909
  for (const param of node.params) {
899
910
  if (param.type === "Identifier") {
900
- scopeTracker.declareVariable(param.name, param, getLineNumber(param), {
901
- isParameter: true
902
- });
911
+ scopeTracker.declareVariable(
912
+ param.name,
913
+ param,
914
+ getLineNumber(param),
915
+ {
916
+ isParameter: true
917
+ }
918
+ );
903
919
  } else if (param.type === "ObjectPattern" || param.type === "ArrayPattern") {
904
920
  extractIdentifiersFromPattern(param, scopeTracker, true);
905
921
  }
@@ -914,7 +930,7 @@ function analyzeFileNamingAST(file, ast, allAbbreviations, allShortWords, disabl
914
930
  }
915
931
  if (node.type === "VariableDeclarator") {
916
932
  if (node.id.type === "Identifier") {
917
- const isInCoverage = isCoverageContext(node, ancestors);
933
+ void isCoverageContext(node, ancestors);
918
934
  scopeTracker.declareVariable(
919
935
  node.id.name,
920
936
  node.id,
@@ -926,7 +942,12 @@ function analyzeFileNamingAST(file, ast, allAbbreviations, allShortWords, disabl
926
942
  }
927
943
  );
928
944
  } else if (node.id.type === "ObjectPattern" || node.id.type === "ArrayPattern") {
929
- extractIdentifiersFromPattern(node.id, scopeTracker, false, ancestors);
945
+ extractIdentifiersFromPattern(
946
+ node.id,
947
+ scopeTracker,
948
+ false,
949
+ ancestors
950
+ );
930
951
  }
931
952
  }
932
953
  if (node.type === "Identifier" && parent) {
@@ -993,7 +1014,10 @@ function analyzeFileNamingAST(file, ast, allAbbreviations, allShortWords, disabl
993
1014
  }
994
1015
  if (!disabledChecks.has("convention-mix") && file.match(/\.(ts|tsx|js|jsx)$/)) {
995
1016
  if (name.includes("_") && !name.startsWith("_") && name.toLowerCase() === name) {
996
- const camelCase = name.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
1017
+ const camelCase = name.replace(
1018
+ /_([a-z])/g,
1019
+ (_, letter) => letter.toUpperCase()
1020
+ );
997
1021
  issues.push({
998
1022
  file,
999
1023
  line,
@@ -1013,16 +1037,37 @@ function analyzeFileNamingAST(file, ast, allAbbreviations, allShortWords, disabl
1013
1037
  if (!name) return;
1014
1038
  const line = getLineNumber(node);
1015
1039
  if (["main", "init", "setup", "bootstrap"].includes(name)) return;
1016
- const hasActionVerb = name.match(/^(get|set|is|has|can|should|create|update|delete|fetch|load|save|process|handle|validate|check|find|search|filter|map|reduce|make|do|run|start|stop|build|parse|format|render|calculate|compute|generate|transform|convert|normalize|sanitize|encode|decode|compress|extract|merge|split|join|sort|compare|test|verify|ensure|apply|execute|invoke|call|emit|dispatch|trigger|listen|subscribe|unsubscribe|add|remove|clear|reset|toggle|enable|disable|open|close|connect|disconnect|send|receive|read|write|import|export|register|unregister|mount|unmount|track|store|persist|upsert|derive|classify|combine|discover|activate|require|assert|expect|mask|escape|sign|put|list|complete|page|safe|mock|pick|pluralize|text|count|detect|select)/);
1017
- const isFactoryPattern = name.match(/(Factory|Builder|Creator|Generator|Provider|Adapter|Mock)$/);
1040
+ const hasActionVerb = name.match(
1041
+ /^(get|set|is|has|can|should|create|update|delete|fetch|load|save|process|handle|validate|check|find|search|filter|map|reduce|make|do|run|start|stop|build|parse|format|render|calculate|compute|generate|transform|convert|normalize|sanitize|encode|decode|compress|extract|merge|split|join|sort|compare|test|verify|ensure|apply|execute|invoke|call|emit|dispatch|trigger|listen|subscribe|unsubscribe|add|remove|clear|reset|toggle|enable|disable|open|close|connect|disconnect|send|receive|read|write|import|export|register|unregister|mount|unmount|track|store|persist|upsert|derive|classify|combine|discover|activate|require|assert|expect|mask|escape|sign|put|list|complete|page|safe|mock|pick|pluralize|text|count|detect|select)/
1042
+ );
1043
+ const isFactoryPattern = name.match(
1044
+ /(Factory|Builder|Creator|Generator|Provider|Adapter|Mock)$/
1045
+ );
1018
1046
  const isEventHandler = name.match(/^on[A-Z]/);
1019
1047
  const isDescriptiveLong = name.length > 15;
1020
1048
  const isReactHook = name.match(/^use[A-Z]/);
1021
1049
  const isHelperPattern = name.match(/^(to|from|with|without|for|as|into)\w+/) || name.match(/^\w+(To|From|With|Without|For|As|Into)\w*$/);
1022
- const isUtilityName = ["cn", "proxy", "sitemap", "robots", "gtag"].includes(name);
1023
- const isLanguageKeyword = ["constructor", "toString", "valueOf", "toJSON"].includes(name);
1024
- const isFrameworkPattern = name.match(/^(goto|fill|click|select|submit|wait|expect)\w*/);
1025
- const isDescriptivePattern = name.match(/^(default|total|count|sum|avg|max|min|initial|current|previous|next)\w+/) || name.match(/\w+(Count|Total|Sum|Average|List|Map|Set|Config|Settings|Options|Props|Data|Info|Details|State|Status|Response|Result)$/);
1050
+ const isUtilityName = [
1051
+ "cn",
1052
+ "proxy",
1053
+ "sitemap",
1054
+ "robots",
1055
+ "gtag"
1056
+ ].includes(name);
1057
+ const isLanguageKeyword = [
1058
+ "constructor",
1059
+ "toString",
1060
+ "valueOf",
1061
+ "toJSON"
1062
+ ].includes(name);
1063
+ const isFrameworkPattern = name.match(
1064
+ /^(goto|fill|click|select|submit|wait|expect)\w*/
1065
+ );
1066
+ const isDescriptivePattern = name.match(
1067
+ /^(default|total|count|sum|avg|max|min|initial|current|previous|next)\w+/
1068
+ ) || name.match(
1069
+ /\w+(Count|Total|Sum|Average|List|Map|Set|Config|Settings|Options|Props|Data|Info|Details|State|Status|Response|Result)$/
1070
+ );
1026
1071
  const capitalCount = (name.match(/[A-Z]/g) || []).length;
1027
1072
  const isCompoundWord = capitalCount >= 3;
1028
1073
  if (!hasActionVerb && !isFactoryPattern && !isEventHandler && !isDescriptiveLong && !isReactHook && !isHelperPattern && !isUtilityName && !isDescriptivePattern && !isCompoundWord && !isLanguageKeyword && !isFrameworkPattern) {
@@ -1042,6 +1087,7 @@ function analyzeFileNamingAST(file, ast, allAbbreviations, allShortWords, disabl
1042
1087
  return issues;
1043
1088
  }
1044
1089
  function extractIdentifiersFromPattern(pattern, scopeTracker, isParameter, ancestors) {
1090
+ void ancestors;
1045
1091
  if (pattern.type === "ObjectPattern") {
1046
1092
  for (const prop of pattern.properties) {
1047
1093
  if (prop.type === "Property" && prop.value.type === "Identifier") {
@@ -1099,7 +1145,12 @@ async function analyzePythonNaming(files) {
1099
1145
  const code = await fs.promises.readFile(file, "utf-8");
1100
1146
  const result = parser.parse(code, file);
1101
1147
  for (const exp of result.exports) {
1102
- const nameIssue = checkPythonNaming(exp.name, exp.type, file, exp.loc?.start.line || 0);
1148
+ const nameIssue = checkPythonNaming(
1149
+ exp.name,
1150
+ exp.type,
1151
+ file,
1152
+ exp.loc?.start.line || 0
1153
+ );
1103
1154
  if (nameIssue) {
1104
1155
  issues.push(nameIssue);
1105
1156
  }
@@ -1107,7 +1158,12 @@ async function analyzePythonNaming(files) {
1107
1158
  for (const imp of result.imports) {
1108
1159
  for (const spec of imp.specifiers) {
1109
1160
  if (spec !== "*" && spec !== "default") {
1110
- const nameIssue = checkPythonNaming(spec, "variable", file, imp.loc?.start.line || 0);
1161
+ const nameIssue = checkPythonNaming(
1162
+ spec,
1163
+ "variable",
1164
+ file,
1165
+ imp.loc?.start.line || 0
1166
+ );
1111
1167
  if (nameIssue) {
1112
1168
  issues.push(nameIssue);
1113
1169
  }
@@ -1230,15 +1286,19 @@ async function analyzeErrorHandling(files) {
1230
1286
  }
1231
1287
  }
1232
1288
  const issues = [];
1233
- const strategiesUsed = Object.values(patterns).filter((p) => p.length > 0).length;
1289
+ const strategiesUsed = Object.values(patterns).filter(
1290
+ (p) => p.length > 0
1291
+ ).length;
1234
1292
  if (strategiesUsed > 2) {
1235
1293
  issues.push({
1236
- files: [.../* @__PURE__ */ new Set([
1237
- ...patterns.tryCatch,
1238
- ...patterns.throwsError,
1239
- ...patterns.returnsNull,
1240
- ...patterns.returnsError
1241
- ])],
1294
+ files: [
1295
+ .../* @__PURE__ */ new Set([
1296
+ ...patterns.tryCatch,
1297
+ ...patterns.throwsError,
1298
+ ...patterns.returnsNull,
1299
+ ...patterns.returnsError
1300
+ ])
1301
+ ],
1242
1302
  type: "error-handling",
1243
1303
  description: "Inconsistent error handling strategies across codebase",
1244
1304
  examples: [
@@ -1359,6 +1419,7 @@ async function analyzeConsistency(options) {
1359
1419
  minSeverity = "info",
1360
1420
  ...scanOptions
1361
1421
  } = options;
1422
+ void checkArchitecture;
1362
1423
  const filePaths = await (0, import_core4.scanFiles)(scanOptions);
1363
1424
  const tsJsFiles = filePaths.filter((f) => /\.(ts|tsx|js|jsx)$/i.test(f));
1364
1425
  const pythonFiles = filePaths.filter((f) => /\.py$/i.test(f));
@@ -1428,10 +1489,14 @@ async function analyzeConsistency(options) {
1428
1489
  results.sort((fileResultA, fileResultB) => {
1429
1490
  const severityOrder = { critical: 0, major: 1, minor: 2, info: 3 };
1430
1491
  const maxSeverityA = Math.min(
1431
- ...fileResultA.issues.map((i) => severityOrder[i.severity])
1492
+ ...fileResultA.issues.map(
1493
+ (i) => severityOrder[i.severity]
1494
+ )
1432
1495
  );
1433
1496
  const maxSeverityB = Math.min(
1434
- ...fileResultB.issues.map((i) => severityOrder[i.severity])
1497
+ ...fileResultB.issues.map(
1498
+ (i) => severityOrder[i.severity]
1499
+ )
1435
1500
  );
1436
1501
  if (maxSeverityA !== maxSeverityB) {
1437
1502
  return maxSeverityA - maxSeverityB;
@@ -1439,8 +1504,12 @@ async function analyzeConsistency(options) {
1439
1504
  return fileResultB.issues.length - fileResultA.issues.length;
1440
1505
  });
1441
1506
  const recommendations = generateRecommendations(namingIssues, patternIssues);
1442
- const namingCountFiltered = namingIssues.filter((i) => shouldIncludeSeverity(i.severity, minSeverity)).length;
1443
- const patternCountFiltered = patternIssues.filter((i) => shouldIncludeSeverity(i.severity, minSeverity)).length;
1507
+ const namingCountFiltered = namingIssues.filter(
1508
+ (i) => shouldIncludeSeverity(i.severity, minSeverity)
1509
+ ).length;
1510
+ const patternCountFiltered = patternIssues.filter(
1511
+ (i) => shouldIncludeSeverity(i.severity, minSeverity)
1512
+ ).length;
1444
1513
  return {
1445
1514
  summary: {
1446
1515
  totalIssues: namingCountFiltered + patternCountFiltered,
@@ -1459,19 +1528,26 @@ function shouldIncludeSeverity(severity, minSeverity) {
1459
1528
  }
1460
1529
  function calculateConsistencyScore(issues) {
1461
1530
  const weights = { critical: 10, major: 5, minor: 2, info: 1 };
1462
- const totalWeight = issues.reduce((sum, issue) => sum + weights[issue.severity], 0);
1531
+ const totalWeight = issues.reduce(
1532
+ (sum, issue) => sum + weights[issue.severity],
1533
+ 0
1534
+ );
1463
1535
  return Math.max(0, 1 - totalWeight / 100);
1464
1536
  }
1465
1537
  function generateRecommendations(namingIssues, patternIssues) {
1466
1538
  const recommendations = [];
1467
1539
  if (namingIssues.length > 0) {
1468
- const conventionMixCount = namingIssues.filter((i) => i.type === "convention-mix").length;
1540
+ const conventionMixCount = namingIssues.filter(
1541
+ (i) => i.type === "convention-mix"
1542
+ ).length;
1469
1543
  if (conventionMixCount > 0) {
1470
1544
  recommendations.push(
1471
1545
  `Standardize naming conventions: Found ${conventionMixCount} snake_case variables in TypeScript/JavaScript (use camelCase)`
1472
1546
  );
1473
1547
  }
1474
- const poorNamingCount = namingIssues.filter((i) => i.type === "poor-naming").length;
1548
+ const poorNamingCount = namingIssues.filter(
1549
+ (i) => i.type === "poor-naming"
1550
+ ).length;
1475
1551
  if (poorNamingCount > 0) {
1476
1552
  recommendations.push(
1477
1553
  `Improve variable naming: Found ${poorNamingCount} single-letter or unclear variable names`
@@ -1479,7 +1555,9 @@ function generateRecommendations(namingIssues, patternIssues) {
1479
1555
  }
1480
1556
  }
1481
1557
  if (patternIssues.length > 0) {
1482
- const errorHandlingIssues = patternIssues.filter((i) => i.type === "error-handling");
1558
+ const errorHandlingIssues = patternIssues.filter(
1559
+ (i) => i.type === "error-handling"
1560
+ );
1483
1561
  if (errorHandlingIssues.length > 0) {
1484
1562
  recommendations.push(
1485
1563
  "Standardize error handling strategy across the codebase (prefer try-catch with typed errors)"
@@ -1499,7 +1577,9 @@ function generateRecommendations(namingIssues, patternIssues) {
1499
1577
  }
1500
1578
  }
1501
1579
  if (recommendations.length === 0) {
1502
- recommendations.push("No major consistency issues found! Your codebase follows good practices.");
1580
+ recommendations.push(
1581
+ "No major consistency issues found! Your codebase follows good practices."
1582
+ );
1503
1583
  }
1504
1584
  return recommendations;
1505
1585
  }
@@ -1510,7 +1590,11 @@ var import_fs2 = require("fs");
1510
1590
  var import_path2 = require("path");
1511
1591
  var import_core5 = require("@aiready/core");
1512
1592
  var program = new import_commander.Command();
1513
- program.name("aiready-consistency").description("Detect consistency patterns in naming, code structure, and architecture").version("0.1.0").addHelpText("after", `
1593
+ program.name("aiready-consistency").description(
1594
+ "Detect consistency patterns in naming, code structure, and architecture"
1595
+ ).version("0.1.0").addHelpText(
1596
+ "after",
1597
+ `
1514
1598
  LANGUAGE SUPPORT:
1515
1599
  Supported: TypeScript (.ts, .tsx), JavaScript (.js, .jsx)
1516
1600
  Note: Python, Java, and other language files will be safely ignored
@@ -1529,7 +1613,18 @@ EXAMPLES:
1529
1613
  aiready-consistency . --no-naming # Skip naming checks
1530
1614
  aiready-consistency . --min-severity major # Only show major+ patterns
1531
1615
  aiready-consistency . --output json > report.json # JSON export
1532
- `).argument("<directory>", "Directory to analyze").option("--naming", "Check naming conventions and quality (default: true)").option("--no-naming", "Skip naming analysis").option("--patterns", "Check code pattern consistency (default: true)").option("--no-patterns", "Skip pattern analysis").option("--architecture", "Check architectural consistency (not yet implemented)").option("--min-severity <level>", "Minimum severity: info|minor|major|critical. Default: info").option("--include <patterns>", "File patterns to include (comma-separated)").option("--exclude <patterns>", "File patterns to exclude (comma-separated)").option("-o, --output <format>", "Output format: console|json|markdown", "console").option("--output-file <path>", "Output file path (for json/markdown)").action(async (directory, options) => {
1616
+ `
1617
+ ).argument("<directory>", "Directory to analyze").option("--naming", "Check naming conventions and quality (default: true)").option("--no-naming", "Skip naming analysis").option("--patterns", "Check code pattern consistency (default: true)").option("--no-patterns", "Skip pattern analysis").option(
1618
+ "--architecture",
1619
+ "Check architectural consistency (not yet implemented)"
1620
+ ).option(
1621
+ "--min-severity <level>",
1622
+ "Minimum severity: info|minor|major|critical. Default: info"
1623
+ ).option("--include <patterns>", "File patterns to include (comma-separated)").option("--exclude <patterns>", "File patterns to exclude (comma-separated)").option(
1624
+ "-o, --output <format>",
1625
+ "Output format: console|json|markdown",
1626
+ "console"
1627
+ ).option("--output-file <path>", "Output file path (for json/markdown)").action(async (directory, options) => {
1533
1628
  console.log(import_chalk.default.blue("\u{1F50D} Analyzing consistency...\n"));
1534
1629
  const startTime = Date.now();
1535
1630
  const config = await (0, import_core5.loadConfig)(directory);
@@ -1595,7 +1690,11 @@ function displayConsoleReport(report, elapsedTime) {
1595
1690
  console.log(`Analysis Time: ${import_chalk.default.gray(elapsedTime + "s")}
1596
1691
  `);
1597
1692
  if (summary.totalIssues === 0) {
1598
- console.log(import_chalk.default.green("\u2728 No consistency patterns found! Your codebase is AI-friendly.\n"));
1693
+ console.log(
1694
+ import_chalk.default.green(
1695
+ "\u2728 No consistency patterns found! Your codebase is AI-friendly.\n"
1696
+ )
1697
+ );
1599
1698
  return;
1600
1699
  }
1601
1700
  const namingResults = results.filter(
package/dist/cli.mjs CHANGED
@@ -1,16 +1,24 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  analyzeConsistency
4
- } from "./chunk-YEHXYHGY.mjs";
4
+ } from "./chunk-J5IFYDVU.mjs";
5
5
 
6
6
  // src/cli.ts
7
7
  import { Command } from "commander";
8
8
  import chalk from "chalk";
9
9
  import { writeFileSync, mkdirSync, existsSync } from "fs";
10
10
  import { dirname } from "path";
11
- import { loadConfig, mergeConfigWithDefaults, resolveOutputPath } from "@aiready/core";
11
+ import {
12
+ loadConfig,
13
+ mergeConfigWithDefaults,
14
+ resolveOutputPath
15
+ } from "@aiready/core";
12
16
  var program = new Command();
13
- program.name("aiready-consistency").description("Detect consistency patterns in naming, code structure, and architecture").version("0.1.0").addHelpText("after", `
17
+ program.name("aiready-consistency").description(
18
+ "Detect consistency patterns in naming, code structure, and architecture"
19
+ ).version("0.1.0").addHelpText(
20
+ "after",
21
+ `
14
22
  LANGUAGE SUPPORT:
15
23
  Supported: TypeScript (.ts, .tsx), JavaScript (.js, .jsx)
16
24
  Note: Python, Java, and other language files will be safely ignored
@@ -29,7 +37,18 @@ EXAMPLES:
29
37
  aiready-consistency . --no-naming # Skip naming checks
30
38
  aiready-consistency . --min-severity major # Only show major+ patterns
31
39
  aiready-consistency . --output json > report.json # JSON export
32
- `).argument("<directory>", "Directory to analyze").option("--naming", "Check naming conventions and quality (default: true)").option("--no-naming", "Skip naming analysis").option("--patterns", "Check code pattern consistency (default: true)").option("--no-patterns", "Skip pattern analysis").option("--architecture", "Check architectural consistency (not yet implemented)").option("--min-severity <level>", "Minimum severity: info|minor|major|critical. Default: info").option("--include <patterns>", "File patterns to include (comma-separated)").option("--exclude <patterns>", "File patterns to exclude (comma-separated)").option("-o, --output <format>", "Output format: console|json|markdown", "console").option("--output-file <path>", "Output file path (for json/markdown)").action(async (directory, options) => {
40
+ `
41
+ ).argument("<directory>", "Directory to analyze").option("--naming", "Check naming conventions and quality (default: true)").option("--no-naming", "Skip naming analysis").option("--patterns", "Check code pattern consistency (default: true)").option("--no-patterns", "Skip pattern analysis").option(
42
+ "--architecture",
43
+ "Check architectural consistency (not yet implemented)"
44
+ ).option(
45
+ "--min-severity <level>",
46
+ "Minimum severity: info|minor|major|critical. Default: info"
47
+ ).option("--include <patterns>", "File patterns to include (comma-separated)").option("--exclude <patterns>", "File patterns to exclude (comma-separated)").option(
48
+ "-o, --output <format>",
49
+ "Output format: console|json|markdown",
50
+ "console"
51
+ ).option("--output-file <path>", "Output file path (for json/markdown)").action(async (directory, options) => {
33
52
  console.log(chalk.blue("\u{1F50D} Analyzing consistency...\n"));
34
53
  const startTime = Date.now();
35
54
  const config = await loadConfig(directory);
@@ -95,7 +114,11 @@ function displayConsoleReport(report, elapsedTime) {
95
114
  console.log(`Analysis Time: ${chalk.gray(elapsedTime + "s")}
96
115
  `);
97
116
  if (summary.totalIssues === 0) {
98
- console.log(chalk.green("\u2728 No consistency patterns found! Your codebase is AI-friendly.\n"));
117
+ console.log(
118
+ chalk.green(
119
+ "\u2728 No consistency patterns found! Your codebase is AI-friendly.\n"
120
+ )
121
+ );
99
122
  return;
100
123
  }
101
124
  const namingResults = results.filter(