@aiready/pattern-detect 0.12.3 → 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/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 import_core5 = require("@aiready/core");
30
+ var import_core6 = require("@aiready/core");
31
31
 
32
32
  // src/detector.ts
33
33
  var import_core2 = require("@aiready/core");
@@ -260,7 +260,9 @@ async function detectDuplicatePatterns(fileContents, options) {
260
260
  const allBlocks = [];
261
261
  for (const { file, content } of fileContents) {
262
262
  const blocks = extractBlocks(file, content);
263
- allBlocks.push(...blocks.filter((b) => b.endLine - b.startLine + 1 >= minLines));
263
+ allBlocks.push(
264
+ ...blocks.filter((b) => b.endLine - b.startLine + 1 >= minLines)
265
+ );
264
266
  }
265
267
  const duplicates = [];
266
268
  for (let i = 0; i < allBlocks.length; i++) {
@@ -385,7 +387,10 @@ function createRefactorClusters(duplicates) {
385
387
  const componentDups = duplicates.filter(
386
388
  (d) => component.includes(d.file1) && component.includes(d.file2)
387
389
  );
388
- const totalTokenCost = componentDups.reduce((sum, d) => sum + d.tokenCost, 0);
390
+ const totalTokenCost = componentDups.reduce(
391
+ (sum, d) => sum + d.tokenCost,
392
+ 0
393
+ );
389
394
  const avgSimilarity = componentDups.reduce((sum, d) => sum + d.similarity, 0) / Math.max(1, componentDups.length);
390
395
  const name = determineClusterName(component);
391
396
  const { severity, reason, suggestion } = calculateSeverity(
@@ -414,7 +419,8 @@ function createRefactorClusters(duplicates) {
414
419
  function determineClusterName(files) {
415
420
  if (files.length === 0) return "Unknown Cluster";
416
421
  if (files.some((f) => f.includes("blog"))) return "Blog SEO Boilerplate";
417
- if (files.some((f) => f.includes("buttons"))) return "Button Component Variants";
422
+ if (files.some((f) => f.includes("buttons")))
423
+ return "Button Component Variants";
418
424
  if (files.some((f) => f.includes("cards"))) return "Card Component Variants";
419
425
  if (files.some((f) => f.includes("login.test"))) return "E2E Test Patterns";
420
426
  const first = files[0];
@@ -432,8 +438,148 @@ function filterClustersByImpact(clusters, minTokenCost = 1e3, minFiles = 3) {
432
438
 
433
439
  // src/scoring.ts
434
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
+ };
435
580
 
436
581
  // src/index.ts
582
+ import_core6.ToolRegistry.register(PatternDetectProvider);
437
583
  function getRefactoringSuggestion(patternType, similarity) {
438
584
  const baseMessages = {
439
585
  "api-handler": "Extract common middleware or create a base handler class",
@@ -549,7 +695,7 @@ async function analyzePatterns(options) {
549
695
  const batchContents = await Promise.all(
550
696
  batch.map(async (file) => ({
551
697
  file,
552
- content: await (0, import_core5.readFileContent)(file)
698
+ content: await (0, import_core6.readFileContent)(file)
553
699
  }))
554
700
  );
555
701
  fileContents.push(...batchContents);
@@ -570,9 +716,9 @@ async function analyzePatterns(options) {
570
716
  );
571
717
  const issues = fileDuplicates.map((dup) => {
572
718
  const otherFile = dup.file1 === file ? dup.file2 : dup.file1;
573
- const severity2 = dup.similarity > 0.95 ? import_core5.Severity.Critical : dup.similarity > 0.9 ? import_core5.Severity.Major : import_core5.Severity.Minor;
719
+ const severity2 = dup.similarity > 0.95 ? import_core6.Severity.Critical : dup.similarity > 0.9 ? import_core6.Severity.Major : import_core6.Severity.Minor;
574
720
  return {
575
- type: import_core5.IssueType.DuplicatePattern,
721
+ type: import_core6.IssueType.DuplicatePattern,
576
722
  severity: severity2,
577
723
  message: `${dup.patternType} pattern ${Math.round(dup.similarity * 100)}% similar to ${otherFile} (${dup.tokenCost} tokens wasted)`,
578
724
  location: {
@@ -585,11 +731,11 @@ async function analyzePatterns(options) {
585
731
  let filteredIssues = issues;
586
732
  if (severity !== "all") {
587
733
  const severityMap = {
588
- critical: [import_core5.Severity.Critical],
589
- high: [import_core5.Severity.Critical, import_core5.Severity.Major],
590
- medium: [import_core5.Severity.Critical, import_core5.Severity.Major, import_core5.Severity.Minor]
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]
591
737
  };
592
- const allowedSeverities = severityMap[severity] || [import_core5.Severity.Critical, import_core5.Severity.Major, import_core5.Severity.Minor];
738
+ const allowedSeverities = severityMap[severity] || [import_core6.Severity.Critical, import_core6.Severity.Major, import_core6.Severity.Minor];
593
739
  filteredIssues = issues.filter(
594
740
  (issue) => allowedSeverities.includes(issue.severity)
595
741
  );
@@ -682,7 +828,7 @@ function generateSummary(results) {
682
828
  var import_chalk = __toESM(require("chalk"));
683
829
  var import_fs = require("fs");
684
830
  var import_path2 = require("path");
685
- var import_core6 = require("@aiready/core");
831
+ var import_core7 = require("@aiready/core");
686
832
  var program = new import_commander.Command();
687
833
  program.name("aiready-patterns").description("Detect duplicate patterns in your codebase").version("0.1.0").addHelpText(
688
834
  "after",
@@ -736,7 +882,7 @@ program.name("aiready-patterns").description("Detect duplicate patterns in your
736
882
  ).option("--output-file <path>", "Output file path (for json/html)").action(async (directory, options) => {
737
883
  console.log(import_chalk.default.blue("\u{1F50D} Analyzing patterns...\n"));
738
884
  const startTime = Date.now();
739
- const config = await (0, import_core6.loadConfig)(directory);
885
+ const config = await (0, import_core7.loadConfig)(directory);
740
886
  const defaults = {
741
887
  minSimilarity: 0.4,
742
888
  minLines: 5,
@@ -747,7 +893,7 @@ program.name("aiready-patterns").description("Detect duplicate patterns in your
747
893
  streamResults: true,
748
894
  include: void 0,
749
895
  exclude: void 0,
750
- minSeverity: import_core6.Severity.Minor,
896
+ minSeverity: import_core7.Severity.Minor,
751
897
  excludeTestFixtures: false,
752
898
  excludeTemplates: false,
753
899
  includeTests: false,
@@ -758,7 +904,7 @@ program.name("aiready-patterns").description("Detect duplicate patterns in your
758
904
  minClusterFiles: 3,
759
905
  showRawDuplicates: false
760
906
  };
761
- const mergedConfig = (0, import_core6.mergeConfigWithDefaults)(config, defaults);
907
+ const mergedConfig = (0, import_core7.mergeConfigWithDefaults)(config, defaults);
762
908
  const finalOptions = {
763
909
  rootDir: directory,
764
910
  minSimilarity: options.similarity ? parseFloat(options.similarity) : mergedConfig.minSimilarity,
@@ -830,7 +976,7 @@ program.name("aiready-patterns").description("Detect duplicate patterns in your
830
976
  clusters: clusters || [],
831
977
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
832
978
  };
833
- const outputPath = (0, import_core6.resolveOutputPath)(
979
+ const outputPath = (0, import_core7.resolveOutputPath)(
834
980
  options.outputFile,
835
981
  `pattern-report-${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}.json`,
836
982
  directory
@@ -846,7 +992,7 @@ program.name("aiready-patterns").description("Detect duplicate patterns in your
846
992
  }
847
993
  if (options.output === "html") {
848
994
  const html = generateHTMLReport(summary, results);
849
- const outputPath = (0, import_core6.resolveOutputPath)(
995
+ const outputPath = (0, import_core7.resolveOutputPath)(
850
996
  options.outputFile,
851
997
  `pattern-report-${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}.html`,
852
998
  directory
@@ -1176,10 +1322,10 @@ function generateHTMLReport(summary, results) {
1176
1322
  }
1177
1323
  program.parse();
1178
1324
  function getSeverityValue(s) {
1179
- if (s === import_core6.Severity.Critical || s === "critical") return 4;
1180
- if (s === import_core6.Severity.Major || s === "major") return 3;
1181
- if (s === import_core6.Severity.Minor || s === "minor") return 2;
1182
- if (s === import_core6.Severity.Info || s === "info") return 1;
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;
1183
1329
  return 0;
1184
1330
  }
1185
1331
  function getSeverityBadge(severity) {
package/dist/cli.mjs CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  analyzePatterns,
4
4
  filterBySeverity,
5
5
  generateSummary
6
- } from "./chunk-2R7HOR5H.mjs";
6
+ } from "./chunk-KDWGWBP5.mjs";
7
7
 
8
8
  // src/cli.ts
9
9
  import { Command } from "commander";
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
- Severity: () => import_core5.Severity,
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 import_core5 = require("@aiready/core");
45
+ var import_core6 = require("@aiready/core");
45
46
 
46
47
  // src/detector.ts
47
48
  var import_core2 = require("@aiready/core");
@@ -283,7 +284,9 @@ async function detectDuplicatePatterns(fileContents, options) {
283
284
  const allBlocks = [];
284
285
  for (const { file, content } of fileContents) {
285
286
  const blocks = extractBlocks(file, content);
286
- allBlocks.push(...blocks.filter((b) => b.endLine - b.startLine + 1 >= minLines));
287
+ allBlocks.push(
288
+ ...blocks.filter((b) => b.endLine - b.startLine + 1 >= minLines)
289
+ );
287
290
  }
288
291
  const duplicates = [];
289
292
  for (let i = 0; i < allBlocks.length; i++) {
@@ -408,7 +411,10 @@ function createRefactorClusters(duplicates) {
408
411
  const componentDups = duplicates.filter(
409
412
  (d) => component.includes(d.file1) && component.includes(d.file2)
410
413
  );
411
- const totalTokenCost = componentDups.reduce((sum, d) => sum + d.tokenCost, 0);
414
+ const totalTokenCost = componentDups.reduce(
415
+ (sum, d) => sum + d.tokenCost,
416
+ 0
417
+ );
412
418
  const avgSimilarity = componentDups.reduce((sum, d) => sum + d.similarity, 0) / Math.max(1, componentDups.length);
413
419
  const name = determineClusterName(component);
414
420
  const { severity, reason, suggestion } = calculateSeverity(
@@ -437,7 +443,8 @@ function createRefactorClusters(duplicates) {
437
443
  function determineClusterName(files) {
438
444
  if (files.length === 0) return "Unknown Cluster";
439
445
  if (files.some((f) => f.includes("blog"))) return "Blog SEO Boilerplate";
440
- if (files.some((f) => f.includes("buttons"))) return "Button Component Variants";
446
+ if (files.some((f) => f.includes("buttons")))
447
+ return "Button Component Variants";
441
448
  if (files.some((f) => f.includes("cards"))) return "Card Component Variants";
442
449
  if (files.some((f) => f.includes("login.test"))) return "E2E Test Patterns";
443
450
  const first = files[0];
@@ -463,7 +470,7 @@ function calculatePatternScore(duplicates, totalFilesAnalyzed, costConfig) {
463
470
  ).length;
464
471
  if (totalFilesAnalyzed === 0) {
465
472
  return {
466
- toolName: "pattern-detect",
473
+ toolName: import_core4.ToolName.PatternDetect,
467
474
  score: 100,
468
475
  rawMetrics: {
469
476
  totalDuplicates: 0,
@@ -557,7 +564,46 @@ function calculatePatternScore(duplicates, totalFilesAnalyzed, costConfig) {
557
564
  };
558
565
  }
559
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
+
560
605
  // src/index.ts
606
+ import_core6.ToolRegistry.register(PatternDetectProvider);
561
607
  function getRefactoringSuggestion(patternType, similarity) {
562
608
  const baseMessages = {
563
609
  "api-handler": "Extract common middleware or create a base handler class",
@@ -673,7 +719,7 @@ async function analyzePatterns(options) {
673
719
  const batchContents = await Promise.all(
674
720
  batch.map(async (file) => ({
675
721
  file,
676
- content: await (0, import_core5.readFileContent)(file)
722
+ content: await (0, import_core6.readFileContent)(file)
677
723
  }))
678
724
  );
679
725
  fileContents.push(...batchContents);
@@ -694,9 +740,9 @@ async function analyzePatterns(options) {
694
740
  );
695
741
  const issues = fileDuplicates.map((dup) => {
696
742
  const otherFile = dup.file1 === file ? dup.file2 : dup.file1;
697
- const severity2 = dup.similarity > 0.95 ? import_core5.Severity.Critical : dup.similarity > 0.9 ? import_core5.Severity.Major : import_core5.Severity.Minor;
743
+ const severity2 = dup.similarity > 0.95 ? import_core6.Severity.Critical : dup.similarity > 0.9 ? import_core6.Severity.Major : import_core6.Severity.Minor;
698
744
  return {
699
- type: import_core5.IssueType.DuplicatePattern,
745
+ type: import_core6.IssueType.DuplicatePattern,
700
746
  severity: severity2,
701
747
  message: `${dup.patternType} pattern ${Math.round(dup.similarity * 100)}% similar to ${otherFile} (${dup.tokenCost} tokens wasted)`,
702
748
  location: {
@@ -709,11 +755,11 @@ async function analyzePatterns(options) {
709
755
  let filteredIssues = issues;
710
756
  if (severity !== "all") {
711
757
  const severityMap = {
712
- critical: [import_core5.Severity.Critical],
713
- high: [import_core5.Severity.Critical, import_core5.Severity.Major],
714
- medium: [import_core5.Severity.Critical, import_core5.Severity.Major, import_core5.Severity.Minor]
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]
715
761
  };
716
- const allowedSeverities = severityMap[severity] || [import_core5.Severity.Critical, import_core5.Severity.Major, import_core5.Severity.Minor];
762
+ const allowedSeverities = severityMap[severity] || [import_core6.Severity.Critical, import_core6.Severity.Major, import_core6.Severity.Minor];
717
763
  filteredIssues = issues.filter(
718
764
  (issue) => allowedSeverities.includes(issue.severity)
719
765
  );
@@ -803,6 +849,7 @@ function generateSummary(results) {
803
849
  }
804
850
  // Annotate the CommonJS export names for ESM import in node:
805
851
  0 && (module.exports = {
852
+ PatternDetectProvider,
806
853
  Severity,
807
854
  analyzePatterns,
808
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-2R7HOR5H.mjs";
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.12.3",
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.19.3"
48
+ "@aiready/core": "0.21.0"
49
49
  },
50
50
  "devDependencies": {
51
51
  "tsup": "^8.3.5",