@aiready/pattern-detect 0.16.6 → 0.16.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-DR5W7S3Z.mjs +968 -0
- package/dist/chunk-PSVG2NLH.mjs +966 -0
- package/dist/cli.js +170 -90
- package/dist/cli.mjs +118 -85
- package/dist/index.d.mts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +54 -5
- package/dist/index.mjs +1 -1
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -312,14 +312,33 @@ function calculateSimilarity(a, b) {
|
|
|
312
312
|
const union = /* @__PURE__ */ new Set([...setA, ...setB]);
|
|
313
313
|
return intersection.size / union.size;
|
|
314
314
|
}
|
|
315
|
+
function calculateConfidence(similarity, tokens, lines) {
|
|
316
|
+
let confidence = similarity;
|
|
317
|
+
if (lines > 20) confidence += 0.05;
|
|
318
|
+
if (tokens > 200) confidence += 0.05;
|
|
319
|
+
if (lines < 5) confidence -= 0.1;
|
|
320
|
+
return Math.max(0, Math.min(1, confidence));
|
|
321
|
+
}
|
|
315
322
|
async function detectDuplicatePatterns(fileContents, options) {
|
|
316
|
-
const {
|
|
323
|
+
const {
|
|
324
|
+
minSimilarity,
|
|
325
|
+
minLines,
|
|
326
|
+
streamResults,
|
|
327
|
+
onProgress,
|
|
328
|
+
excludePatterns = [],
|
|
329
|
+
confidenceThreshold = 0,
|
|
330
|
+
ignoreWhitelist = []
|
|
331
|
+
} = options;
|
|
317
332
|
const allBlocks = [];
|
|
333
|
+
const excludeRegexes = excludePatterns.map((p) => new RegExp(p, "i"));
|
|
318
334
|
for (const { file, content } of fileContents) {
|
|
319
335
|
const blocks = extractBlocks(file, content);
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
336
|
+
for (const b of blocks) {
|
|
337
|
+
if (b.endLine - b.startLine + 1 < minLines) continue;
|
|
338
|
+
const isExcluded = excludeRegexes.some((regex) => regex.test(b.code));
|
|
339
|
+
if (isExcluded) continue;
|
|
340
|
+
allBlocks.push(b);
|
|
341
|
+
}
|
|
323
342
|
}
|
|
324
343
|
const duplicates = [];
|
|
325
344
|
const totalBlocks = allBlocks.length;
|
|
@@ -350,10 +369,20 @@ async function detectDuplicatePatterns(fileContents, options) {
|
|
|
350
369
|
comparisons++;
|
|
351
370
|
const b2 = allBlocks[j];
|
|
352
371
|
if (b1.file === b2.file) continue;
|
|
372
|
+
const isWhitelisted = ignoreWhitelist.some((pattern) => {
|
|
373
|
+
return b1.file.includes(pattern) && b2.file.includes(pattern) || pattern === `${b1.file}::${b2.file}` || pattern === `${b2.file}::${b1.file}`;
|
|
374
|
+
});
|
|
375
|
+
if (isWhitelisted) continue;
|
|
353
376
|
const isPython2 = b2.file.toLowerCase().endsWith(".py");
|
|
354
377
|
const norm2 = normalizeCode(b2.code, isPython2);
|
|
355
378
|
const sim = calculateSimilarity(norm1, norm2);
|
|
356
379
|
if (sim >= minSimilarity) {
|
|
380
|
+
const confidence = calculateConfidence(
|
|
381
|
+
sim,
|
|
382
|
+
b1.tokens,
|
|
383
|
+
b1.endLine - b1.startLine + 1
|
|
384
|
+
);
|
|
385
|
+
if (confidence < confidenceThreshold) continue;
|
|
357
386
|
const { severity, reason, suggestion, matchedRule } = calculateSeverity(
|
|
358
387
|
b1.file,
|
|
359
388
|
b2.file,
|
|
@@ -371,6 +400,7 @@ async function detectDuplicatePatterns(fileContents, options) {
|
|
|
371
400
|
code1: b1.code,
|
|
372
401
|
code2: b2.code,
|
|
373
402
|
similarity: sim,
|
|
403
|
+
confidence,
|
|
374
404
|
patternType: b1.patternType,
|
|
375
405
|
tokenCost: b1.tokens + b2.tokens,
|
|
376
406
|
severity,
|
|
@@ -381,7 +411,7 @@ async function detectDuplicatePatterns(fileContents, options) {
|
|
|
381
411
|
duplicates.push(dup);
|
|
382
412
|
if (streamResults)
|
|
383
413
|
console.log(
|
|
384
|
-
`[DUPLICATE] ${dup.file1}:${dup.line1} <-> ${dup.file2}:${dup.line2} (${Math.round(sim * 100)}%)`
|
|
414
|
+
`[DUPLICATE] ${dup.file1}:${dup.line1} <-> ${dup.file2}:${dup.line2} (${Math.round(sim * 100)}%, conf: ${Math.round(confidence * 100)}%)`
|
|
385
415
|
);
|
|
386
416
|
}
|
|
387
417
|
}
|
|
@@ -595,6 +625,17 @@ function logConfiguration(config, estimatedBlocks) {
|
|
|
595
625
|
console.log(` Min shared tokens: ${config.minSharedTokens}`);
|
|
596
626
|
console.log(` Severity filter: ${config.severity}`);
|
|
597
627
|
console.log(` Include tests: ${config.includeTests}`);
|
|
628
|
+
if (config.excludePatterns && config.excludePatterns.length > 0) {
|
|
629
|
+
console.log(` Exclude patterns: ${config.excludePatterns.length} active`);
|
|
630
|
+
}
|
|
631
|
+
if (config.confidenceThreshold && config.confidenceThreshold > 0) {
|
|
632
|
+
console.log(` Confidence threshold: ${config.confidenceThreshold}`);
|
|
633
|
+
}
|
|
634
|
+
if (config.ignoreWhitelist && config.ignoreWhitelist.length > 0) {
|
|
635
|
+
console.log(
|
|
636
|
+
` Ignore whitelist: ${config.ignoreWhitelist.length} entries`
|
|
637
|
+
);
|
|
638
|
+
}
|
|
598
639
|
console.log("");
|
|
599
640
|
}
|
|
600
641
|
async function analyzePatterns(options) {
|
|
@@ -613,6 +654,9 @@ async function analyzePatterns(options) {
|
|
|
613
654
|
createClusters = true,
|
|
614
655
|
minClusterTokenCost = 1e3,
|
|
615
656
|
minClusterFiles = 3,
|
|
657
|
+
excludePatterns = [],
|
|
658
|
+
confidenceThreshold = 0,
|
|
659
|
+
ignoreWhitelist = [],
|
|
616
660
|
...scanOptions
|
|
617
661
|
} = finalOptions;
|
|
618
662
|
const files = await (0, import_core4.scanFiles)(scanOptions);
|
|
@@ -639,6 +683,9 @@ async function analyzePatterns(options) {
|
|
|
639
683
|
minSharedTokens,
|
|
640
684
|
maxCandidatesPerBlock,
|
|
641
685
|
streamResults,
|
|
686
|
+
excludePatterns,
|
|
687
|
+
confidenceThreshold,
|
|
688
|
+
ignoreWhitelist,
|
|
642
689
|
onProgress: options.onProgress
|
|
643
690
|
});
|
|
644
691
|
for (const file of files) {
|
|
@@ -740,6 +787,8 @@ function generateSummary(results) {
|
|
|
740
787
|
}
|
|
741
788
|
],
|
|
742
789
|
similarity: similarityMatch ? parseInt(similarityMatch[1]) / 100 : 0,
|
|
790
|
+
confidence: similarityMatch ? parseInt(similarityMatch[1]) / 100 : 0,
|
|
791
|
+
// Fallback for summary
|
|
743
792
|
patternType: typeMatch?.[1] || "unknown",
|
|
744
793
|
tokenCost: tokenMatch ? parseInt(tokenMatch[1]) : 0
|
|
745
794
|
};
|
|
@@ -901,7 +950,7 @@ var PatternDetectProvider = {
|
|
|
901
950
|
// src/index.ts
|
|
902
951
|
import_core7.ToolRegistry.register(PatternDetectProvider);
|
|
903
952
|
|
|
904
|
-
// src/cli.ts
|
|
953
|
+
// src/cli-action.ts
|
|
905
954
|
var import_chalk = __toESM(require("chalk"));
|
|
906
955
|
var import_fs = require("fs");
|
|
907
956
|
var import_path2 = require("path");
|
|
@@ -1006,80 +1055,61 @@ function generateHTMLReport(results, summary) {
|
|
|
1006
1055
|
</html>`;
|
|
1007
1056
|
}
|
|
1008
1057
|
|
|
1009
|
-
// src/
|
|
1010
|
-
var
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
)
|
|
1039
|
-
"--exclude-test-fixtures",
|
|
1040
|
-
"Exclude test fixture duplication (beforeAll/afterAll)"
|
|
1041
|
-
).option("--exclude-templates", "Exclude template file duplication").option(
|
|
1042
|
-
"--include-tests",
|
|
1043
|
-
"Include test files in analysis (excluded by default)"
|
|
1044
|
-
).option(
|
|
1045
|
-
"--max-results <number>",
|
|
1046
|
-
"Maximum number of results to show in console output. Default: 10"
|
|
1047
|
-
).option("--no-group-by-file-pair", "Disable grouping duplicates by file pair").option("--no-create-clusters", "Disable creating refactor clusters").option(
|
|
1048
|
-
"--min-cluster-tokens <number>",
|
|
1049
|
-
"Minimum token cost for cluster reporting. Default: 1000"
|
|
1050
|
-
).option(
|
|
1051
|
-
"--min-cluster-files <number>",
|
|
1052
|
-
"Minimum files for cluster reporting. Default: 3"
|
|
1053
|
-
).option(
|
|
1054
|
-
"--show-raw-duplicates",
|
|
1055
|
-
"Show raw duplicates instead of grouped view"
|
|
1056
|
-
).option(
|
|
1057
|
-
"-o, --output <format>",
|
|
1058
|
-
"Output format: console, json, html",
|
|
1059
|
-
"console"
|
|
1060
|
-
).option("--output-file <path>", "Output file path (for json/html)").action(async (directory, options) => {
|
|
1058
|
+
// src/constants.ts
|
|
1059
|
+
var DEFAULT_MIN_SIMILARITY = 0.4;
|
|
1060
|
+
var DEFAULT_MIN_LINES = 5;
|
|
1061
|
+
var DEFAULT_BATCH_SIZE = 100;
|
|
1062
|
+
var DEFAULT_MIN_SHARED_TOKENS = 8;
|
|
1063
|
+
var DEFAULT_MAX_CANDIDATES_PER_BLOCK = 100;
|
|
1064
|
+
var DEFAULT_MAX_RESULTS = 10;
|
|
1065
|
+
var DEFAULT_MIN_CLUSTER_TOKEN_COST = 1e3;
|
|
1066
|
+
var DEFAULT_MIN_CLUSTER_FILES = 3;
|
|
1067
|
+
var COMMAND_NAME = "aiready-patterns";
|
|
1068
|
+
var COMMAND_VERSION = "0.1.0";
|
|
1069
|
+
var DEFAULT_OUTPUT_FORMAT = "console";
|
|
1070
|
+
var HELP_TEXT_AFTER = `
|
|
1071
|
+
CONFIGURATION:
|
|
1072
|
+
Supports config files: aiready.json, aiready.config.json, .aiready.json, .aireadyrc.json, aiready.config.js, .aireadyrc.js
|
|
1073
|
+
CLI options override config file settings
|
|
1074
|
+
|
|
1075
|
+
PARAMETER TUNING:
|
|
1076
|
+
If you get too few results: decrease --similarity, --min-lines, or --min-shared-tokens
|
|
1077
|
+
If analysis is too slow: increase --min-lines, --min-shared-tokens, or decrease --max-candidates
|
|
1078
|
+
If you get too many false positives: increase --similarity or --min-lines
|
|
1079
|
+
|
|
1080
|
+
EXAMPLES:
|
|
1081
|
+
aiready-patterns . # Basic analysis with smart defaults
|
|
1082
|
+
aiready-patterns . --similarity 0.3 --min-lines 3 # More sensitive detection
|
|
1083
|
+
aiready-patterns . --max-candidates 50 --no-approx # Slower but more thorough
|
|
1084
|
+
aiready-patterns . --output json > report.json # JSON export`;
|
|
1085
|
+
|
|
1086
|
+
// src/cli-action.ts
|
|
1087
|
+
async function patternActionHandler(directory, options) {
|
|
1061
1088
|
console.log(import_chalk.default.blue("\u{1F50D} Analyzing patterns...\n"));
|
|
1062
1089
|
const startTime = Date.now();
|
|
1063
1090
|
const config = await (0, import_core9.loadConfig)(directory);
|
|
1064
1091
|
const defaults = {
|
|
1065
|
-
minSimilarity:
|
|
1066
|
-
minLines:
|
|
1067
|
-
batchSize:
|
|
1092
|
+
minSimilarity: DEFAULT_MIN_SIMILARITY,
|
|
1093
|
+
minLines: DEFAULT_MIN_LINES,
|
|
1094
|
+
batchSize: DEFAULT_BATCH_SIZE,
|
|
1068
1095
|
approx: true,
|
|
1069
|
-
minSharedTokens:
|
|
1070
|
-
maxCandidatesPerBlock:
|
|
1096
|
+
minSharedTokens: DEFAULT_MIN_SHARED_TOKENS,
|
|
1097
|
+
maxCandidatesPerBlock: DEFAULT_MAX_CANDIDATES_PER_BLOCK,
|
|
1071
1098
|
streamResults: true,
|
|
1072
1099
|
include: void 0,
|
|
1073
1100
|
exclude: void 0,
|
|
1101
|
+
excludePatterns: void 0,
|
|
1102
|
+
confidenceThreshold: 0,
|
|
1103
|
+
ignoreWhitelist: void 0,
|
|
1074
1104
|
minSeverity: import_core9.Severity.Minor,
|
|
1075
1105
|
excludeTestFixtures: false,
|
|
1076
1106
|
excludeTemplates: false,
|
|
1077
1107
|
includeTests: false,
|
|
1078
|
-
maxResults:
|
|
1108
|
+
maxResults: DEFAULT_MAX_RESULTS,
|
|
1079
1109
|
groupByFilePair: true,
|
|
1080
1110
|
createClusters: true,
|
|
1081
|
-
minClusterTokenCost:
|
|
1082
|
-
minClusterFiles:
|
|
1111
|
+
minClusterTokenCost: DEFAULT_MIN_CLUSTER_TOKEN_COST,
|
|
1112
|
+
minClusterFiles: DEFAULT_MIN_CLUSTER_FILES,
|
|
1083
1113
|
showRawDuplicates: false
|
|
1084
1114
|
};
|
|
1085
1115
|
const mergedConfig = (0, import_core9.mergeConfigWithDefaults)(config, defaults);
|
|
@@ -1095,15 +1125,18 @@ program.name("aiready-patterns").description("Detect duplicate patterns in your
|
|
|
1095
1125
|
streamResults: options.streamResults !== false && mergedConfig.streamResults,
|
|
1096
1126
|
include: options.include?.split(",") || mergedConfig.include,
|
|
1097
1127
|
exclude: options.exclude?.split(",") || mergedConfig.exclude,
|
|
1128
|
+
excludePatterns: options.excludePatterns?.split(",") || mergedConfig.excludePatterns,
|
|
1129
|
+
confidenceThreshold: options.confidenceThreshold ? parseFloat(options.confidenceThreshold) : mergedConfig.confidenceThreshold,
|
|
1130
|
+
ignoreWhitelist: options.ignoreWhitelist?.split(",") || mergedConfig.ignoreWhitelist,
|
|
1098
1131
|
minSeverity: options.minSeverity || mergedConfig.minSeverity,
|
|
1099
1132
|
excludeTestFixtures: options.excludeTestFixtures || mergedConfig.excludeTestFixtures,
|
|
1100
1133
|
excludeTemplates: options.excludeTemplates || mergedConfig.excludeTemplates,
|
|
1101
1134
|
includeTests: options.includeTests || mergedConfig.includeTests,
|
|
1102
1135
|
maxResults: options.maxResults ? parseInt(options.maxResults) : mergedConfig.maxResults,
|
|
1103
|
-
groupByFilePair: options.
|
|
1104
|
-
createClusters: options.
|
|
1105
|
-
minClusterTokenCost: options.
|
|
1106
|
-
minClusterFiles: options.
|
|
1136
|
+
groupByFilePair: options.groupByFilePair !== false && mergedConfig.groupByFilePair,
|
|
1137
|
+
createClusters: options.createClusters !== false && mergedConfig.createClusters,
|
|
1138
|
+
minClusterTokenCost: options.minClusterTokens ? parseInt(options.minClusterTokens) : mergedConfig.minClusterTokenCost,
|
|
1139
|
+
minClusterFiles: options.minClusterFiles ? parseInt(options.minClusterFiles) : mergedConfig.minClusterFiles,
|
|
1107
1140
|
showRawDuplicates: options.showRawDuplicates || mergedConfig.showRawDuplicates
|
|
1108
1141
|
};
|
|
1109
1142
|
if (finalOptions.includeTests && finalOptions.exclude) {
|
|
@@ -1189,9 +1222,7 @@ program.name("aiready-patterns").description("Detect duplicate patterns in your
|
|
|
1189
1222
|
console.log(import_chalk.default.cyan(divider));
|
|
1190
1223
|
console.log(import_chalk.default.bold.white(" PATTERN ANALYSIS SUMMARY"));
|
|
1191
1224
|
console.log(import_chalk.default.cyan(divider) + "\n");
|
|
1192
|
-
console.log(
|
|
1193
|
-
import_chalk.default.white(`\u{1F4C1} Files analyzed: ${import_chalk.default.bold(results.length)}`)
|
|
1194
|
-
);
|
|
1225
|
+
console.log(import_chalk.default.white(`\u{1F4C1} Files analyzed: ${import_chalk.default.bold(results.length)}`));
|
|
1195
1226
|
console.log(
|
|
1196
1227
|
import_chalk.default.yellow(
|
|
1197
1228
|
`\u26A0 AI confusion patterns detected: ${import_chalk.default.bold(totalIssues)}`
|
|
@@ -1202,9 +1233,7 @@ program.name("aiready-patterns").description("Detect duplicate patterns in your
|
|
|
1202
1233
|
`\u{1F4B0} Token cost (wasted): ${import_chalk.default.bold(summary.totalTokenCost.toLocaleString())}`
|
|
1203
1234
|
)
|
|
1204
1235
|
);
|
|
1205
|
-
console.log(
|
|
1206
|
-
import_chalk.default.gray(`\u23F1 Analysis time: ${import_chalk.default.bold(elapsedTime + "s")}`)
|
|
1207
|
-
);
|
|
1236
|
+
console.log(import_chalk.default.gray(`\u23F1 Analysis time: ${import_chalk.default.bold(elapsedTime + "s")}`));
|
|
1208
1237
|
const sortedTypes = Object.entries(summary.patternsByType).filter(([, count]) => count > 0).sort(([, a], [, b]) => b - a);
|
|
1209
1238
|
if (sortedTypes.length > 0) {
|
|
1210
1239
|
console.log(import_chalk.default.cyan("\n" + divider));
|
|
@@ -1270,9 +1299,7 @@ program.name("aiready-patterns").description("Detect duplicate patterns in your
|
|
|
1270
1299
|
console.log(import_chalk.default.cyan(divider) + "\n");
|
|
1271
1300
|
clusters.sort((a, b) => b.totalTokenCost - a.totalTokenCost).forEach((cluster, idx) => {
|
|
1272
1301
|
const severityBadge = (0, import_core9.getSeverityBadge)(cluster.severity);
|
|
1273
|
-
console.log(
|
|
1274
|
-
`${idx + 1}. ${severityBadge} ${import_chalk.default.bold(cluster.name)}`
|
|
1275
|
-
);
|
|
1302
|
+
console.log(`${idx + 1}. ${severityBadge} ${import_chalk.default.bold(cluster.name)}`);
|
|
1276
1303
|
console.log(
|
|
1277
1304
|
` Total tokens: ${import_chalk.default.bold(cluster.totalTokenCost.toLocaleString())} | Avg similarity: ${import_chalk.default.bold(Math.round(cluster.averageSimilarity * 100) + "%")} | Duplicates: ${import_chalk.default.bold(cluster.duplicateCount)}`
|
|
1278
1305
|
);
|
|
@@ -1354,10 +1381,8 @@ program.name("aiready-patterns").description("Detect duplicate patterns in your
|
|
|
1354
1381
|
import_chalk.default.red("\u25CF ") + import_chalk.default.white(`${issue.file}:${issue.location.line}`)
|
|
1355
1382
|
);
|
|
1356
1383
|
console.log(` ${import_chalk.default.dim(issue.message)}`);
|
|
1357
|
-
console.log(
|
|
1358
|
-
|
|
1359
|
-
`
|
|
1360
|
-
);
|
|
1384
|
+
console.log(` ${import_chalk.default.green("\u2192")} ${import_chalk.default.italic(issue.suggestion)}
|
|
1385
|
+
`);
|
|
1361
1386
|
});
|
|
1362
1387
|
}
|
|
1363
1388
|
if (totalIssues === 0) {
|
|
@@ -1367,9 +1392,7 @@ program.name("aiready-patterns").description("Detect duplicate patterns in your
|
|
|
1367
1392
|
"\u{1F4A1} If you expected to find duplicates, try adjusting parameters:"
|
|
1368
1393
|
)
|
|
1369
1394
|
);
|
|
1370
|
-
console.log(
|
|
1371
|
-
import_chalk.default.dim(" \u2022 Lower similarity threshold: --similarity 0.3")
|
|
1372
|
-
);
|
|
1395
|
+
console.log(import_chalk.default.dim(" \u2022 Lower similarity threshold: --similarity 0.3"));
|
|
1373
1396
|
console.log(import_chalk.default.dim(" \u2022 Reduce minimum lines: --min-lines 3"));
|
|
1374
1397
|
console.log(import_chalk.default.dim(" \u2022 Include test files: --include-tests"));
|
|
1375
1398
|
console.log(
|
|
@@ -1381,9 +1404,7 @@ program.name("aiready-patterns").description("Detect duplicate patterns in your
|
|
|
1381
1404
|
console.log(
|
|
1382
1405
|
import_chalk.default.yellow("\n\u{1F4A1} Few results found. To find more duplicates, try:")
|
|
1383
1406
|
);
|
|
1384
|
-
console.log(
|
|
1385
|
-
import_chalk.default.dim(" \u2022 Lower similarity threshold: --similarity 0.3")
|
|
1386
|
-
);
|
|
1407
|
+
console.log(import_chalk.default.dim(" \u2022 Lower similarity threshold: --similarity 0.3"));
|
|
1387
1408
|
console.log(import_chalk.default.dim(" \u2022 Reduce minimum lines: --min-lines 3"));
|
|
1388
1409
|
console.log(import_chalk.default.dim(" \u2022 Include test files: --include-tests"));
|
|
1389
1410
|
console.log(
|
|
@@ -1410,5 +1431,64 @@ program.name("aiready-patterns").description("Detect duplicate patterns in your
|
|
|
1410
1431
|
"\u{1F41B} Found a bug? Report it: https://github.com/caopengau/aiready-pattern-detect/issues\n"
|
|
1411
1432
|
)
|
|
1412
1433
|
);
|
|
1413
|
-
}
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1436
|
+
// src/cli.ts
|
|
1437
|
+
var program = new import_commander.Command();
|
|
1438
|
+
program.name(COMMAND_NAME).description("Detect duplicate patterns in your codebase").version(COMMAND_VERSION).addHelpText("after", HELP_TEXT_AFTER).argument("<directory>", "Directory to analyze").option(
|
|
1439
|
+
"-s, --similarity <number>",
|
|
1440
|
+
`Minimum similarity score (0-1). Default: ${DEFAULT_MIN_SIMILARITY}`
|
|
1441
|
+
).option(
|
|
1442
|
+
"-l, --min-lines <number>",
|
|
1443
|
+
`Minimum lines to consider. Default: ${DEFAULT_MIN_LINES}`
|
|
1444
|
+
).option(
|
|
1445
|
+
"--batch-size <number>",
|
|
1446
|
+
`Batch size for comparisons. Default: ${DEFAULT_BATCH_SIZE}`
|
|
1447
|
+
).option(
|
|
1448
|
+
"--no-approx",
|
|
1449
|
+
"Disable approximate candidate selection. Slower but more thorough on small repos"
|
|
1450
|
+
).option(
|
|
1451
|
+
"--min-shared-tokens <number>",
|
|
1452
|
+
`Minimum shared tokens to consider a candidate. Default: ${DEFAULT_MIN_SHARED_TOKENS}`
|
|
1453
|
+
).option(
|
|
1454
|
+
"--max-candidates <number>",
|
|
1455
|
+
`Maximum candidates per block. Default: ${DEFAULT_MAX_CANDIDATES_PER_BLOCK}`
|
|
1456
|
+
).option(
|
|
1457
|
+
"--no-stream-results",
|
|
1458
|
+
"Disable incremental output (default: enabled)"
|
|
1459
|
+
).option("--include <patterns>", "File patterns to include (comma-separated)").option("--exclude <patterns>", "File patterns to exclude (comma-separated)").option(
|
|
1460
|
+
"--exclude-patterns <regexes>",
|
|
1461
|
+
"Regex patterns to exclude specific code content (comma-separated)"
|
|
1462
|
+
).option(
|
|
1463
|
+
"--confidence-threshold <number>",
|
|
1464
|
+
"Minimum confidence score (0-1). Default: 0"
|
|
1465
|
+
).option(
|
|
1466
|
+
"--ignore-whitelist <patterns>",
|
|
1467
|
+
"List of file pairs or patterns to ignore (comma-separated)"
|
|
1468
|
+
).option(
|
|
1469
|
+
"--min-severity <level>",
|
|
1470
|
+
"Minimum severity to show: critical|major|minor|info. Default: minor"
|
|
1471
|
+
).option(
|
|
1472
|
+
"--exclude-test-fixtures",
|
|
1473
|
+
"Exclude test fixture duplication (beforeAll/afterAll)"
|
|
1474
|
+
).option("--exclude-templates", "Exclude template file duplication").option(
|
|
1475
|
+
"--include-tests",
|
|
1476
|
+
"Include test files in analysis (excluded by default)"
|
|
1477
|
+
).option(
|
|
1478
|
+
"--max-results <number>",
|
|
1479
|
+
`Maximum number of results to show in console output. Default: ${DEFAULT_MAX_RESULTS}`
|
|
1480
|
+
).option("--no-group-by-file-pair", "Disable grouping duplicates by file pair").option("--no-create-clusters", "Disable creating refactor clusters").option(
|
|
1481
|
+
"--min-cluster-tokens <number>",
|
|
1482
|
+
`Minimum token cost for cluster reporting. Default: ${DEFAULT_MIN_CLUSTER_TOKEN_COST}`
|
|
1483
|
+
).option(
|
|
1484
|
+
"--min-cluster-files <number>",
|
|
1485
|
+
`Minimum files for cluster reporting. Default: ${DEFAULT_MIN_CLUSTER_FILES}`
|
|
1486
|
+
).option(
|
|
1487
|
+
"--show-raw-duplicates",
|
|
1488
|
+
"Show raw duplicates instead of grouped view"
|
|
1489
|
+
).option(
|
|
1490
|
+
"-o, --output <format>",
|
|
1491
|
+
"Output format: console, json, html",
|
|
1492
|
+
DEFAULT_OUTPUT_FORMAT
|
|
1493
|
+
).option("--output-file <path>", "Output file path (for json/html)").action(patternActionHandler);
|
|
1414
1494
|
program.parse();
|