uilint-duplicates 0.2.142 → 0.2.144

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.
@@ -2,28 +2,23 @@
2
2
  import { pluginRegistry } from "uilint-core";
3
3
 
4
4
  // src/plugin/state.ts
5
+ import { createOperationInitialState, createOperationComputed } from "uilint-core";
5
6
  var duplicatesInitialState = {
6
- indexStatus: "idle",
7
- indexProgress: null,
8
- indexStats: null,
9
- lastIndexError: null,
7
+ indexing: createOperationInitialState(),
10
8
  selectedDuplicate: null
11
9
  };
10
+ var opComputed = createOperationComputed((s) => s.indexing);
12
11
  var duplicatesStateDefinition = {
13
12
  initialState: duplicatesInitialState,
14
13
  computed: {
15
14
  /** Whether index is ready for queries */
16
- isIndexReady: (state) => state.indexStatus === "ready",
15
+ isIndexReady: opComputed.isReady,
17
16
  /** Whether indexing is in progress */
18
- isIndexing: (state) => state.indexStatus === "indexing",
17
+ isIndexing: opComputed.isActive,
19
18
  /** Whether there was an error */
20
- hasError: (state) => state.indexStatus === "error" || state.lastIndexError !== null,
19
+ hasError: opComputed.hasError,
21
20
  /** Progress percentage (0-100) */
22
- progressPercent: (state) => {
23
- if (!state.indexProgress) return 0;
24
- if (state.indexProgress.total === 0) return 0;
25
- return Math.round(state.indexProgress.current / state.indexProgress.total * 100);
26
- }
21
+ progressPercent: opComputed.progressPercent
27
22
  },
28
23
  persist: {
29
24
  key: "uilint-duplicates",
@@ -32,64 +27,25 @@ var duplicatesStateDefinition = {
32
27
  };
33
28
 
34
29
  // src/plugin/actions.ts
30
+ import { createOperationActions } from "uilint-core";
35
31
  var h = (fn) => fn;
32
+ var indexingActions = createOperationActions(
33
+ "indexing",
34
+ {
35
+ getOp: (s) => s.indexing,
36
+ setOp: (op) => ({ indexing: op })
37
+ }
38
+ );
36
39
  var duplicatesActionHandlers = {
40
+ // Spread in generated lifecycle handlers
41
+ ...indexingActions,
37
42
  /**
38
43
  * Start indexing
39
44
  */
40
45
  "start-indexing": h((ctx) => {
41
- ctx.setState({
42
- indexStatus: "indexing",
43
- indexProgress: { current: 0, total: 0 },
44
- lastIndexError: null
45
- });
46
+ ctx.dispatch("handle-indexing-start");
46
47
  ctx.websocket.send({ type: "duplicates:index" });
47
48
  }),
48
- /**
49
- * Handle indexing started
50
- */
51
- "handle-indexing-start": h((ctx) => {
52
- ctx.setState({
53
- indexStatus: "indexing",
54
- indexProgress: { current: 0, total: 0, message: "Starting..." },
55
- lastIndexError: null
56
- });
57
- }),
58
- /**
59
- * Handle indexing progress
60
- */
61
- "handle-indexing-progress": h(
62
- (ctx, payload) => {
63
- ctx.setState({
64
- indexProgress: {
65
- current: payload.current ?? 0,
66
- total: payload.total ?? 0,
67
- message: payload.message
68
- }
69
- });
70
- }
71
- ),
72
- /**
73
- * Handle indexing complete
74
- */
75
- "handle-indexing-complete": h((ctx, payload) => {
76
- ctx.setState({
77
- indexStatus: "ready",
78
- indexProgress: null,
79
- indexStats: payload,
80
- lastIndexError: null
81
- });
82
- }),
83
- /**
84
- * Handle indexing error
85
- */
86
- "handle-indexing-error": h((ctx, payload) => {
87
- ctx.setState({
88
- indexStatus: "error",
89
- indexProgress: null,
90
- lastIndexError: payload.error
91
- });
92
- }),
93
49
  /**
94
50
  * Select a duplicate for viewing in inspector
95
51
  */
@@ -258,29 +214,29 @@ var indexStatusPanelDefinition = {
258
214
  {
259
215
  type: "badge",
260
216
  variant: "status",
261
- value: { binding: "indexStatus" },
217
+ value: { binding: "indexing.status" },
262
218
  centered: true
263
219
  },
264
220
  // Progress (when indexing)
265
221
  {
266
222
  type: "conditional",
267
- condition: { expression: "indexStatus === 'indexing'" },
223
+ condition: { expression: "indexing.status === 'active'" },
268
224
  then: [
269
225
  {
270
226
  type: "progress",
271
227
  value: { binding: "progressPercent" },
272
- label: { binding: "indexProgress.message" }
228
+ label: { binding: "indexing.progress.message" }
273
229
  }
274
230
  ]
275
231
  },
276
- // Stats (when ready)
232
+ // Stats (when complete)
277
233
  {
278
234
  type: "conditional",
279
- condition: { expression: "indexStatus === 'ready' && indexStats" },
235
+ condition: { expression: "indexing.status === 'complete'" },
280
236
  then: [
281
237
  {
282
238
  type: "text",
283
- content: { binding: "indexStats.totalChunks" },
239
+ content: { binding: "indexing.stats.totalChunks" },
284
240
  variant: "body"
285
241
  }
286
242
  ]
@@ -288,11 +244,11 @@ var indexStatusPanelDefinition = {
288
244
  // Error (when error)
289
245
  {
290
246
  type: "conditional",
291
- condition: { expression: "indexStatus === 'error'" },
247
+ condition: { expression: "indexing.status === 'error'" },
292
248
  then: [
293
249
  {
294
250
  type: "text",
295
- content: { binding: "lastIndexError" },
251
+ content: { binding: "indexing.lastError" },
296
252
  variant: "error"
297
253
  }
298
254
  ]
@@ -442,44 +398,33 @@ var duplicatesRuleDefinitions = [
442
398
  ];
443
399
 
444
400
  // src/plugin/messages.ts
401
+ import { createOperationMessageHandlers } from "uilint-core";
445
402
  var duplicatesMessageHandlers = {
446
- /**
447
- * Handle indexing started
448
- */
449
- "duplicates:indexing:start": (ctx) => {
450
- ctx.dispatch("handle-indexing-start");
451
- },
452
- /**
453
- * Handle indexing progress
454
- */
455
- "duplicates:indexing:progress": (ctx, message) => {
456
- const msg = message;
457
- ctx.dispatch("handle-indexing-progress", {
458
- message: msg.message,
459
- current: msg.current,
460
- total: msg.total
461
- });
462
- },
463
- /**
464
- * Handle indexing complete
465
- */
466
- "duplicates:indexing:complete": (ctx, message) => {
467
- const msg = message;
468
- ctx.dispatch("handle-indexing-complete", {
469
- added: msg.added,
470
- modified: msg.modified,
471
- deleted: msg.deleted,
472
- totalChunks: msg.totalChunks,
473
- duration: msg.duration
474
- });
475
- },
476
- /**
477
- * Handle indexing error
478
- */
479
- "duplicates:indexing:error": (ctx, message) => {
480
- const msg = message;
481
- ctx.dispatch("handle-indexing-error", { error: msg.error });
482
- }
403
+ ...createOperationMessageHandlers({
404
+ actionPrefix: "indexing",
405
+ startMessage: "duplicates:indexing:start",
406
+ progressMessage: "duplicates:indexing:progress",
407
+ completeMessage: "duplicates:indexing:complete",
408
+ errorMessage: "duplicates:indexing:error",
409
+ extractProgress: (msg) => {
410
+ const m = msg;
411
+ return {
412
+ current: m.current ?? 0,
413
+ total: m.total ?? 0,
414
+ message: m.message
415
+ };
416
+ },
417
+ extractStats: (msg) => {
418
+ const m = msg;
419
+ return {
420
+ added: m.added,
421
+ modified: m.modified,
422
+ deleted: m.deleted,
423
+ totalChunks: m.totalChunks,
424
+ duration: m.duration
425
+ };
426
+ }
427
+ })
483
428
  };
484
429
 
485
430
  // src/plugin/index.ts
@@ -517,4 +462,4 @@ export {
517
462
  duplicatesPlugin,
518
463
  plugin_default
519
464
  };
520
- //# sourceMappingURL=chunk-XHRCN3DB.js.map
465
+ //# sourceMappingURL=chunk-3DDDYXCK.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/plugin/index.ts","../src/plugin/state.ts","../src/plugin/actions.ts","../src/plugin/commands.ts","../src/plugin/panels.ts","../src/plugin/rules.ts","../src/plugin/messages.ts"],"sourcesContent":["/**\n * Duplicates Plugin Definition\n *\n * Complete plugin export - NO REACT.\n * This is the main plugin definition that gets registered with pluginRegistry.\n */\n\nimport type { PluginWithHandlers, IssueContribution } from \"uilint-core\";\nimport { pluginRegistry } from \"uilint-core\";\n\nimport { duplicatesStateDefinition, type DuplicatesState } from \"./state.js\";\nimport { duplicatesActionHandlers } from \"./actions.js\";\nimport { duplicatesCommands } from \"./commands.js\";\nimport { duplicatesPanelDefinitions } from \"./panels.js\";\nimport { duplicatesRuleDefinitions } from \"./rules.js\";\nimport { duplicatesMessageHandlers } from \"./messages.js\";\n\n/**\n * Duplicates plugin definition\n *\n * Contains everything needed for duplicate detection EXCEPT React components.\n * The host (uilint-react) imports this and renders the appropriate UI.\n */\nexport const duplicatesPlugin: PluginWithHandlers<DuplicatesState> = {\n // === Metadata ===\n id: \"duplicates\",\n name: \"Duplicate Detection\",\n version: \"1.0.0\",\n description: \"Embedding-based semantic code duplicate detection\",\n icon: \"copy\",\n\n // === State ===\n state: duplicatesStateDefinition,\n actions: duplicatesActionHandlers,\n\n // === UI Contributions (Declarative) ===\n commands: duplicatesCommands,\n panels: duplicatesPanelDefinitions,\n\n // === Rules ===\n rules: duplicatesRuleDefinitions,\n handlesRuleCategories: [\"duplicates\"],\n\n // === WebSocket ===\n messageHandlers: duplicatesMessageHandlers,\n\n // === Issue Aggregation ===\n // Duplicate issues are reported by the no-duplicates ESLint rule.\n // They don't come from plugin state, so we return empty.\n getIssues: (_state: DuplicatesState): IssueContribution => {\n return { pluginId: \"duplicates\", issues: new Map() };\n },\n\n // === Browser Actions ===\n browserActions: [],\n};\n\n// Auto-register with plugin registry on import\npluginRegistry.register(duplicatesPlugin);\n\n// Export types for host apps\nexport type { DuplicatesState } from \"./state.js\";\n\nexport default duplicatesPlugin;\n","/**\n * Duplicates Plugin State\n *\n * State shape and initial state for the duplicates detection plugin.\n * No React - pure TypeScript.\n */\n\nimport type { StateDefinition, OperationState } from \"uilint-core\";\nimport { createOperationInitialState, createOperationComputed } from \"uilint-core\";\n\n/**\n * Index statistics\n */\nexport interface IndexStats {\n totalChunks: number;\n added: number;\n modified: number;\n deleted: number;\n duration: number;\n}\n\n/**\n * Duplicates plugin state shape\n */\nexport interface DuplicatesState {\n // === Index Operation ===\n /** Indexing operation lifecycle state */\n indexing: OperationState<IndexStats>;\n\n // === UI State ===\n /** Currently selected duplicate for inspector */\n selectedDuplicate: {\n sourceDataLoc: string;\n targetDataLoc: string;\n similarity: number;\n } | null;\n}\n\n/**\n * Initial state for the duplicates plugin\n */\nexport const duplicatesInitialState: DuplicatesState = {\n indexing: createOperationInitialState<IndexStats>(),\n selectedDuplicate: null,\n};\n\nconst opComputed = createOperationComputed<DuplicatesState>((s) => s.indexing);\n\n/**\n * State definition for the plugin system\n */\nexport const duplicatesStateDefinition: StateDefinition<DuplicatesState> = {\n initialState: duplicatesInitialState,\n\n computed: {\n /** Whether index is ready for queries */\n isIndexReady: opComputed.isReady,\n\n /** Whether indexing is in progress */\n isIndexing: opComputed.isActive,\n\n /** Whether there was an error */\n hasError: opComputed.hasError,\n\n /** Progress percentage (0-100) */\n progressPercent: opComputed.progressPercent,\n },\n\n persist: {\n key: \"uilint-duplicates\",\n include: [],\n },\n};\n","/**\n * Duplicates Plugin Action Handlers\n *\n * Plain functions that handle plugin actions.\n * No React - uses PluginContext for state management.\n */\n\nimport type { ActionHandlers, PluginContext } from \"uilint-core\";\nimport { createOperationActions } from \"uilint-core\";\nimport type { DuplicatesState, IndexStats } from \"./state.js\";\n\n// Helper type for cleaner action handler definitions\ntype Handler<TPayload = void> = (\n ctx: PluginContext<DuplicatesState>,\n payload: TPayload\n) => void | Promise<void>;\n\n// Cast helper for proper typing\nconst h = <TPayload = void>(fn: Handler<TPayload>): Handler<unknown> =>\n fn as Handler<unknown>;\n\n/**\n * Generated lifecycle action handlers for the indexing operation.\n *\n * Provides: handle-indexing-start, handle-indexing-progress,\n * handle-indexing-complete, handle-indexing-error\n */\nconst indexingActions = createOperationActions<DuplicatesState, IndexStats>(\n \"indexing\",\n {\n getOp: (s) => s.indexing,\n setOp: (op) => ({ indexing: op }),\n }\n);\n\n/**\n * Action handlers for the duplicates plugin\n */\nexport const duplicatesActionHandlers: ActionHandlers<DuplicatesState> = {\n // Spread in generated lifecycle handlers\n ...indexingActions,\n\n /**\n * Start indexing\n */\n \"start-indexing\": h((ctx) => {\n ctx.dispatch(\"handle-indexing-start\");\n ctx.websocket.send({ type: \"duplicates:index\" });\n }),\n\n /**\n * Select a duplicate for viewing in inspector\n */\n \"select-duplicate\": h<{ sourceDataLoc: string; targetDataLoc: string; similarity: number }>(\n (ctx, payload) => {\n ctx.setState({ selectedDuplicate: payload });\n ctx.openInspector(\"duplicates\", payload);\n }\n ),\n\n /**\n * Clear selected duplicate\n */\n \"clear-selected-duplicate\": h((ctx) => {\n ctx.setState({ selectedDuplicate: null });\n }),\n\n /**\n * Toggle heatmap filter for duplicates\n */\n \"toggle-heatmap-filter\": h<{ sourceDataLoc: string; targetDataLoc: string }>(\n (ctx, payload) => {\n ctx.setHeatmapFilter(\n [payload.sourceDataLoc, payload.targetDataLoc],\n \"Duplicate Code\"\n );\n }\n ),\n\n /**\n * Clear heatmap filter\n */\n \"clear-heatmap-filter\": h((ctx) => {\n ctx.clearHeatmapFilter();\n }),\n\n /**\n * Open file in editor\n */\n \"open-editor\": h<{ dataLoc: string }>((ctx, payload) => {\n ctx.openInEditor(payload.dataLoc);\n }),\n};\n","/**\n * Duplicates Plugin Commands\n *\n * Command palette commands for the duplicates plugin.\n * Declarative - no React.\n */\n\nimport type { CommandDefinition } from \"uilint-core\";\n\n/**\n * Duplicates plugin commands\n */\nexport const duplicatesCommands: CommandDefinition[] = [\n {\n id: \"duplicates:rebuild-index\",\n title: \"Rebuild Duplicates Index\",\n keywords: [\"duplicates\", \"index\", \"rebuild\", \"scan\", \"embeddings\"],\n category: \"Duplicates\",\n subtitle: \"Rebuild the semantic code index for duplicate detection\",\n icon: \"refresh\",\n action: { type: \"start-indexing\" },\n },\n {\n id: \"duplicates:clear-filter\",\n title: \"Clear Duplicate Filter\",\n keywords: [\"duplicates\", \"clear\", \"filter\", \"heatmap\"],\n category: \"Duplicates\",\n subtitle: \"Clear the heatmap filter for duplicates\",\n icon: \"x\",\n action: { type: \"clear-heatmap-filter\" },\n },\n];\n","/**\n * Duplicates Plugin Panels\n *\n * Inspector panel definitions for the duplicates plugin.\n * Declarative - no React.\n */\n\nimport type { PanelDefinition } from \"uilint-core\";\n\n/**\n * Duplicates inspector panel\n */\nexport const duplicatesPanelDefinition: PanelDefinition = {\n id: \"duplicates\",\n title: \"Duplicate Code\",\n priority: 10,\n\n loading: {\n when: { binding: \"isLoading\" },\n message: \"Loading code comparison...\",\n },\n\n empty: {\n when: { expression: \"!sourceCode && !targetCode\" },\n message: \"No duplicate information available.\",\n icon: \"search\",\n },\n\n layout: [\n // Similarity badge\n {\n type: \"badge\",\n variant: \"similarity\",\n value: { binding: \"similarity\" },\n centered: true,\n },\n\n // Source code section\n {\n type: \"code-viewer\",\n label: \"This Code\",\n icon: \"target\",\n code: {\n fetch: {\n type: \"source-code\",\n params: {\n filePath: { binding: \"sourceLocation.filePath\" },\n line: { binding: \"sourceLocation.startLine\" },\n contextAbove: 10,\n contextBelow: 10,\n },\n },\n },\n location: { binding: \"sourceLocation\" },\n diffHighlighting: true,\n maxHeight: 250,\n onNavigate: {\n type: \"open-editor\",\n payloadBindings: { dataLoc: \"sourceDataLoc\" },\n },\n },\n\n // Target code section\n {\n type: \"code-viewer\",\n label: \"Similar Code\",\n icon: \"link\",\n code: {\n fetch: {\n type: \"source-code\",\n params: {\n filePath: { binding: \"targetLocation.filePath\" },\n line: { binding: \"targetLocation.startLine\" },\n contextAbove: 10,\n contextBelow: 10,\n },\n },\n },\n location: { binding: \"targetLocation\" },\n diffHighlighting: true,\n maxHeight: 250,\n onNavigate: {\n type: \"open-editor\",\n payloadBindings: { dataLoc: \"targetDataLoc\" },\n },\n },\n\n { type: \"divider\", spacing: \"medium\" },\n\n // Actions\n {\n type: \"actions\",\n direction: \"row\",\n actions: [\n {\n id: \"toggle-heatmap\",\n label: {\n condition: { binding: \"heatmapFilterActive\" },\n true: \"Clear Heatmap Filter\",\n false: \"Focus in Heatmap\",\n },\n icon: \"filter\",\n variant: \"primary\",\n action: {\n type: \"toggle-heatmap-filter\",\n payloadBindings: {\n sourceDataLoc: \"sourceDataLoc\",\n targetDataLoc: \"targetDataLoc\",\n },\n },\n },\n ],\n },\n ],\n};\n\n/**\n * Index status panel\n */\nexport const indexStatusPanelDefinition: PanelDefinition = {\n id: \"duplicates-index-status\",\n title: \"Index Status\",\n priority: 5,\n\n layout: [\n // Status badge\n {\n type: \"badge\",\n variant: \"status\",\n value: { binding: \"indexing.status\" },\n centered: true,\n },\n\n // Progress (when indexing)\n {\n type: \"conditional\",\n condition: { expression: \"indexing.status === 'active'\" },\n then: [\n {\n type: \"progress\",\n value: { binding: \"progressPercent\" },\n label: { binding: \"indexing.progress.message\" },\n },\n ],\n },\n\n // Stats (when complete)\n {\n type: \"conditional\",\n condition: { expression: \"indexing.status === 'complete'\" },\n then: [\n {\n type: \"text\",\n content: { binding: \"indexing.stats.totalChunks\" },\n variant: \"body\",\n },\n ],\n },\n\n // Error (when error)\n {\n type: \"conditional\",\n condition: { expression: \"indexing.status === 'error'\" },\n then: [\n {\n type: \"text\",\n content: { binding: \"indexing.lastError\" },\n variant: \"error\",\n },\n ],\n },\n\n { type: \"divider\" },\n\n // Rebuild action\n {\n type: \"actions\",\n direction: \"column\",\n actions: [\n {\n id: \"rebuild-index\",\n label: \"Rebuild Index\",\n icon: \"refresh\",\n variant: \"secondary\",\n action: { type: \"start-indexing\" },\n disabled: { binding: \"isIndexing\" },\n },\n ],\n },\n ],\n};\n\n/**\n * All duplicates panel definitions\n */\nexport const duplicatesPanelDefinitions: PanelDefinition[] = [\n duplicatesPanelDefinition,\n indexStatusPanelDefinition,\n];\n","/**\n * Duplicates Plugin Rules\n *\n * Rule definitions for the duplicates plugin.\n * Declarative - no React.\n */\n\nimport type { RuleDefinition } from \"uilint-core\";\n\n/**\n * no-duplicates rule definition\n */\nexport const noDuplicatesRuleDefinition: RuleDefinition = {\n id: \"no-duplicates\",\n name: \"No Duplicates\",\n description: \"Warns when code is semantically similar to existing code\",\n category: \"duplicates\",\n icon: \"copy\",\n defaultSeverity: \"warn\",\n defaultEnabled: false,\n heatmapColor: \"#f59e0b\", // Amber\n customInspectorPanel: \"duplicates\",\n requirements: [\n {\n type: \"semantic-index\",\n description: \"Requires semantic index for duplicate detection\",\n setupHint: \"Run: uilint duplicates index\",\n },\n ],\n defaultOptions: [\n {\n threshold: 0.75,\n indexPath: \".uilint/.duplicates-index\",\n minLines: 3,\n confidenceLevel: \"low\",\n useStructuralBoost: true,\n includeSameFile: false,\n kind: \"all\",\n },\n ],\n optionSchema: {\n fields: [\n {\n key: \"threshold\",\n label: \"Similarity Threshold\",\n type: \"number\",\n defaultValue: 0.75,\n description: \"Minimum similarity score (0-1) to report as duplicate.\",\n },\n {\n key: \"confidenceLevel\",\n label: \"Minimum Confidence\",\n type: \"select\",\n defaultValue: \"low\",\n options: [\n { value: \"high\", label: \"High (>90%) - Likely copy-paste\" },\n { value: \"medium\", label: \"Medium (>75%) - Semantically similar\" },\n { value: \"low\", label: \"Low (>60%) - Possibly related\" },\n ],\n description: \"Minimum confidence level for reported duplicates.\",\n },\n {\n key: \"kind\",\n label: \"Chunk Type\",\n type: \"select\",\n defaultValue: \"all\",\n options: [\n { value: \"all\", label: \"All\" },\n { value: \"component\", label: \"Components\" },\n { value: \"hook\", label: \"Hooks\" },\n { value: \"function\", label: \"Functions\" },\n ],\n description: \"Filter duplicates by code type.\",\n },\n {\n key: \"useStructuralBoost\",\n label: \"Use Structural Analysis\",\n type: \"boolean\",\n defaultValue: true,\n description: \"Include structural similarity (props, JSX, hooks) in scoring.\",\n },\n {\n key: \"includeSameFile\",\n label: \"Include Same-File Duplicates\",\n type: \"boolean\",\n defaultValue: false,\n description: \"Report duplicates within the same file.\",\n },\n {\n key: \"minLines\",\n label: \"Minimum Lines\",\n type: \"number\",\n defaultValue: 3,\n description: \"Minimum number of lines for a code chunk.\",\n },\n ],\n },\n docs: `\n## No Duplicates Rule\n\nThis rule detects code that is semantically similar to existing code in your codebase.\n\n### How it Works\n\n1. The codebase is indexed to extract \"chunks\" (components, hooks, functions)\n2. Each chunk is embedded using an AI model to capture semantic meaning\n3. During linting, chunks are compared against the index\n4. Similar chunks above the threshold are reported\n\n### Confidence Levels\n\n- **High (>90%)**: Very likely copy-paste or near-identical code\n- **Medium (>75%)**: Semantically similar, possibly refactorable\n- **Low (>60%)**: Possibly related, worth reviewing\n\n### Setup\n\n1. Run \\`uilint duplicates index\\` to build the semantic index\n2. Enable this rule in your ESLint config\n3. The rule will report duplicates during linting\n\n### Performance\n\nThe rule uses a pre-built index, so it's fast during linting.\nRe-index periodically to keep the index up to date.\n `.trim(),\n};\n\n/**\n * All duplicates rule definitions\n */\nexport const duplicatesRuleDefinitions: RuleDefinition[] = [\n noDuplicatesRuleDefinition,\n];\n","/**\n * Duplicates Plugin Message Handlers\n *\n * WebSocket message handlers for the duplicates plugin.\n * Plain functions - no React.\n */\n\nimport type { MessageHandlers } from \"uilint-core\";\nimport { createOperationMessageHandlers } from \"uilint-core\";\nimport type { DuplicatesState } from \"./state.js\";\n\n/**\n * WebSocket message types for duplicates indexing\n */\nexport interface DuplicatesIndexingStartMessage {\n type: \"duplicates:indexing:start\";\n}\n\nexport interface DuplicatesIndexingProgressMessage {\n type: \"duplicates:indexing:progress\";\n message: string;\n current?: number;\n total?: number;\n}\n\nexport interface DuplicatesIndexingCompleteMessage {\n type: \"duplicates:indexing:complete\";\n added: number;\n modified: number;\n deleted: number;\n totalChunks: number;\n duration: number;\n}\n\nexport interface DuplicatesIndexingErrorMessage {\n type: \"duplicates:indexing:error\";\n error: string;\n}\n\nexport type DuplicatesMessage =\n | DuplicatesIndexingStartMessage\n | DuplicatesIndexingProgressMessage\n | DuplicatesIndexingCompleteMessage\n | DuplicatesIndexingErrorMessage;\n\n/**\n * Message handlers for the duplicates plugin.\n *\n * Uses the operation lifecycle framework for the standard\n * start -> progress -> complete/error message flow.\n */\nexport const duplicatesMessageHandlers: MessageHandlers<DuplicatesState> = {\n ...createOperationMessageHandlers<DuplicatesState>({\n actionPrefix: \"indexing\",\n startMessage: \"duplicates:indexing:start\",\n progressMessage: \"duplicates:indexing:progress\",\n completeMessage: \"duplicates:indexing:complete\",\n errorMessage: \"duplicates:indexing:error\",\n extractProgress: (msg) => {\n const m = msg as DuplicatesIndexingProgressMessage;\n return {\n current: m.current ?? 0,\n total: m.total ?? 0,\n message: m.message,\n };\n },\n extractStats: (msg) => {\n const m = msg as DuplicatesIndexingCompleteMessage;\n return {\n added: m.added,\n modified: m.modified,\n deleted: m.deleted,\n totalChunks: m.totalChunks,\n duration: m.duration,\n };\n },\n }),\n};\n"],"mappings":"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","names":[]}
package/dist/index.js CHANGED
@@ -53,7 +53,7 @@ import {
53
53
  } from "./chunk-7YAFHXIU.js";
54
54
  import {
55
55
  duplicatesPlugin
56
- } from "./chunk-XHRCN3DB.js";
56
+ } from "./chunk-3DDDYXCK.js";
57
57
  export {
58
58
  DEFAULT_COMBINED_SCORER_OPTIONS,
59
59
  DEFAULT_CONFIDENCE_CONFIG,
package/dist/node.js CHANGED
@@ -53,7 +53,7 @@ import {
53
53
  } from "./chunk-7YAFHXIU.js";
54
54
  import {
55
55
  duplicatesPlugin
56
- } from "./chunk-XHRCN3DB.js";
56
+ } from "./chunk-3DDDYXCK.js";
57
57
  export {
58
58
  DEFAULT_COMBINED_SCORER_OPTIONS,
59
59
  DEFAULT_CONFIDENCE_CONFIG,
@@ -1,4 +1,4 @@
1
- import { PluginWithHandlers } from 'uilint-core';
1
+ import { OperationState, PluginWithHandlers } from 'uilint-core';
2
2
 
3
3
  /**
4
4
  * Duplicates Plugin State
@@ -7,18 +7,6 @@ import { PluginWithHandlers } from 'uilint-core';
7
7
  * No React - pure TypeScript.
8
8
  */
9
9
 
10
- /**
11
- * Indexing status
12
- */
13
- type IndexStatus = "idle" | "indexing" | "ready" | "error";
14
- /**
15
- * Indexing progress
16
- */
17
- interface IndexProgress {
18
- current: number;
19
- total: number;
20
- message?: string;
21
- }
22
10
  /**
23
11
  * Index statistics
24
12
  */
@@ -33,14 +21,8 @@ interface IndexStats {
33
21
  * Duplicates plugin state shape
34
22
  */
35
23
  interface DuplicatesState {
36
- /** Current index status */
37
- indexStatus: IndexStatus;
38
- /** Indexing progress */
39
- indexProgress: IndexProgress | null;
40
- /** Index statistics from last build */
41
- indexStats: IndexStats | null;
42
- /** Last indexing error */
43
- lastIndexError: string | null;
24
+ /** Indexing operation lifecycle state */
25
+ indexing: OperationState<IndexStats>;
44
26
  /** Currently selected duplicate for inspector */
45
27
  selectedDuplicate: {
46
28
  sourceDataLoc: string;
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  duplicatesPlugin,
3
3
  plugin_default
4
- } from "../chunk-XHRCN3DB.js";
4
+ } from "../chunk-3DDDYXCK.js";
5
5
  export {
6
6
  plugin_default as default,
7
7
  duplicatesPlugin
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "uilint-duplicates",
3
- "version": "0.2.142",
3
+ "version": "0.2.144",
4
4
  "description": "Semantic code duplicate detection for React/TypeScript codebases",
5
5
  "author": "Peter Suggate",
6
6
  "repository": {
@@ -75,8 +75,8 @@
75
75
  "vitest": "^4.0.16"
76
76
  },
77
77
  "peerDependencies": {
78
- "uilint-core": "0.2.142",
79
- "uilint-eslint": "0.2.142"
78
+ "uilint-core": "0.2.144",
79
+ "uilint-eslint": "0.2.144"
80
80
  },
81
81
  "keywords": [
82
82
  "duplicate-detection",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/plugin/index.ts","../src/plugin/state.ts","../src/plugin/actions.ts","../src/plugin/commands.ts","../src/plugin/panels.ts","../src/plugin/rules.ts","../src/plugin/messages.ts"],"sourcesContent":["/**\n * Duplicates Plugin Definition\n *\n * Complete plugin export - NO REACT.\n * This is the main plugin definition that gets registered with pluginRegistry.\n */\n\nimport type { PluginWithHandlers, IssueContribution } from \"uilint-core\";\nimport { pluginRegistry } from \"uilint-core\";\n\nimport { duplicatesStateDefinition, type DuplicatesState } from \"./state.js\";\nimport { duplicatesActionHandlers } from \"./actions.js\";\nimport { duplicatesCommands } from \"./commands.js\";\nimport { duplicatesPanelDefinitions } from \"./panels.js\";\nimport { duplicatesRuleDefinitions } from \"./rules.js\";\nimport { duplicatesMessageHandlers } from \"./messages.js\";\n\n/**\n * Duplicates plugin definition\n *\n * Contains everything needed for duplicate detection EXCEPT React components.\n * The host (uilint-react) imports this and renders the appropriate UI.\n */\nexport const duplicatesPlugin: PluginWithHandlers<DuplicatesState> = {\n // === Metadata ===\n id: \"duplicates\",\n name: \"Duplicate Detection\",\n version: \"1.0.0\",\n description: \"Embedding-based semantic code duplicate detection\",\n icon: \"copy\",\n\n // === State ===\n state: duplicatesStateDefinition,\n actions: duplicatesActionHandlers,\n\n // === UI Contributions (Declarative) ===\n commands: duplicatesCommands,\n panels: duplicatesPanelDefinitions,\n\n // === Rules ===\n rules: duplicatesRuleDefinitions,\n handlesRuleCategories: [\"duplicates\"],\n\n // === WebSocket ===\n messageHandlers: duplicatesMessageHandlers,\n\n // === Issue Aggregation ===\n // Duplicate issues are reported by the no-duplicates ESLint rule.\n // They don't come from plugin state, so we return empty.\n getIssues: (_state: DuplicatesState): IssueContribution => {\n return { pluginId: \"duplicates\", issues: new Map() };\n },\n\n // === Browser Actions ===\n browserActions: [],\n};\n\n// Auto-register with plugin registry on import\npluginRegistry.register(duplicatesPlugin);\n\n// Export types for host apps\nexport type { DuplicatesState } from \"./state.js\";\n\nexport default duplicatesPlugin;\n","/**\n * Duplicates Plugin State\n *\n * State shape and initial state for the duplicates detection plugin.\n * No React - pure TypeScript.\n */\n\nimport type { StateDefinition } from \"uilint-core\";\n\n/**\n * Indexing status\n */\nexport type IndexStatus = \"idle\" | \"indexing\" | \"ready\" | \"error\";\n\n/**\n * Indexing progress\n */\nexport interface IndexProgress {\n current: number;\n total: number;\n message?: string;\n}\n\n/**\n * Index statistics\n */\nexport interface IndexStats {\n totalChunks: number;\n added: number;\n modified: number;\n deleted: number;\n duration: number;\n}\n\n/**\n * Duplicates plugin state shape\n */\nexport interface DuplicatesState {\n // === Index Status ===\n /** Current index status */\n indexStatus: IndexStatus;\n /** Indexing progress */\n indexProgress: IndexProgress | null;\n /** Index statistics from last build */\n indexStats: IndexStats | null;\n\n // === Error State ===\n /** Last indexing error */\n lastIndexError: string | null;\n\n // === UI State ===\n /** Currently selected duplicate for inspector */\n selectedDuplicate: {\n sourceDataLoc: string;\n targetDataLoc: string;\n similarity: number;\n } | null;\n}\n\n/**\n * Initial state for the duplicates plugin\n */\nexport const duplicatesInitialState: DuplicatesState = {\n indexStatus: \"idle\",\n indexProgress: null,\n indexStats: null,\n lastIndexError: null,\n selectedDuplicate: null,\n};\n\n/**\n * State definition for the plugin system\n */\nexport const duplicatesStateDefinition: StateDefinition<DuplicatesState> = {\n initialState: duplicatesInitialState,\n\n computed: {\n /** Whether index is ready for queries */\n isIndexReady: (state) => state.indexStatus === \"ready\",\n\n /** Whether indexing is in progress */\n isIndexing: (state) => state.indexStatus === \"indexing\",\n\n /** Whether there was an error */\n hasError: (state) => state.indexStatus === \"error\" || state.lastIndexError !== null,\n\n /** Progress percentage (0-100) */\n progressPercent: (state) => {\n if (!state.indexProgress) return 0;\n if (state.indexProgress.total === 0) return 0;\n return Math.round((state.indexProgress.current / state.indexProgress.total) * 100);\n },\n },\n\n persist: {\n key: \"uilint-duplicates\",\n include: [],\n },\n};\n","/**\n * Duplicates Plugin Action Handlers\n *\n * Plain functions that handle plugin actions.\n * No React - uses PluginContext for state management.\n */\n\nimport type { ActionHandlers, PluginContext } from \"uilint-core\";\nimport type { DuplicatesState, IndexStats } from \"./state.js\";\n\n// Helper type for cleaner action handler definitions\ntype Handler<TPayload = void> = (\n ctx: PluginContext<DuplicatesState>,\n payload: TPayload\n) => void | Promise<void>;\n\n// Cast helper for proper typing\nconst h = <TPayload = void>(fn: Handler<TPayload>): Handler<unknown> =>\n fn as Handler<unknown>;\n\n/**\n * Action handlers for the duplicates plugin\n */\nexport const duplicatesActionHandlers: ActionHandlers<DuplicatesState> = {\n /**\n * Start indexing\n */\n \"start-indexing\": h((ctx) => {\n ctx.setState({\n indexStatus: \"indexing\",\n indexProgress: { current: 0, total: 0 },\n lastIndexError: null,\n });\n\n ctx.websocket.send({ type: \"duplicates:index\" });\n }),\n\n /**\n * Handle indexing started\n */\n \"handle-indexing-start\": h((ctx) => {\n ctx.setState({\n indexStatus: \"indexing\",\n indexProgress: { current: 0, total: 0, message: \"Starting...\" },\n lastIndexError: null,\n });\n }),\n\n /**\n * Handle indexing progress\n */\n \"handle-indexing-progress\": h<{ message: string; current?: number; total?: number }>(\n (ctx, payload) => {\n ctx.setState({\n indexProgress: {\n current: payload.current ?? 0,\n total: payload.total ?? 0,\n message: payload.message,\n },\n });\n }\n ),\n\n /**\n * Handle indexing complete\n */\n \"handle-indexing-complete\": h<IndexStats>((ctx, payload) => {\n ctx.setState({\n indexStatus: \"ready\",\n indexProgress: null,\n indexStats: payload,\n lastIndexError: null,\n });\n }),\n\n /**\n * Handle indexing error\n */\n \"handle-indexing-error\": h<{ error: string }>((ctx, payload) => {\n ctx.setState({\n indexStatus: \"error\",\n indexProgress: null,\n lastIndexError: payload.error,\n });\n }),\n\n /**\n * Select a duplicate for viewing in inspector\n */\n \"select-duplicate\": h<{ sourceDataLoc: string; targetDataLoc: string; similarity: number }>(\n (ctx, payload) => {\n ctx.setState({ selectedDuplicate: payload });\n ctx.openInspector(\"duplicates\", payload);\n }\n ),\n\n /**\n * Clear selected duplicate\n */\n \"clear-selected-duplicate\": h((ctx) => {\n ctx.setState({ selectedDuplicate: null });\n }),\n\n /**\n * Toggle heatmap filter for duplicates\n */\n \"toggle-heatmap-filter\": h<{ sourceDataLoc: string; targetDataLoc: string }>(\n (ctx, payload) => {\n ctx.setHeatmapFilter(\n [payload.sourceDataLoc, payload.targetDataLoc],\n \"Duplicate Code\"\n );\n }\n ),\n\n /**\n * Clear heatmap filter\n */\n \"clear-heatmap-filter\": h((ctx) => {\n ctx.clearHeatmapFilter();\n }),\n\n /**\n * Open file in editor\n */\n \"open-editor\": h<{ dataLoc: string }>((ctx, payload) => {\n ctx.openInEditor(payload.dataLoc);\n }),\n};\n","/**\n * Duplicates Plugin Commands\n *\n * Command palette commands for the duplicates plugin.\n * Declarative - no React.\n */\n\nimport type { CommandDefinition } from \"uilint-core\";\n\n/**\n * Duplicates plugin commands\n */\nexport const duplicatesCommands: CommandDefinition[] = [\n {\n id: \"duplicates:rebuild-index\",\n title: \"Rebuild Duplicates Index\",\n keywords: [\"duplicates\", \"index\", \"rebuild\", \"scan\", \"embeddings\"],\n category: \"Duplicates\",\n subtitle: \"Rebuild the semantic code index for duplicate detection\",\n icon: \"refresh\",\n action: { type: \"start-indexing\" },\n },\n {\n id: \"duplicates:clear-filter\",\n title: \"Clear Duplicate Filter\",\n keywords: [\"duplicates\", \"clear\", \"filter\", \"heatmap\"],\n category: \"Duplicates\",\n subtitle: \"Clear the heatmap filter for duplicates\",\n icon: \"x\",\n action: { type: \"clear-heatmap-filter\" },\n },\n];\n","/**\n * Duplicates Plugin Panels\n *\n * Inspector panel definitions for the duplicates plugin.\n * Declarative - no React.\n */\n\nimport type { PanelDefinition } from \"uilint-core\";\n\n/**\n * Duplicates inspector panel\n */\nexport const duplicatesPanelDefinition: PanelDefinition = {\n id: \"duplicates\",\n title: \"Duplicate Code\",\n priority: 10,\n\n loading: {\n when: { binding: \"isLoading\" },\n message: \"Loading code comparison...\",\n },\n\n empty: {\n when: { expression: \"!sourceCode && !targetCode\" },\n message: \"No duplicate information available.\",\n icon: \"search\",\n },\n\n layout: [\n // Similarity badge\n {\n type: \"badge\",\n variant: \"similarity\",\n value: { binding: \"similarity\" },\n centered: true,\n },\n\n // Source code section\n {\n type: \"code-viewer\",\n label: \"This Code\",\n icon: \"target\",\n code: {\n fetch: {\n type: \"source-code\",\n params: {\n filePath: { binding: \"sourceLocation.filePath\" },\n line: { binding: \"sourceLocation.startLine\" },\n contextAbove: 10,\n contextBelow: 10,\n },\n },\n },\n location: { binding: \"sourceLocation\" },\n diffHighlighting: true,\n maxHeight: 250,\n onNavigate: {\n type: \"open-editor\",\n payloadBindings: { dataLoc: \"sourceDataLoc\" },\n },\n },\n\n // Target code section\n {\n type: \"code-viewer\",\n label: \"Similar Code\",\n icon: \"link\",\n code: {\n fetch: {\n type: \"source-code\",\n params: {\n filePath: { binding: \"targetLocation.filePath\" },\n line: { binding: \"targetLocation.startLine\" },\n contextAbove: 10,\n contextBelow: 10,\n },\n },\n },\n location: { binding: \"targetLocation\" },\n diffHighlighting: true,\n maxHeight: 250,\n onNavigate: {\n type: \"open-editor\",\n payloadBindings: { dataLoc: \"targetDataLoc\" },\n },\n },\n\n { type: \"divider\", spacing: \"medium\" },\n\n // Actions\n {\n type: \"actions\",\n direction: \"row\",\n actions: [\n {\n id: \"toggle-heatmap\",\n label: {\n condition: { binding: \"heatmapFilterActive\" },\n true: \"Clear Heatmap Filter\",\n false: \"Focus in Heatmap\",\n },\n icon: \"filter\",\n variant: \"primary\",\n action: {\n type: \"toggle-heatmap-filter\",\n payloadBindings: {\n sourceDataLoc: \"sourceDataLoc\",\n targetDataLoc: \"targetDataLoc\",\n },\n },\n },\n ],\n },\n ],\n};\n\n/**\n * Index status panel\n */\nexport const indexStatusPanelDefinition: PanelDefinition = {\n id: \"duplicates-index-status\",\n title: \"Index Status\",\n priority: 5,\n\n layout: [\n // Status badge\n {\n type: \"badge\",\n variant: \"status\",\n value: { binding: \"indexStatus\" },\n centered: true,\n },\n\n // Progress (when indexing)\n {\n type: \"conditional\",\n condition: { expression: \"indexStatus === 'indexing'\" },\n then: [\n {\n type: \"progress\",\n value: { binding: \"progressPercent\" },\n label: { binding: \"indexProgress.message\" },\n },\n ],\n },\n\n // Stats (when ready)\n {\n type: \"conditional\",\n condition: { expression: \"indexStatus === 'ready' && indexStats\" },\n then: [\n {\n type: \"text\",\n content: { binding: \"indexStats.totalChunks\" },\n variant: \"body\",\n },\n ],\n },\n\n // Error (when error)\n {\n type: \"conditional\",\n condition: { expression: \"indexStatus === 'error'\" },\n then: [\n {\n type: \"text\",\n content: { binding: \"lastIndexError\" },\n variant: \"error\",\n },\n ],\n },\n\n { type: \"divider\" },\n\n // Rebuild action\n {\n type: \"actions\",\n direction: \"column\",\n actions: [\n {\n id: \"rebuild-index\",\n label: \"Rebuild Index\",\n icon: \"refresh\",\n variant: \"secondary\",\n action: { type: \"start-indexing\" },\n disabled: { binding: \"isIndexing\" },\n },\n ],\n },\n ],\n};\n\n/**\n * All duplicates panel definitions\n */\nexport const duplicatesPanelDefinitions: PanelDefinition[] = [\n duplicatesPanelDefinition,\n indexStatusPanelDefinition,\n];\n","/**\n * Duplicates Plugin Rules\n *\n * Rule definitions for the duplicates plugin.\n * Declarative - no React.\n */\n\nimport type { RuleDefinition } from \"uilint-core\";\n\n/**\n * no-duplicates rule definition\n */\nexport const noDuplicatesRuleDefinition: RuleDefinition = {\n id: \"no-duplicates\",\n name: \"No Duplicates\",\n description: \"Warns when code is semantically similar to existing code\",\n category: \"duplicates\",\n icon: \"copy\",\n defaultSeverity: \"warn\",\n defaultEnabled: false,\n heatmapColor: \"#f59e0b\", // Amber\n customInspectorPanel: \"duplicates\",\n requirements: [\n {\n type: \"semantic-index\",\n description: \"Requires semantic index for duplicate detection\",\n setupHint: \"Run: uilint duplicates index\",\n },\n ],\n defaultOptions: [\n {\n threshold: 0.75,\n indexPath: \".uilint/.duplicates-index\",\n minLines: 3,\n confidenceLevel: \"low\",\n useStructuralBoost: true,\n includeSameFile: false,\n kind: \"all\",\n },\n ],\n optionSchema: {\n fields: [\n {\n key: \"threshold\",\n label: \"Similarity Threshold\",\n type: \"number\",\n defaultValue: 0.75,\n description: \"Minimum similarity score (0-1) to report as duplicate.\",\n },\n {\n key: \"confidenceLevel\",\n label: \"Minimum Confidence\",\n type: \"select\",\n defaultValue: \"low\",\n options: [\n { value: \"high\", label: \"High (>90%) - Likely copy-paste\" },\n { value: \"medium\", label: \"Medium (>75%) - Semantically similar\" },\n { value: \"low\", label: \"Low (>60%) - Possibly related\" },\n ],\n description: \"Minimum confidence level for reported duplicates.\",\n },\n {\n key: \"kind\",\n label: \"Chunk Type\",\n type: \"select\",\n defaultValue: \"all\",\n options: [\n { value: \"all\", label: \"All\" },\n { value: \"component\", label: \"Components\" },\n { value: \"hook\", label: \"Hooks\" },\n { value: \"function\", label: \"Functions\" },\n ],\n description: \"Filter duplicates by code type.\",\n },\n {\n key: \"useStructuralBoost\",\n label: \"Use Structural Analysis\",\n type: \"boolean\",\n defaultValue: true,\n description: \"Include structural similarity (props, JSX, hooks) in scoring.\",\n },\n {\n key: \"includeSameFile\",\n label: \"Include Same-File Duplicates\",\n type: \"boolean\",\n defaultValue: false,\n description: \"Report duplicates within the same file.\",\n },\n {\n key: \"minLines\",\n label: \"Minimum Lines\",\n type: \"number\",\n defaultValue: 3,\n description: \"Minimum number of lines for a code chunk.\",\n },\n ],\n },\n docs: `\n## No Duplicates Rule\n\nThis rule detects code that is semantically similar to existing code in your codebase.\n\n### How it Works\n\n1. The codebase is indexed to extract \"chunks\" (components, hooks, functions)\n2. Each chunk is embedded using an AI model to capture semantic meaning\n3. During linting, chunks are compared against the index\n4. Similar chunks above the threshold are reported\n\n### Confidence Levels\n\n- **High (>90%)**: Very likely copy-paste or near-identical code\n- **Medium (>75%)**: Semantically similar, possibly refactorable\n- **Low (>60%)**: Possibly related, worth reviewing\n\n### Setup\n\n1. Run \\`uilint duplicates index\\` to build the semantic index\n2. Enable this rule in your ESLint config\n3. The rule will report duplicates during linting\n\n### Performance\n\nThe rule uses a pre-built index, so it's fast during linting.\nRe-index periodically to keep the index up to date.\n `.trim(),\n};\n\n/**\n * All duplicates rule definitions\n */\nexport const duplicatesRuleDefinitions: RuleDefinition[] = [\n noDuplicatesRuleDefinition,\n];\n","/**\n * Duplicates Plugin Message Handlers\n *\n * WebSocket message handlers for the duplicates plugin.\n * Plain functions - no React.\n */\n\nimport type { MessageHandlers, PluginContext } from \"uilint-core\";\nimport type { DuplicatesState } from \"./state.js\";\n\n/**\n * WebSocket message types for duplicates indexing\n */\nexport interface DuplicatesIndexingStartMessage {\n type: \"duplicates:indexing:start\";\n}\n\nexport interface DuplicatesIndexingProgressMessage {\n type: \"duplicates:indexing:progress\";\n message: string;\n current?: number;\n total?: number;\n}\n\nexport interface DuplicatesIndexingCompleteMessage {\n type: \"duplicates:indexing:complete\";\n added: number;\n modified: number;\n deleted: number;\n totalChunks: number;\n duration: number;\n}\n\nexport interface DuplicatesIndexingErrorMessage {\n type: \"duplicates:indexing:error\";\n error: string;\n}\n\nexport type DuplicatesMessage =\n | DuplicatesIndexingStartMessage\n | DuplicatesIndexingProgressMessage\n | DuplicatesIndexingCompleteMessage\n | DuplicatesIndexingErrorMessage;\n\n/**\n * Message handlers for the duplicates plugin\n */\nexport const duplicatesMessageHandlers: MessageHandlers<DuplicatesState> = {\n /**\n * Handle indexing started\n */\n \"duplicates:indexing:start\": (ctx: PluginContext<DuplicatesState>) => {\n ctx.dispatch(\"handle-indexing-start\");\n },\n\n /**\n * Handle indexing progress\n */\n \"duplicates:indexing:progress\": (\n ctx: PluginContext<DuplicatesState>,\n message: unknown\n ) => {\n const msg = message as DuplicatesIndexingProgressMessage;\n ctx.dispatch(\"handle-indexing-progress\", {\n message: msg.message,\n current: msg.current,\n total: msg.total,\n });\n },\n\n /**\n * Handle indexing complete\n */\n \"duplicates:indexing:complete\": (\n ctx: PluginContext<DuplicatesState>,\n message: unknown\n ) => {\n const msg = message as DuplicatesIndexingCompleteMessage;\n ctx.dispatch(\"handle-indexing-complete\", {\n added: msg.added,\n modified: msg.modified,\n deleted: msg.deleted,\n totalChunks: msg.totalChunks,\n duration: msg.duration,\n });\n },\n\n /**\n * Handle indexing error\n */\n \"duplicates:indexing:error\": (\n ctx: PluginContext<DuplicatesState>,\n message: unknown\n ) => {\n const msg = message as DuplicatesIndexingErrorMessage;\n ctx.dispatch(\"handle-indexing-error\", { error: msg.error });\n },\n};\n"],"mappings":"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","names":[]}