@aiready/pattern-detect 0.16.19 → 0.16.21
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/analyzer-entry/index.d.mts +3 -0
- package/dist/analyzer-entry/index.d.ts +3 -0
- package/dist/analyzer-entry/index.js +693 -0
- package/dist/analyzer-entry/index.mjs +12 -0
- package/dist/analyzer-entry.d.mts +100 -3
- package/dist/analyzer-entry.d.ts +100 -3
- package/dist/analyzer-entry.js +9 -126
- package/dist/analyzer-entry.mjs +2 -2
- package/dist/chunk-65UQ5J2J.mjs +64 -0
- package/dist/chunk-6JTVOBJX.mjs +64 -0
- package/dist/chunk-BKRPSTT2.mjs +64 -0
- package/dist/chunk-CMWW24HW.mjs +259 -0
- package/dist/chunk-DNZS4ESD.mjs +391 -0
- package/dist/chunk-GLKAGFKX.mjs +391 -0
- package/dist/chunk-GREN7X5H.mjs +143 -0
- package/dist/chunk-JBUZ6YHE.mjs +391 -0
- package/dist/chunk-KWMNN3TG.mjs +391 -0
- package/dist/chunk-LYKRYBSM.mjs +64 -0
- package/dist/chunk-MHU3CL4R.mjs +64 -0
- package/dist/chunk-RS73WLNI.mjs +251 -0
- package/dist/chunk-SVCSIZ2A.mjs +259 -0
- package/dist/chunk-VGMM3L3O.mjs +143 -0
- package/dist/chunk-XNPID6FU.mjs +391 -0
- package/dist/cli.js +29 -147
- package/dist/cli.mjs +27 -25
- package/dist/context-rules-entry/index.d.mts +2 -0
- package/dist/context-rules-entry/index.d.ts +2 -0
- package/dist/context-rules-entry/index.js +207 -0
- package/dist/context-rules-entry/index.mjs +12 -0
- package/dist/context-rules-entry.d.mts +55 -2
- package/dist/context-rules-entry.d.ts +55 -2
- package/dist/detector-entry/index.d.mts +14 -0
- package/dist/detector-entry/index.d.ts +14 -0
- package/dist/detector-entry/index.js +301 -0
- package/dist/detector-entry/index.mjs +7 -0
- package/dist/detector-entry.d.mts +2 -2
- package/dist/detector-entry.d.ts +2 -2
- package/dist/detector-entry.js +9 -126
- package/dist/detector-entry.mjs +1 -1
- package/dist/index-BVz-HnZd.d.mts +119 -0
- package/dist/index-BwuoiCNm.d.ts +119 -0
- package/dist/index-y2uJSngh.d.mts +60 -0
- package/dist/index-y2uJSngh.d.ts +60 -0
- package/dist/index.d.mts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +9 -126
- package/dist/index.mjs +3 -3
- package/dist/scoring-entry/index.d.mts +23 -0
- package/dist/scoring-entry/index.d.ts +23 -0
- package/dist/scoring-entry/index.js +133 -0
- package/dist/scoring-entry/index.mjs +6 -0
- package/dist/scoring-entry.d.mts +1 -1
- package/dist/scoring-entry.d.ts +1 -1
- package/dist/types-C4lmb2Yh.d.mts +36 -0
- package/dist/types-C4lmb2Yh.d.ts +36 -0
- package/package.json +16 -16
|
@@ -1,3 +1,100 @@
|
|
|
1
|
-
|
|
2
|
-
import '
|
|
3
|
-
|
|
1
|
+
import { Severity, ScanOptions, AnalysisResult } from '@aiready/core';
|
|
2
|
+
import { P as PatternType, a as DuplicatePattern } from './types-C4lmb2Yh.mjs';
|
|
3
|
+
|
|
4
|
+
interface DuplicateGroup {
|
|
5
|
+
filePair: string;
|
|
6
|
+
severity: Severity;
|
|
7
|
+
occurrences: number;
|
|
8
|
+
totalTokenCost: number;
|
|
9
|
+
averageSimilarity: number;
|
|
10
|
+
patternTypes: Set<PatternType>;
|
|
11
|
+
lineRanges: Array<{
|
|
12
|
+
file1: {
|
|
13
|
+
start: number;
|
|
14
|
+
end: number;
|
|
15
|
+
};
|
|
16
|
+
file2: {
|
|
17
|
+
start: number;
|
|
18
|
+
end: number;
|
|
19
|
+
};
|
|
20
|
+
}>;
|
|
21
|
+
}
|
|
22
|
+
interface RefactorCluster {
|
|
23
|
+
id: string;
|
|
24
|
+
name: string;
|
|
25
|
+
files: string[];
|
|
26
|
+
severity: Severity;
|
|
27
|
+
duplicateCount: number;
|
|
28
|
+
totalTokenCost: number;
|
|
29
|
+
averageSimilarity: number;
|
|
30
|
+
reason?: string;
|
|
31
|
+
suggestion?: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
interface PatternDetectOptions extends ScanOptions {
|
|
35
|
+
minSimilarity?: number;
|
|
36
|
+
minLines?: number;
|
|
37
|
+
batchSize?: number;
|
|
38
|
+
approx?: boolean;
|
|
39
|
+
minSharedTokens?: number;
|
|
40
|
+
maxCandidatesPerBlock?: number;
|
|
41
|
+
streamResults?: boolean;
|
|
42
|
+
severity?: string;
|
|
43
|
+
includeTests?: boolean;
|
|
44
|
+
useSmartDefaults?: boolean;
|
|
45
|
+
groupByFilePair?: boolean;
|
|
46
|
+
createClusters?: boolean;
|
|
47
|
+
minClusterTokenCost?: number;
|
|
48
|
+
minClusterFiles?: number;
|
|
49
|
+
excludePatterns?: string[];
|
|
50
|
+
confidenceThreshold?: number;
|
|
51
|
+
ignoreWhitelist?: string[];
|
|
52
|
+
onProgress?: (processed: number, total: number, message: string) => void;
|
|
53
|
+
}
|
|
54
|
+
interface PatternSummary {
|
|
55
|
+
totalPatterns: number;
|
|
56
|
+
totalTokenCost: number;
|
|
57
|
+
patternsByType: Record<PatternType, number>;
|
|
58
|
+
topDuplicates: Array<{
|
|
59
|
+
files: Array<{
|
|
60
|
+
path: string;
|
|
61
|
+
startLine: number;
|
|
62
|
+
endLine: number;
|
|
63
|
+
}>;
|
|
64
|
+
similarity: number;
|
|
65
|
+
patternType: PatternType;
|
|
66
|
+
tokenCost: number;
|
|
67
|
+
}>;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Determine smart defaults based on repository size estimation.
|
|
71
|
+
*
|
|
72
|
+
* @param directory - The directory to analyze for size.
|
|
73
|
+
* @param userOptions - User-provided option overrides.
|
|
74
|
+
* @returns Promise resolving to optimal detection options.
|
|
75
|
+
*/
|
|
76
|
+
declare function getSmartDefaults(directory: string, userOptions: Partial<PatternDetectOptions>): Promise<PatternDetectOptions>;
|
|
77
|
+
/**
|
|
78
|
+
* Main entry point for pattern detection analysis.
|
|
79
|
+
*
|
|
80
|
+
* @param options - Configuration including rootDir and detection parameters.
|
|
81
|
+
* @returns Promise resolving to the comprehensive pattern detect report.
|
|
82
|
+
* @lastUpdated 2026-03-18
|
|
83
|
+
*/
|
|
84
|
+
declare function analyzePatterns(options: PatternDetectOptions): Promise<{
|
|
85
|
+
results: AnalysisResult[];
|
|
86
|
+
duplicates: DuplicatePattern[];
|
|
87
|
+
files: string[];
|
|
88
|
+
groups?: DuplicateGroup[];
|
|
89
|
+
clusters?: RefactorCluster[];
|
|
90
|
+
config: PatternDetectOptions;
|
|
91
|
+
}>;
|
|
92
|
+
/**
|
|
93
|
+
* Generate a summary of pattern detection results.
|
|
94
|
+
*
|
|
95
|
+
* @param results - Array of file-level analysis results.
|
|
96
|
+
* @returns Consolidated pattern summary object.
|
|
97
|
+
*/
|
|
98
|
+
declare function generateSummary(results: AnalysisResult[]): PatternSummary;
|
|
99
|
+
|
|
100
|
+
export { type PatternDetectOptions, type PatternSummary, analyzePatterns, generateSummary, getSmartDefaults };
|
package/dist/analyzer-entry.d.ts
CHANGED
|
@@ -1,3 +1,100 @@
|
|
|
1
|
-
|
|
2
|
-
import '
|
|
3
|
-
|
|
1
|
+
import { Severity, ScanOptions, AnalysisResult } from '@aiready/core';
|
|
2
|
+
import { P as PatternType, a as DuplicatePattern } from './types-C4lmb2Yh.js';
|
|
3
|
+
|
|
4
|
+
interface DuplicateGroup {
|
|
5
|
+
filePair: string;
|
|
6
|
+
severity: Severity;
|
|
7
|
+
occurrences: number;
|
|
8
|
+
totalTokenCost: number;
|
|
9
|
+
averageSimilarity: number;
|
|
10
|
+
patternTypes: Set<PatternType>;
|
|
11
|
+
lineRanges: Array<{
|
|
12
|
+
file1: {
|
|
13
|
+
start: number;
|
|
14
|
+
end: number;
|
|
15
|
+
};
|
|
16
|
+
file2: {
|
|
17
|
+
start: number;
|
|
18
|
+
end: number;
|
|
19
|
+
};
|
|
20
|
+
}>;
|
|
21
|
+
}
|
|
22
|
+
interface RefactorCluster {
|
|
23
|
+
id: string;
|
|
24
|
+
name: string;
|
|
25
|
+
files: string[];
|
|
26
|
+
severity: Severity;
|
|
27
|
+
duplicateCount: number;
|
|
28
|
+
totalTokenCost: number;
|
|
29
|
+
averageSimilarity: number;
|
|
30
|
+
reason?: string;
|
|
31
|
+
suggestion?: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
interface PatternDetectOptions extends ScanOptions {
|
|
35
|
+
minSimilarity?: number;
|
|
36
|
+
minLines?: number;
|
|
37
|
+
batchSize?: number;
|
|
38
|
+
approx?: boolean;
|
|
39
|
+
minSharedTokens?: number;
|
|
40
|
+
maxCandidatesPerBlock?: number;
|
|
41
|
+
streamResults?: boolean;
|
|
42
|
+
severity?: string;
|
|
43
|
+
includeTests?: boolean;
|
|
44
|
+
useSmartDefaults?: boolean;
|
|
45
|
+
groupByFilePair?: boolean;
|
|
46
|
+
createClusters?: boolean;
|
|
47
|
+
minClusterTokenCost?: number;
|
|
48
|
+
minClusterFiles?: number;
|
|
49
|
+
excludePatterns?: string[];
|
|
50
|
+
confidenceThreshold?: number;
|
|
51
|
+
ignoreWhitelist?: string[];
|
|
52
|
+
onProgress?: (processed: number, total: number, message: string) => void;
|
|
53
|
+
}
|
|
54
|
+
interface PatternSummary {
|
|
55
|
+
totalPatterns: number;
|
|
56
|
+
totalTokenCost: number;
|
|
57
|
+
patternsByType: Record<PatternType, number>;
|
|
58
|
+
topDuplicates: Array<{
|
|
59
|
+
files: Array<{
|
|
60
|
+
path: string;
|
|
61
|
+
startLine: number;
|
|
62
|
+
endLine: number;
|
|
63
|
+
}>;
|
|
64
|
+
similarity: number;
|
|
65
|
+
patternType: PatternType;
|
|
66
|
+
tokenCost: number;
|
|
67
|
+
}>;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Determine smart defaults based on repository size estimation.
|
|
71
|
+
*
|
|
72
|
+
* @param directory - The directory to analyze for size.
|
|
73
|
+
* @param userOptions - User-provided option overrides.
|
|
74
|
+
* @returns Promise resolving to optimal detection options.
|
|
75
|
+
*/
|
|
76
|
+
declare function getSmartDefaults(directory: string, userOptions: Partial<PatternDetectOptions>): Promise<PatternDetectOptions>;
|
|
77
|
+
/**
|
|
78
|
+
* Main entry point for pattern detection analysis.
|
|
79
|
+
*
|
|
80
|
+
* @param options - Configuration including rootDir and detection parameters.
|
|
81
|
+
* @returns Promise resolving to the comprehensive pattern detect report.
|
|
82
|
+
* @lastUpdated 2026-03-18
|
|
83
|
+
*/
|
|
84
|
+
declare function analyzePatterns(options: PatternDetectOptions): Promise<{
|
|
85
|
+
results: AnalysisResult[];
|
|
86
|
+
duplicates: DuplicatePattern[];
|
|
87
|
+
files: string[];
|
|
88
|
+
groups?: DuplicateGroup[];
|
|
89
|
+
clusters?: RefactorCluster[];
|
|
90
|
+
config: PatternDetectOptions;
|
|
91
|
+
}>;
|
|
92
|
+
/**
|
|
93
|
+
* Generate a summary of pattern detection results.
|
|
94
|
+
*
|
|
95
|
+
* @param results - Array of file-level analysis results.
|
|
96
|
+
* @returns Consolidated pattern summary object.
|
|
97
|
+
*/
|
|
98
|
+
declare function generateSummary(results: AnalysisResult[]): PatternSummary;
|
|
99
|
+
|
|
100
|
+
export { type PatternDetectOptions, type PatternSummary, analyzePatterns, generateSummary, getSmartDefaults };
|
package/dist/analyzer-entry.js
CHANGED
|
@@ -182,144 +182,27 @@ function calculateSeverity(file1, file2, code, similarity, linesOfCode) {
|
|
|
182
182
|
}
|
|
183
183
|
}
|
|
184
184
|
|
|
185
|
-
// src/
|
|
185
|
+
// src/core/normalizer.ts
|
|
186
186
|
function normalizeCode(code, isPython = false) {
|
|
187
|
+
if (!code) return "";
|
|
187
188
|
let normalized = code;
|
|
188
189
|
if (isPython) {
|
|
189
190
|
normalized = normalized.replace(/#.*/g, "");
|
|
190
191
|
} else {
|
|
191
|
-
normalized = normalized.replace(
|
|
192
|
+
normalized = normalized.replace(/\/\/.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "");
|
|
192
193
|
}
|
|
193
|
-
return normalized.replace(/[
|
|
194
|
+
return normalized.replace(/"[^"]*"/g, '"STR"').replace(/'[^']*'/g, "'STR'").replace(/`[^`]*`/g, "`STR`").replace(/\b\d+\b/g, "NUM").replace(/\s+/g, " ").trim().toLowerCase();
|
|
194
195
|
}
|
|
196
|
+
|
|
197
|
+
// src/detector.ts
|
|
195
198
|
function extractBlocks(file, content) {
|
|
196
|
-
|
|
197
|
-
if (isPython) {
|
|
198
|
-
return extractBlocksPython(file, content);
|
|
199
|
-
}
|
|
200
|
-
const blocks = [];
|
|
201
|
-
const lines = content.split("\n");
|
|
202
|
-
const blockRegex = /^\s*(?:export\s+)?(?:async\s+)?(?:public\s+|private\s+|protected\s+|internal\s+|static\s+|readonly\s+|virtual\s+|abstract\s+|override\s+)*(function|class|interface|type|enum|record|struct|void|func|[a-zA-Z0-9_<>[]]+)\s+([a-zA-Z0-9_]+)(?:\s*\(|(?:\s+extends|\s+implements|\s+where)?\s*\{)|^\s*(?:export\s+)?const\s+([a-zA-Z0-9_]+)\s*=\s*[a-zA-Z0-9_.]+\.object\(|^\s*(app\.(?:get|post|put|delete|patch|use))\(/gm;
|
|
203
|
-
let match;
|
|
204
|
-
while ((match = blockRegex.exec(content)) !== null) {
|
|
205
|
-
const startLine = content.substring(0, match.index).split("\n").length;
|
|
206
|
-
let type;
|
|
207
|
-
let name;
|
|
208
|
-
if (match[1]) {
|
|
209
|
-
type = match[1];
|
|
210
|
-
name = match[2];
|
|
211
|
-
} else if (match[3]) {
|
|
212
|
-
type = "const";
|
|
213
|
-
name = match[3];
|
|
214
|
-
} else {
|
|
215
|
-
type = "handler";
|
|
216
|
-
name = match[4];
|
|
217
|
-
}
|
|
218
|
-
let endLine = -1;
|
|
219
|
-
let openBraces = 0;
|
|
220
|
-
let foundStart = false;
|
|
221
|
-
for (let i = match.index; i < content.length; i++) {
|
|
222
|
-
if (content[i] === "{") {
|
|
223
|
-
openBraces++;
|
|
224
|
-
foundStart = true;
|
|
225
|
-
} else if (content[i] === "}") {
|
|
226
|
-
openBraces--;
|
|
227
|
-
}
|
|
228
|
-
if (foundStart && openBraces === 0) {
|
|
229
|
-
endLine = content.substring(0, i + 1).split("\n").length;
|
|
230
|
-
break;
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
if (endLine === -1) {
|
|
234
|
-
const remaining = content.slice(match.index);
|
|
235
|
-
const nextLineMatch = remaining.indexOf("\n");
|
|
236
|
-
if (nextLineMatch !== -1) {
|
|
237
|
-
endLine = startLine;
|
|
238
|
-
} else {
|
|
239
|
-
endLine = lines.length;
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
endLine = Math.max(startLine, endLine);
|
|
243
|
-
const blockCode = lines.slice(startLine - 1, endLine).join("\n");
|
|
244
|
-
const tokens = (0, import_core2.estimateTokens)(blockCode);
|
|
245
|
-
blocks.push({
|
|
246
|
-
file,
|
|
247
|
-
startLine,
|
|
248
|
-
endLine,
|
|
249
|
-
code: blockCode,
|
|
250
|
-
tokens,
|
|
251
|
-
patternType: inferPatternType(type, name)
|
|
252
|
-
});
|
|
253
|
-
}
|
|
254
|
-
return blocks;
|
|
255
|
-
}
|
|
256
|
-
function extractBlocksPython(file, content) {
|
|
257
|
-
const blocks = [];
|
|
258
|
-
const lines = content.split("\n");
|
|
259
|
-
const blockRegex = /^\s*(?:async\s+)?(def|class)\s+([a-zA-Z0-9_]+)/gm;
|
|
260
|
-
let match;
|
|
261
|
-
while ((match = blockRegex.exec(content)) !== null) {
|
|
262
|
-
const startLinePos = content.substring(0, match.index).split("\n").length;
|
|
263
|
-
const startLineIdx = startLinePos - 1;
|
|
264
|
-
const initialIndent = lines[startLineIdx].search(/\S/);
|
|
265
|
-
let endLineIdx = startLineIdx;
|
|
266
|
-
for (let i = startLineIdx + 1; i < lines.length; i++) {
|
|
267
|
-
const line = lines[i];
|
|
268
|
-
if (line.trim().length === 0) {
|
|
269
|
-
endLineIdx = i;
|
|
270
|
-
continue;
|
|
271
|
-
}
|
|
272
|
-
const currentIndent = line.search(/\S/);
|
|
273
|
-
if (currentIndent <= initialIndent) {
|
|
274
|
-
break;
|
|
275
|
-
}
|
|
276
|
-
endLineIdx = i;
|
|
277
|
-
}
|
|
278
|
-
while (endLineIdx > startLineIdx && lines[endLineIdx].trim().length === 0) {
|
|
279
|
-
endLineIdx--;
|
|
280
|
-
}
|
|
281
|
-
const blockCode = lines.slice(startLineIdx, endLineIdx + 1).join("\n");
|
|
282
|
-
const tokens = (0, import_core2.estimateTokens)(blockCode);
|
|
283
|
-
blocks.push({
|
|
284
|
-
file,
|
|
285
|
-
startLine: startLinePos,
|
|
286
|
-
endLine: endLineIdx + 1,
|
|
287
|
-
code: blockCode,
|
|
288
|
-
tokens,
|
|
289
|
-
patternType: inferPatternType(match[1], match[2])
|
|
290
|
-
});
|
|
291
|
-
}
|
|
292
|
-
return blocks;
|
|
293
|
-
}
|
|
294
|
-
function inferPatternType(keyword, name) {
|
|
295
|
-
const n = name.toLowerCase();
|
|
296
|
-
if (keyword === "handler" || n.includes("handler") || n.includes("controller") || n.startsWith("app.")) {
|
|
297
|
-
return "api-handler";
|
|
298
|
-
}
|
|
299
|
-
if (n.includes("validate") || n.includes("schema")) return "validator";
|
|
300
|
-
if (n.includes("util") || n.includes("helper")) return "utility";
|
|
301
|
-
if (keyword === "class") return "class-method";
|
|
302
|
-
if (n.match(/^[A-Z]/)) return "component";
|
|
303
|
-
if (keyword === "function") return "function";
|
|
304
|
-
return "unknown";
|
|
199
|
+
return (0, import_core2.extractCodeBlocks)(file, content);
|
|
305
200
|
}
|
|
306
201
|
function calculateSimilarity(a, b) {
|
|
307
|
-
|
|
308
|
-
const tokensA = a.split(/[^a-zA-Z0-9]+/).filter((t) => t.length > 0);
|
|
309
|
-
const tokensB = b.split(/[^a-zA-Z0-9]+/).filter((t) => t.length > 0);
|
|
310
|
-
if (tokensA.length === 0 || tokensB.length === 0) return 0;
|
|
311
|
-
const setA = new Set(tokensA);
|
|
312
|
-
const setB = new Set(tokensB);
|
|
313
|
-
const intersection = new Set([...setA].filter((x) => setB.has(x)));
|
|
314
|
-
const union = /* @__PURE__ */ new Set([...setA, ...setB]);
|
|
315
|
-
return intersection.size / union.size;
|
|
202
|
+
return (0, import_core2.calculateStringSimilarity)(a, b);
|
|
316
203
|
}
|
|
317
204
|
function calculateConfidence(similarity, tokens, lines) {
|
|
318
|
-
|
|
319
|
-
if (lines > 20) confidence += 0.05;
|
|
320
|
-
if (tokens > 200) confidence += 0.05;
|
|
321
|
-
if (lines < 5) confidence -= 0.1;
|
|
322
|
-
return Math.max(0, Math.min(1, confidence));
|
|
205
|
+
return (0, import_core2.calculateHeuristicConfidence)(similarity, tokens, lines);
|
|
323
206
|
}
|
|
324
207
|
async function detectDuplicatePatterns(fileContents, options) {
|
|
325
208
|
const {
|
package/dist/analyzer-entry.mjs
CHANGED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import {
|
|
2
|
+
analyzePatterns
|
|
3
|
+
} from "./chunk-JBUZ6YHE.mjs";
|
|
4
|
+
import {
|
|
5
|
+
calculatePatternScore
|
|
6
|
+
} from "./chunk-WBBO35SC.mjs";
|
|
7
|
+
|
|
8
|
+
// src/index.ts
|
|
9
|
+
import { ToolRegistry, Severity } from "@aiready/core";
|
|
10
|
+
|
|
11
|
+
// src/provider.ts
|
|
12
|
+
import {
|
|
13
|
+
ToolName,
|
|
14
|
+
SpokeOutputSchema,
|
|
15
|
+
GLOBAL_SCAN_OPTIONS
|
|
16
|
+
} from "@aiready/core";
|
|
17
|
+
var PatternDetectProvider = {
|
|
18
|
+
id: ToolName.PatternDetect,
|
|
19
|
+
alias: ["patterns", "duplicates", "duplication"],
|
|
20
|
+
async analyze(options) {
|
|
21
|
+
const results = await analyzePatterns(options);
|
|
22
|
+
return SpokeOutputSchema.parse({
|
|
23
|
+
results: results.results,
|
|
24
|
+
summary: {
|
|
25
|
+
totalFiles: results.files.length,
|
|
26
|
+
totalIssues: results.results.reduce(
|
|
27
|
+
(sum, r) => sum + r.issues.length,
|
|
28
|
+
0
|
|
29
|
+
),
|
|
30
|
+
duplicates: results.duplicates,
|
|
31
|
+
// Keep the raw duplicates for score calculation
|
|
32
|
+
clusters: results.clusters,
|
|
33
|
+
config: Object.fromEntries(
|
|
34
|
+
Object.entries(results.config).filter(
|
|
35
|
+
([key]) => !GLOBAL_SCAN_OPTIONS.includes(key) || key === "rootDir"
|
|
36
|
+
)
|
|
37
|
+
)
|
|
38
|
+
},
|
|
39
|
+
metadata: {
|
|
40
|
+
toolName: ToolName.PatternDetect,
|
|
41
|
+
version: "0.12.5",
|
|
42
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
},
|
|
46
|
+
score(output, options) {
|
|
47
|
+
const duplicates = output.summary.duplicates || [];
|
|
48
|
+
const totalFiles = output.summary.totalFiles || output.results.length;
|
|
49
|
+
return calculatePatternScore(
|
|
50
|
+
duplicates,
|
|
51
|
+
totalFiles,
|
|
52
|
+
options.costConfig
|
|
53
|
+
);
|
|
54
|
+
},
|
|
55
|
+
defaultWeight: 22
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
// src/index.ts
|
|
59
|
+
ToolRegistry.register(PatternDetectProvider);
|
|
60
|
+
|
|
61
|
+
export {
|
|
62
|
+
PatternDetectProvider,
|
|
63
|
+
Severity
|
|
64
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import {
|
|
2
|
+
analyzePatterns
|
|
3
|
+
} from "./chunk-DNZS4ESD.mjs";
|
|
4
|
+
import {
|
|
5
|
+
calculatePatternScore
|
|
6
|
+
} from "./chunk-WBBO35SC.mjs";
|
|
7
|
+
|
|
8
|
+
// src/index.ts
|
|
9
|
+
import { ToolRegistry, Severity } from "@aiready/core";
|
|
10
|
+
|
|
11
|
+
// src/provider.ts
|
|
12
|
+
import {
|
|
13
|
+
ToolName,
|
|
14
|
+
SpokeOutputSchema,
|
|
15
|
+
GLOBAL_SCAN_OPTIONS
|
|
16
|
+
} from "@aiready/core";
|
|
17
|
+
var PatternDetectProvider = {
|
|
18
|
+
id: ToolName.PatternDetect,
|
|
19
|
+
alias: ["patterns", "duplicates", "duplication"],
|
|
20
|
+
async analyze(options) {
|
|
21
|
+
const results = await analyzePatterns(options);
|
|
22
|
+
return SpokeOutputSchema.parse({
|
|
23
|
+
results: results.results,
|
|
24
|
+
summary: {
|
|
25
|
+
totalFiles: results.files.length,
|
|
26
|
+
totalIssues: results.results.reduce(
|
|
27
|
+
(sum, r) => sum + r.issues.length,
|
|
28
|
+
0
|
|
29
|
+
),
|
|
30
|
+
duplicates: results.duplicates,
|
|
31
|
+
// Keep the raw duplicates for score calculation
|
|
32
|
+
clusters: results.clusters,
|
|
33
|
+
config: Object.fromEntries(
|
|
34
|
+
Object.entries(results.config).filter(
|
|
35
|
+
([key]) => !GLOBAL_SCAN_OPTIONS.includes(key) || key === "rootDir"
|
|
36
|
+
)
|
|
37
|
+
)
|
|
38
|
+
},
|
|
39
|
+
metadata: {
|
|
40
|
+
toolName: ToolName.PatternDetect,
|
|
41
|
+
version: "0.12.5",
|
|
42
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
},
|
|
46
|
+
score(output, options) {
|
|
47
|
+
const duplicates = output.summary.duplicates || [];
|
|
48
|
+
const totalFiles = output.summary.totalFiles || output.results.length;
|
|
49
|
+
return calculatePatternScore(
|
|
50
|
+
duplicates,
|
|
51
|
+
totalFiles,
|
|
52
|
+
options.costConfig
|
|
53
|
+
);
|
|
54
|
+
},
|
|
55
|
+
defaultWeight: 22
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
// src/index.ts
|
|
59
|
+
ToolRegistry.register(PatternDetectProvider);
|
|
60
|
+
|
|
61
|
+
export {
|
|
62
|
+
PatternDetectProvider,
|
|
63
|
+
Severity
|
|
64
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import {
|
|
2
|
+
analyzePatterns
|
|
3
|
+
} from "./chunk-XNPID6FU.mjs";
|
|
4
|
+
import {
|
|
5
|
+
calculatePatternScore
|
|
6
|
+
} from "./chunk-WBBO35SC.mjs";
|
|
7
|
+
|
|
8
|
+
// src/index.ts
|
|
9
|
+
import { ToolRegistry, Severity } from "@aiready/core";
|
|
10
|
+
|
|
11
|
+
// src/provider.ts
|
|
12
|
+
import {
|
|
13
|
+
ToolName,
|
|
14
|
+
SpokeOutputSchema,
|
|
15
|
+
GLOBAL_SCAN_OPTIONS
|
|
16
|
+
} from "@aiready/core";
|
|
17
|
+
var PatternDetectProvider = {
|
|
18
|
+
id: ToolName.PatternDetect,
|
|
19
|
+
alias: ["patterns", "duplicates", "duplication"],
|
|
20
|
+
async analyze(options) {
|
|
21
|
+
const results = await analyzePatterns(options);
|
|
22
|
+
return SpokeOutputSchema.parse({
|
|
23
|
+
results: results.results,
|
|
24
|
+
summary: {
|
|
25
|
+
totalFiles: results.files.length,
|
|
26
|
+
totalIssues: results.results.reduce(
|
|
27
|
+
(sum, r) => sum + r.issues.length,
|
|
28
|
+
0
|
|
29
|
+
),
|
|
30
|
+
duplicates: results.duplicates,
|
|
31
|
+
// Keep the raw duplicates for score calculation
|
|
32
|
+
clusters: results.clusters,
|
|
33
|
+
config: Object.fromEntries(
|
|
34
|
+
Object.entries(results.config).filter(
|
|
35
|
+
([key]) => !GLOBAL_SCAN_OPTIONS.includes(key) || key === "rootDir"
|
|
36
|
+
)
|
|
37
|
+
)
|
|
38
|
+
},
|
|
39
|
+
metadata: {
|
|
40
|
+
toolName: ToolName.PatternDetect,
|
|
41
|
+
version: "0.12.5",
|
|
42
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
},
|
|
46
|
+
score(output, options) {
|
|
47
|
+
const duplicates = output.summary.duplicates || [];
|
|
48
|
+
const totalFiles = output.summary.totalFiles || output.results.length;
|
|
49
|
+
return calculatePatternScore(
|
|
50
|
+
duplicates,
|
|
51
|
+
totalFiles,
|
|
52
|
+
options.costConfig
|
|
53
|
+
);
|
|
54
|
+
},
|
|
55
|
+
defaultWeight: 22
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
// src/index.ts
|
|
59
|
+
ToolRegistry.register(PatternDetectProvider);
|
|
60
|
+
|
|
61
|
+
export {
|
|
62
|
+
PatternDetectProvider,
|
|
63
|
+
Severity
|
|
64
|
+
};
|