@aiready/pattern-detect 0.12.5 → 0.14.0
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-AJZUNNFH.mjs +817 -0
- package/dist/chunk-KDWGWBP5.mjs +832 -0
- package/dist/chunk-MH6LBXZF.mjs +816 -0
- package/dist/cli.js +158 -18
- package/dist/cli.mjs +1 -1
- package/dist/index.d.mts +7 -2
- package/dist/index.d.ts +7 -2
- package/dist/index.js +51 -10
- package/dist/index.mjs +3 -1
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -27,7 +27,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
27
27
|
var import_commander = require("commander");
|
|
28
28
|
|
|
29
29
|
// src/index.ts
|
|
30
|
-
var
|
|
30
|
+
var import_core6 = require("@aiready/core");
|
|
31
31
|
|
|
32
32
|
// src/detector.ts
|
|
33
33
|
var import_core2 = require("@aiready/core");
|
|
@@ -438,8 +438,148 @@ function filterClustersByImpact(clusters, minTokenCost = 1e3, minFiles = 3) {
|
|
|
438
438
|
|
|
439
439
|
// src/scoring.ts
|
|
440
440
|
var import_core4 = require("@aiready/core");
|
|
441
|
+
function calculatePatternScore(duplicates, totalFilesAnalyzed, costConfig) {
|
|
442
|
+
const totalDuplicates = duplicates.length;
|
|
443
|
+
const totalTokenCost = duplicates.reduce((sum, d) => sum + d.tokenCost, 0);
|
|
444
|
+
const highImpactDuplicates = duplicates.filter(
|
|
445
|
+
(d) => d.tokenCost > 1e3 || d.similarity > 0.7
|
|
446
|
+
).length;
|
|
447
|
+
if (totalFilesAnalyzed === 0) {
|
|
448
|
+
return {
|
|
449
|
+
toolName: import_core4.ToolName.PatternDetect,
|
|
450
|
+
score: 100,
|
|
451
|
+
rawMetrics: {
|
|
452
|
+
totalDuplicates: 0,
|
|
453
|
+
totalTokenCost: 0,
|
|
454
|
+
highImpactDuplicates: 0,
|
|
455
|
+
totalFilesAnalyzed: 0
|
|
456
|
+
},
|
|
457
|
+
factors: [],
|
|
458
|
+
recommendations: []
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
const duplicatesPerFile = totalDuplicates / totalFilesAnalyzed * 100;
|
|
462
|
+
const tokenWastePerFile = totalTokenCost / totalFilesAnalyzed;
|
|
463
|
+
const duplicatesPenalty = Math.min(60, duplicatesPerFile * 0.6);
|
|
464
|
+
const tokenPenalty = Math.min(40, tokenWastePerFile / 125);
|
|
465
|
+
const highImpactPenalty = highImpactDuplicates > 0 ? Math.min(15, highImpactDuplicates * 2 - 5) : -5;
|
|
466
|
+
const score = 100 - duplicatesPenalty - tokenPenalty - highImpactPenalty;
|
|
467
|
+
const finalScore = Math.max(0, Math.min(100, Math.round(score)));
|
|
468
|
+
const factors = [
|
|
469
|
+
{
|
|
470
|
+
name: "Duplication Density",
|
|
471
|
+
impact: -Math.round(duplicatesPenalty),
|
|
472
|
+
description: `${duplicatesPerFile.toFixed(1)} duplicates per 100 files`
|
|
473
|
+
},
|
|
474
|
+
{
|
|
475
|
+
name: "Token Waste",
|
|
476
|
+
impact: -Math.round(tokenPenalty),
|
|
477
|
+
description: `${Math.round(tokenWastePerFile)} tokens wasted per file`
|
|
478
|
+
}
|
|
479
|
+
];
|
|
480
|
+
if (highImpactDuplicates > 0) {
|
|
481
|
+
factors.push({
|
|
482
|
+
name: "High-Impact Patterns",
|
|
483
|
+
impact: -Math.round(highImpactPenalty),
|
|
484
|
+
description: `${highImpactDuplicates} high-impact duplicates (>1000 tokens or >70% similar)`
|
|
485
|
+
});
|
|
486
|
+
} else {
|
|
487
|
+
factors.push({
|
|
488
|
+
name: "No High-Impact Patterns",
|
|
489
|
+
impact: 5,
|
|
490
|
+
description: "No severe duplicates detected"
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
const recommendations = [];
|
|
494
|
+
if (highImpactDuplicates > 0) {
|
|
495
|
+
const estimatedImpact = Math.min(15, highImpactDuplicates * 3);
|
|
496
|
+
recommendations.push({
|
|
497
|
+
action: `Deduplicate ${highImpactDuplicates} high-impact pattern${highImpactDuplicates > 1 ? "s" : ""}`,
|
|
498
|
+
estimatedImpact,
|
|
499
|
+
priority: "high"
|
|
500
|
+
});
|
|
501
|
+
}
|
|
502
|
+
if (totalDuplicates > 10 && duplicatesPerFile > 20) {
|
|
503
|
+
const estimatedImpact = Math.min(10, Math.round(duplicatesPenalty * 0.3));
|
|
504
|
+
recommendations.push({
|
|
505
|
+
action: "Extract common patterns into shared utilities",
|
|
506
|
+
estimatedImpact,
|
|
507
|
+
priority: "medium"
|
|
508
|
+
});
|
|
509
|
+
}
|
|
510
|
+
if (tokenWastePerFile > 2e3) {
|
|
511
|
+
const estimatedImpact = Math.min(8, Math.round(tokenPenalty * 0.4));
|
|
512
|
+
recommendations.push({
|
|
513
|
+
action: "Consolidate duplicated logic to reduce AI context waste",
|
|
514
|
+
estimatedImpact,
|
|
515
|
+
priority: totalTokenCost > 1e4 ? "high" : "medium"
|
|
516
|
+
});
|
|
517
|
+
}
|
|
518
|
+
const cfg = { ...import_core4.DEFAULT_COST_CONFIG, ...costConfig };
|
|
519
|
+
const estimatedMonthlyCost = (0, import_core4.calculateMonthlyCost)(totalTokenCost, cfg);
|
|
520
|
+
const issues = duplicates.map((d) => ({
|
|
521
|
+
severity: d.severity === "critical" ? "critical" : d.severity === "major" ? "major" : "minor"
|
|
522
|
+
}));
|
|
523
|
+
const productivityImpact = (0, import_core4.calculateProductivityImpact)(issues);
|
|
524
|
+
return {
|
|
525
|
+
toolName: "pattern-detect",
|
|
526
|
+
score: finalScore,
|
|
527
|
+
rawMetrics: {
|
|
528
|
+
totalDuplicates,
|
|
529
|
+
totalTokenCost,
|
|
530
|
+
highImpactDuplicates,
|
|
531
|
+
totalFilesAnalyzed,
|
|
532
|
+
duplicatesPerFile: Math.round(duplicatesPerFile * 10) / 10,
|
|
533
|
+
tokenWastePerFile: Math.round(tokenWastePerFile),
|
|
534
|
+
// Business value metrics
|
|
535
|
+
estimatedMonthlyCost,
|
|
536
|
+
estimatedDeveloperHours: productivityImpact.totalHours
|
|
537
|
+
},
|
|
538
|
+
factors,
|
|
539
|
+
recommendations
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
// src/provider.ts
|
|
544
|
+
var import_core5 = require("@aiready/core");
|
|
545
|
+
var PatternDetectProvider = {
|
|
546
|
+
id: import_core5.ToolName.PatternDetect,
|
|
547
|
+
alias: ["patterns", "duplicates", "duplication"],
|
|
548
|
+
async analyze(options) {
|
|
549
|
+
const results = await analyzePatterns(options);
|
|
550
|
+
return import_core5.SpokeOutputSchema.parse({
|
|
551
|
+
results: results.results,
|
|
552
|
+
summary: {
|
|
553
|
+
totalFiles: results.files.length,
|
|
554
|
+
totalIssues: results.results.reduce(
|
|
555
|
+
(sum, r) => sum + r.issues.length,
|
|
556
|
+
0
|
|
557
|
+
),
|
|
558
|
+
duplicates: results.duplicates,
|
|
559
|
+
groups: results.groups,
|
|
560
|
+
clusters: results.clusters
|
|
561
|
+
},
|
|
562
|
+
metadata: {
|
|
563
|
+
toolName: import_core5.ToolName.PatternDetect,
|
|
564
|
+
version: "0.12.5",
|
|
565
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
566
|
+
}
|
|
567
|
+
});
|
|
568
|
+
},
|
|
569
|
+
score(output, options) {
|
|
570
|
+
const duplicates = output.summary.duplicates || [];
|
|
571
|
+
const totalFiles = output.summary.totalFiles || output.results.length;
|
|
572
|
+
return calculatePatternScore(
|
|
573
|
+
duplicates,
|
|
574
|
+
totalFiles,
|
|
575
|
+
options.costConfig
|
|
576
|
+
);
|
|
577
|
+
},
|
|
578
|
+
defaultWeight: 22
|
|
579
|
+
};
|
|
441
580
|
|
|
442
581
|
// src/index.ts
|
|
582
|
+
import_core6.ToolRegistry.register(PatternDetectProvider);
|
|
443
583
|
function getRefactoringSuggestion(patternType, similarity) {
|
|
444
584
|
const baseMessages = {
|
|
445
585
|
"api-handler": "Extract common middleware or create a base handler class",
|
|
@@ -555,7 +695,7 @@ async function analyzePatterns(options) {
|
|
|
555
695
|
const batchContents = await Promise.all(
|
|
556
696
|
batch.map(async (file) => ({
|
|
557
697
|
file,
|
|
558
|
-
content: await (0,
|
|
698
|
+
content: await (0, import_core6.readFileContent)(file)
|
|
559
699
|
}))
|
|
560
700
|
);
|
|
561
701
|
fileContents.push(...batchContents);
|
|
@@ -576,9 +716,9 @@ async function analyzePatterns(options) {
|
|
|
576
716
|
);
|
|
577
717
|
const issues = fileDuplicates.map((dup) => {
|
|
578
718
|
const otherFile = dup.file1 === file ? dup.file2 : dup.file1;
|
|
579
|
-
const severity2 = dup.similarity > 0.95 ?
|
|
719
|
+
const severity2 = dup.similarity > 0.95 ? import_core6.Severity.Critical : dup.similarity > 0.9 ? import_core6.Severity.Major : import_core6.Severity.Minor;
|
|
580
720
|
return {
|
|
581
|
-
type:
|
|
721
|
+
type: import_core6.IssueType.DuplicatePattern,
|
|
582
722
|
severity: severity2,
|
|
583
723
|
message: `${dup.patternType} pattern ${Math.round(dup.similarity * 100)}% similar to ${otherFile} (${dup.tokenCost} tokens wasted)`,
|
|
584
724
|
location: {
|
|
@@ -591,11 +731,11 @@ async function analyzePatterns(options) {
|
|
|
591
731
|
let filteredIssues = issues;
|
|
592
732
|
if (severity !== "all") {
|
|
593
733
|
const severityMap = {
|
|
594
|
-
critical: [
|
|
595
|
-
high: [
|
|
596
|
-
medium: [
|
|
734
|
+
critical: [import_core6.Severity.Critical],
|
|
735
|
+
high: [import_core6.Severity.Critical, import_core6.Severity.Major],
|
|
736
|
+
medium: [import_core6.Severity.Critical, import_core6.Severity.Major, import_core6.Severity.Minor]
|
|
597
737
|
};
|
|
598
|
-
const allowedSeverities = severityMap[severity] || [
|
|
738
|
+
const allowedSeverities = severityMap[severity] || [import_core6.Severity.Critical, import_core6.Severity.Major, import_core6.Severity.Minor];
|
|
599
739
|
filteredIssues = issues.filter(
|
|
600
740
|
(issue) => allowedSeverities.includes(issue.severity)
|
|
601
741
|
);
|
|
@@ -688,7 +828,7 @@ function generateSummary(results) {
|
|
|
688
828
|
var import_chalk = __toESM(require("chalk"));
|
|
689
829
|
var import_fs = require("fs");
|
|
690
830
|
var import_path2 = require("path");
|
|
691
|
-
var
|
|
831
|
+
var import_core7 = require("@aiready/core");
|
|
692
832
|
var program = new import_commander.Command();
|
|
693
833
|
program.name("aiready-patterns").description("Detect duplicate patterns in your codebase").version("0.1.0").addHelpText(
|
|
694
834
|
"after",
|
|
@@ -742,7 +882,7 @@ program.name("aiready-patterns").description("Detect duplicate patterns in your
|
|
|
742
882
|
).option("--output-file <path>", "Output file path (for json/html)").action(async (directory, options) => {
|
|
743
883
|
console.log(import_chalk.default.blue("\u{1F50D} Analyzing patterns...\n"));
|
|
744
884
|
const startTime = Date.now();
|
|
745
|
-
const config = await (0,
|
|
885
|
+
const config = await (0, import_core7.loadConfig)(directory);
|
|
746
886
|
const defaults = {
|
|
747
887
|
minSimilarity: 0.4,
|
|
748
888
|
minLines: 5,
|
|
@@ -753,7 +893,7 @@ program.name("aiready-patterns").description("Detect duplicate patterns in your
|
|
|
753
893
|
streamResults: true,
|
|
754
894
|
include: void 0,
|
|
755
895
|
exclude: void 0,
|
|
756
|
-
minSeverity:
|
|
896
|
+
minSeverity: import_core7.Severity.Minor,
|
|
757
897
|
excludeTestFixtures: false,
|
|
758
898
|
excludeTemplates: false,
|
|
759
899
|
includeTests: false,
|
|
@@ -764,7 +904,7 @@ program.name("aiready-patterns").description("Detect duplicate patterns in your
|
|
|
764
904
|
minClusterFiles: 3,
|
|
765
905
|
showRawDuplicates: false
|
|
766
906
|
};
|
|
767
|
-
const mergedConfig = (0,
|
|
907
|
+
const mergedConfig = (0, import_core7.mergeConfigWithDefaults)(config, defaults);
|
|
768
908
|
const finalOptions = {
|
|
769
909
|
rootDir: directory,
|
|
770
910
|
minSimilarity: options.similarity ? parseFloat(options.similarity) : mergedConfig.minSimilarity,
|
|
@@ -836,7 +976,7 @@ program.name("aiready-patterns").description("Detect duplicate patterns in your
|
|
|
836
976
|
clusters: clusters || [],
|
|
837
977
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
838
978
|
};
|
|
839
|
-
const outputPath = (0,
|
|
979
|
+
const outputPath = (0, import_core7.resolveOutputPath)(
|
|
840
980
|
options.outputFile,
|
|
841
981
|
`pattern-report-${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}.json`,
|
|
842
982
|
directory
|
|
@@ -852,7 +992,7 @@ program.name("aiready-patterns").description("Detect duplicate patterns in your
|
|
|
852
992
|
}
|
|
853
993
|
if (options.output === "html") {
|
|
854
994
|
const html = generateHTMLReport(summary, results);
|
|
855
|
-
const outputPath = (0,
|
|
995
|
+
const outputPath = (0, import_core7.resolveOutputPath)(
|
|
856
996
|
options.outputFile,
|
|
857
997
|
`pattern-report-${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}.html`,
|
|
858
998
|
directory
|
|
@@ -1182,10 +1322,10 @@ function generateHTMLReport(summary, results) {
|
|
|
1182
1322
|
}
|
|
1183
1323
|
program.parse();
|
|
1184
1324
|
function getSeverityValue(s) {
|
|
1185
|
-
if (s ===
|
|
1186
|
-
if (s ===
|
|
1187
|
-
if (s ===
|
|
1188
|
-
if (s ===
|
|
1325
|
+
if (s === import_core7.Severity.Critical || s === "critical") return 4;
|
|
1326
|
+
if (s === import_core7.Severity.Major || s === "major") return 3;
|
|
1327
|
+
if (s === import_core7.Severity.Minor || s === "minor") return 2;
|
|
1328
|
+
if (s === import_core7.Severity.Info || s === "info") return 1;
|
|
1189
1329
|
return 0;
|
|
1190
1330
|
}
|
|
1191
1331
|
function getSeverityBadge(severity) {
|
package/dist/cli.mjs
CHANGED
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Severity, CostConfig, ToolScoringOutput, ScanOptions, AnalysisResult } from '@aiready/core';
|
|
1
|
+
import { Severity, CostConfig, ToolScoringOutput, ToolProvider, ScanOptions, AnalysisResult } from '@aiready/core';
|
|
2
2
|
export { Severity } from '@aiready/core';
|
|
3
3
|
|
|
4
4
|
type PatternType = 'api-handler' | 'validator' | 'utility' | 'class-method' | 'component' | 'function' | 'unknown';
|
|
@@ -83,6 +83,11 @@ interface RefactorCluster {
|
|
|
83
83
|
*/
|
|
84
84
|
declare function calculatePatternScore(duplicates: DuplicatePattern[], totalFilesAnalyzed: number, costConfig?: Partial<CostConfig>): ToolScoringOutput;
|
|
85
85
|
|
|
86
|
+
/**
|
|
87
|
+
* Pattern Detection Tool Provider
|
|
88
|
+
*/
|
|
89
|
+
declare const PatternDetectProvider: ToolProvider;
|
|
90
|
+
|
|
86
91
|
/**
|
|
87
92
|
* Calculate severity based on context rules and code characteristics
|
|
88
93
|
*/
|
|
@@ -151,4 +156,4 @@ declare function analyzePatterns(options: PatternDetectOptions): Promise<{
|
|
|
151
156
|
*/
|
|
152
157
|
declare function generateSummary(results: AnalysisResult[]): PatternSummary;
|
|
153
158
|
|
|
154
|
-
export { type DuplicateGroup, type DuplicatePattern, type PatternDetectOptions, type PatternSummary, type PatternType, type RefactorCluster, analyzePatterns, calculatePatternScore, calculateSeverity, detectDuplicatePatterns, filterBySeverity, generateSummary, getSeverityLabel, getSmartDefaults };
|
|
159
|
+
export { type DuplicateGroup, type DuplicatePattern, type PatternDetectOptions, PatternDetectProvider, type PatternSummary, type PatternType, type RefactorCluster, analyzePatterns, calculatePatternScore, calculateSeverity, detectDuplicatePatterns, filterBySeverity, generateSummary, getSeverityLabel, getSmartDefaults };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Severity, CostConfig, ToolScoringOutput, ScanOptions, AnalysisResult } from '@aiready/core';
|
|
1
|
+
import { Severity, CostConfig, ToolScoringOutput, ToolProvider, ScanOptions, AnalysisResult } from '@aiready/core';
|
|
2
2
|
export { Severity } from '@aiready/core';
|
|
3
3
|
|
|
4
4
|
type PatternType = 'api-handler' | 'validator' | 'utility' | 'class-method' | 'component' | 'function' | 'unknown';
|
|
@@ -83,6 +83,11 @@ interface RefactorCluster {
|
|
|
83
83
|
*/
|
|
84
84
|
declare function calculatePatternScore(duplicates: DuplicatePattern[], totalFilesAnalyzed: number, costConfig?: Partial<CostConfig>): ToolScoringOutput;
|
|
85
85
|
|
|
86
|
+
/**
|
|
87
|
+
* Pattern Detection Tool Provider
|
|
88
|
+
*/
|
|
89
|
+
declare const PatternDetectProvider: ToolProvider;
|
|
90
|
+
|
|
86
91
|
/**
|
|
87
92
|
* Calculate severity based on context rules and code characteristics
|
|
88
93
|
*/
|
|
@@ -151,4 +156,4 @@ declare function analyzePatterns(options: PatternDetectOptions): Promise<{
|
|
|
151
156
|
*/
|
|
152
157
|
declare function generateSummary(results: AnalysisResult[]): PatternSummary;
|
|
153
158
|
|
|
154
|
-
export { type DuplicateGroup, type DuplicatePattern, type PatternDetectOptions, type PatternSummary, type PatternType, type RefactorCluster, analyzePatterns, calculatePatternScore, calculateSeverity, detectDuplicatePatterns, filterBySeverity, generateSummary, getSeverityLabel, getSmartDefaults };
|
|
159
|
+
export { type DuplicateGroup, type DuplicatePattern, type PatternDetectOptions, PatternDetectProvider, type PatternSummary, type PatternType, type RefactorCluster, analyzePatterns, calculatePatternScore, calculateSeverity, detectDuplicatePatterns, filterBySeverity, generateSummary, getSeverityLabel, getSmartDefaults };
|
package/dist/index.js
CHANGED
|
@@ -30,7 +30,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
-
|
|
33
|
+
PatternDetectProvider: () => PatternDetectProvider,
|
|
34
|
+
Severity: () => import_core6.Severity,
|
|
34
35
|
analyzePatterns: () => analyzePatterns,
|
|
35
36
|
calculatePatternScore: () => calculatePatternScore,
|
|
36
37
|
calculateSeverity: () => calculateSeverity,
|
|
@@ -41,7 +42,7 @@ __export(index_exports, {
|
|
|
41
42
|
getSmartDefaults: () => getSmartDefaults
|
|
42
43
|
});
|
|
43
44
|
module.exports = __toCommonJS(index_exports);
|
|
44
|
-
var
|
|
45
|
+
var import_core6 = require("@aiready/core");
|
|
45
46
|
|
|
46
47
|
// src/detector.ts
|
|
47
48
|
var import_core2 = require("@aiready/core");
|
|
@@ -469,7 +470,7 @@ function calculatePatternScore(duplicates, totalFilesAnalyzed, costConfig) {
|
|
|
469
470
|
).length;
|
|
470
471
|
if (totalFilesAnalyzed === 0) {
|
|
471
472
|
return {
|
|
472
|
-
toolName:
|
|
473
|
+
toolName: import_core4.ToolName.PatternDetect,
|
|
473
474
|
score: 100,
|
|
474
475
|
rawMetrics: {
|
|
475
476
|
totalDuplicates: 0,
|
|
@@ -563,7 +564,46 @@ function calculatePatternScore(duplicates, totalFilesAnalyzed, costConfig) {
|
|
|
563
564
|
};
|
|
564
565
|
}
|
|
565
566
|
|
|
567
|
+
// src/provider.ts
|
|
568
|
+
var import_core5 = require("@aiready/core");
|
|
569
|
+
var PatternDetectProvider = {
|
|
570
|
+
id: import_core5.ToolName.PatternDetect,
|
|
571
|
+
alias: ["patterns", "duplicates", "duplication"],
|
|
572
|
+
async analyze(options) {
|
|
573
|
+
const results = await analyzePatterns(options);
|
|
574
|
+
return import_core5.SpokeOutputSchema.parse({
|
|
575
|
+
results: results.results,
|
|
576
|
+
summary: {
|
|
577
|
+
totalFiles: results.files.length,
|
|
578
|
+
totalIssues: results.results.reduce(
|
|
579
|
+
(sum, r) => sum + r.issues.length,
|
|
580
|
+
0
|
|
581
|
+
),
|
|
582
|
+
duplicates: results.duplicates,
|
|
583
|
+
groups: results.groups,
|
|
584
|
+
clusters: results.clusters
|
|
585
|
+
},
|
|
586
|
+
metadata: {
|
|
587
|
+
toolName: import_core5.ToolName.PatternDetect,
|
|
588
|
+
version: "0.12.5",
|
|
589
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
590
|
+
}
|
|
591
|
+
});
|
|
592
|
+
},
|
|
593
|
+
score(output, options) {
|
|
594
|
+
const duplicates = output.summary.duplicates || [];
|
|
595
|
+
const totalFiles = output.summary.totalFiles || output.results.length;
|
|
596
|
+
return calculatePatternScore(
|
|
597
|
+
duplicates,
|
|
598
|
+
totalFiles,
|
|
599
|
+
options.costConfig
|
|
600
|
+
);
|
|
601
|
+
},
|
|
602
|
+
defaultWeight: 22
|
|
603
|
+
};
|
|
604
|
+
|
|
566
605
|
// src/index.ts
|
|
606
|
+
import_core6.ToolRegistry.register(PatternDetectProvider);
|
|
567
607
|
function getRefactoringSuggestion(patternType, similarity) {
|
|
568
608
|
const baseMessages = {
|
|
569
609
|
"api-handler": "Extract common middleware or create a base handler class",
|
|
@@ -679,7 +719,7 @@ async function analyzePatterns(options) {
|
|
|
679
719
|
const batchContents = await Promise.all(
|
|
680
720
|
batch.map(async (file) => ({
|
|
681
721
|
file,
|
|
682
|
-
content: await (0,
|
|
722
|
+
content: await (0, import_core6.readFileContent)(file)
|
|
683
723
|
}))
|
|
684
724
|
);
|
|
685
725
|
fileContents.push(...batchContents);
|
|
@@ -700,9 +740,9 @@ async function analyzePatterns(options) {
|
|
|
700
740
|
);
|
|
701
741
|
const issues = fileDuplicates.map((dup) => {
|
|
702
742
|
const otherFile = dup.file1 === file ? dup.file2 : dup.file1;
|
|
703
|
-
const severity2 = dup.similarity > 0.95 ?
|
|
743
|
+
const severity2 = dup.similarity > 0.95 ? import_core6.Severity.Critical : dup.similarity > 0.9 ? import_core6.Severity.Major : import_core6.Severity.Minor;
|
|
704
744
|
return {
|
|
705
|
-
type:
|
|
745
|
+
type: import_core6.IssueType.DuplicatePattern,
|
|
706
746
|
severity: severity2,
|
|
707
747
|
message: `${dup.patternType} pattern ${Math.round(dup.similarity * 100)}% similar to ${otherFile} (${dup.tokenCost} tokens wasted)`,
|
|
708
748
|
location: {
|
|
@@ -715,11 +755,11 @@ async function analyzePatterns(options) {
|
|
|
715
755
|
let filteredIssues = issues;
|
|
716
756
|
if (severity !== "all") {
|
|
717
757
|
const severityMap = {
|
|
718
|
-
critical: [
|
|
719
|
-
high: [
|
|
720
|
-
medium: [
|
|
758
|
+
critical: [import_core6.Severity.Critical],
|
|
759
|
+
high: [import_core6.Severity.Critical, import_core6.Severity.Major],
|
|
760
|
+
medium: [import_core6.Severity.Critical, import_core6.Severity.Major, import_core6.Severity.Minor]
|
|
721
761
|
};
|
|
722
|
-
const allowedSeverities = severityMap[severity] || [
|
|
762
|
+
const allowedSeverities = severityMap[severity] || [import_core6.Severity.Critical, import_core6.Severity.Major, import_core6.Severity.Minor];
|
|
723
763
|
filteredIssues = issues.filter(
|
|
724
764
|
(issue) => allowedSeverities.includes(issue.severity)
|
|
725
765
|
);
|
|
@@ -809,6 +849,7 @@ function generateSummary(results) {
|
|
|
809
849
|
}
|
|
810
850
|
// Annotate the CommonJS export names for ESM import in node:
|
|
811
851
|
0 && (module.exports = {
|
|
852
|
+
PatternDetectProvider,
|
|
812
853
|
Severity,
|
|
813
854
|
analyzePatterns,
|
|
814
855
|
calculatePatternScore,
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
PatternDetectProvider,
|
|
2
3
|
Severity,
|
|
3
4
|
analyzePatterns,
|
|
4
5
|
calculatePatternScore,
|
|
@@ -8,8 +9,9 @@ import {
|
|
|
8
9
|
generateSummary,
|
|
9
10
|
getSeverityLabel,
|
|
10
11
|
getSmartDefaults
|
|
11
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-KDWGWBP5.mjs";
|
|
12
13
|
export {
|
|
14
|
+
PatternDetectProvider,
|
|
13
15
|
Severity,
|
|
14
16
|
analyzePatterns,
|
|
15
17
|
calculatePatternScore,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aiready/pattern-detect",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"description": "Semantic duplicate pattern detection for AI-generated code - finds similar implementations that waste AI context tokens",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"dependencies": {
|
|
46
46
|
"commander": "^14.0.0",
|
|
47
47
|
"chalk": "^5.3.0",
|
|
48
|
-
"@aiready/core": "0.
|
|
48
|
+
"@aiready/core": "0.21.0"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
51
|
"tsup": "^8.3.5",
|