uilint-duplicates 0.2.156 → 0.2.158

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.
@@ -1473,6 +1473,8 @@ var IncrementalIndexer = class {
1473
1473
  "Ollama is not available. Make sure it's running at " + (this.options.baseUrl || "http://localhost:11434")
1474
1474
  );
1475
1475
  }
1476
+ log("Checking embedding model...");
1477
+ await this.embeddingClient.ensureModel();
1476
1478
  if (force) {
1477
1479
  this.vectorStore.clear();
1478
1480
  this.metadataStore.clear();
@@ -1504,6 +1506,8 @@ var IncrementalIndexer = class {
1504
1506
  if (!available) {
1505
1507
  throw new Error("Ollama is not available");
1506
1508
  }
1509
+ log("Checking embedding model...");
1510
+ await this.embeddingClient.ensureModel();
1507
1511
  log("Detecting changes...");
1508
1512
  const files = await this.findFiles();
1509
1513
  const changes = await this.fileTracker.detectChanges(files);
@@ -2545,4 +2549,4 @@ export {
2545
2549
  getRecommendedAction,
2546
2550
  formatCombinedScore
2547
2551
  };
2548
- //# sourceMappingURL=chunk-7YAFHXIU.js.map
2552
+ //# sourceMappingURL=chunk-F2HSHCUO.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/embeddings/chunker.ts","../src/embeddings/ollama-embeddings.ts","../src/query/api.ts","../src/cache/incremental-indexer.ts","../src/index/vector-store.ts","../src/index/metadata-store.ts","../src/cache/file-tracker.ts","../src/detection/scorer.ts","../src/detection/structural-scorer.ts","../src/detection/confidence.ts","../src/detection/duplicate-finder.ts","../src/detection/normalizer.ts","../src/detection/combined-scorer.ts"],"sourcesContent":["/**\n * Code chunker - extracts meaningful code units from TypeScript/TSX files\n *\n * Uses @typescript-eslint/typescript-estree for parsing.\n * Supports splitting large components into smaller, embeddable chunks.\n */\n\nimport { parse, TSESTree, AST_NODE_TYPES } from \"@typescript-eslint/typescript-estree\";\nimport type { CodeChunk, ChunkKind, ChunkMetadata, ChunkingOptions } from \"./types.js\";\n\nconst DEFAULT_MAX_LINES = 100;\nconst MIN_SECTION_LINES = 3;\n\n/**\n * Hash function for generating chunk IDs\n * Simple djb2 hash - consistent with existing codebase pattern\n */\nfunction hashChunk(content: string, filePath: string, startLine: number): string {\n let hash = 5381;\n const input = `${filePath}:${startLine}:${content}`;\n for (let i = 0; i < input.length; i++) {\n hash = (hash * 33) ^ input.charCodeAt(i);\n }\n return (hash >>> 0).toString(16).padStart(8, \"0\");\n}\n\n/**\n * Parse a file and extract code chunks\n */\nexport function chunkFile(\n filePath: string,\n content: string,\n options: ChunkingOptions = {}\n): CodeChunk[] {\n const {\n minLines = 3,\n maxLines = DEFAULT_MAX_LINES,\n includeAnonymous = false,\n kinds,\n splitStrategy = \"jsx-children\",\n } = options;\n\n // Parse the file\n let ast: TSESTree.Program;\n try {\n ast = parse(content, {\n jsx: true,\n loc: true,\n range: true,\n tokens: false,\n comment: false,\n });\n } catch (error) {\n // Return empty array if parsing fails\n console.warn(`Failed to parse ${filePath}:`, error);\n return [];\n }\n\n const chunks: CodeChunk[] = [];\n const lines = content.split(\"\\n\");\n\n // Track exports for metadata\n const exportedNames = new Set<string>();\n let defaultExportName: string | null = null;\n\n // First pass: collect exports\n for (const node of ast.body) {\n if (node.type === AST_NODE_TYPES.ExportNamedDeclaration) {\n if (node.declaration) {\n const names = getDeclarationNames(node.declaration);\n names.forEach((name) => exportedNames.add(name));\n }\n if (node.specifiers) {\n node.specifiers.forEach((spec) => {\n if (spec.type === AST_NODE_TYPES.ExportSpecifier) {\n exportedNames.add(\n spec.exported.type === AST_NODE_TYPES.Identifier\n ? spec.exported.name\n : spec.exported.value\n );\n }\n });\n }\n } else if (node.type === AST_NODE_TYPES.ExportDefaultDeclaration) {\n if (node.declaration.type === AST_NODE_TYPES.Identifier) {\n defaultExportName = node.declaration.name;\n } else if (\n node.declaration.type === AST_NODE_TYPES.FunctionDeclaration &&\n node.declaration.id\n ) {\n defaultExportName = node.declaration.id.name;\n }\n }\n }\n\n // Second pass: extract chunks\n function visit(node: TSESTree.Node) {\n // Check function declarations\n if (node.type === AST_NODE_TYPES.FunctionDeclaration && node.id) {\n const chunk = processFunction(\n node,\n node.id.name,\n filePath,\n content,\n lines,\n exportedNames,\n defaultExportName\n );\n if (chunk && shouldIncludeChunk(chunk, minLines, includeAnonymous, kinds)) {\n // Check if chunk needs splitting\n const lineCount = chunk.endLine - chunk.startLine + 1;\n if (lineCount > maxLines && splitStrategy !== \"none\") {\n const splitChunks = splitLargeChunk(node, chunk, content, lines, maxLines, splitStrategy);\n chunks.push(...splitChunks.filter(c => shouldIncludeChunk(c, minLines, includeAnonymous, kinds)));\n } else {\n chunks.push(chunk);\n }\n }\n }\n\n // Check variable declarations with arrow functions\n if (node.type === AST_NODE_TYPES.VariableDeclaration) {\n for (const decl of node.declarations) {\n if (\n decl.id.type === AST_NODE_TYPES.Identifier &&\n decl.init &&\n (decl.init.type === AST_NODE_TYPES.ArrowFunctionExpression ||\n decl.init.type === AST_NODE_TYPES.FunctionExpression)\n ) {\n const chunk = processFunction(\n decl.init,\n decl.id.name,\n filePath,\n content,\n lines,\n exportedNames,\n defaultExportName,\n node // Use the variable declaration for location\n );\n if (chunk && shouldIncludeChunk(chunk, minLines, includeAnonymous, kinds)) {\n // Check if chunk needs splitting\n const lineCount = chunk.endLine - chunk.startLine + 1;\n if (lineCount > maxLines && splitStrategy !== \"none\") {\n const splitChunks = splitLargeChunk(decl.init, chunk, content, lines, maxLines, splitStrategy);\n chunks.push(...splitChunks.filter(c => shouldIncludeChunk(c, minLines, includeAnonymous, kinds)));\n } else {\n chunks.push(chunk);\n }\n }\n }\n }\n }\n\n // Recursively visit children\n for (const key of Object.keys(node)) {\n if (key === \"parent\" || key === \"loc\" || key === \"range\") continue;\n\n const child = (node as unknown as Record<string, unknown>)[key];\n if (child && typeof child === \"object\") {\n if (Array.isArray(child)) {\n child.forEach((c) => {\n if (c && typeof c === \"object\" && \"type\" in c) {\n visit(c as TSESTree.Node);\n }\n });\n } else if (\"type\" in child) {\n visit(child as TSESTree.Node);\n }\n }\n }\n }\n\n visit(ast);\n return chunks;\n}\n\nfunction processFunction(\n node:\n | TSESTree.FunctionDeclaration\n | TSESTree.ArrowFunctionExpression\n | TSESTree.FunctionExpression,\n name: string,\n filePath: string,\n content: string,\n lines: string[],\n exportedNames: Set<string>,\n defaultExportName: string | null,\n locationNode?: TSESTree.Node\n): CodeChunk | null {\n const loc = (locationNode || node).loc;\n if (!loc) return null;\n\n const startLine = loc.start.line;\n const endLine = loc.end.line;\n const startColumn = loc.start.column;\n const endColumn = loc.end.column;\n\n // Extract the chunk content\n const chunkContent = lines.slice(startLine - 1, endLine).join(\"\\n\");\n\n // Determine the kind\n const kind = classifyFunction(name, node);\n\n // Extract metadata\n const metadata = extractMetadata(node, name, exportedNames, defaultExportName);\n\n return {\n id: hashChunk(chunkContent, filePath, startLine),\n filePath,\n startLine,\n endLine,\n startColumn,\n endColumn,\n kind,\n name,\n content: chunkContent,\n metadata,\n };\n}\n\nfunction classifyFunction(\n name: string,\n node:\n | TSESTree.FunctionDeclaration\n | TSESTree.ArrowFunctionExpression\n | TSESTree.FunctionExpression\n): ChunkKind {\n // Check for hook (useXxx pattern)\n if (/^use[A-Z]/.test(name)) {\n return \"hook\";\n }\n\n // Check for component (PascalCase + returns JSX)\n if (/^[A-Z]/.test(name) && containsJSX(node)) {\n return \"component\";\n }\n\n // Check for JSX fragment (returns JSX but not PascalCase)\n if (containsJSX(node)) {\n return \"jsx-fragment\";\n }\n\n return \"function\";\n}\n\nfunction containsJSX(node: TSESTree.Node): boolean {\n let found = false;\n\n function search(n: TSESTree.Node) {\n if (found) return;\n if (n.type === AST_NODE_TYPES.JSXElement || n.type === AST_NODE_TYPES.JSXFragment) {\n found = true;\n return;\n }\n for (const key of Object.keys(n)) {\n if (key === \"parent\" || key === \"loc\" || key === \"range\") continue;\n\n const child = (n as unknown as Record<string, unknown>)[key];\n if (child && typeof child === \"object\") {\n if (Array.isArray(child)) {\n child.forEach((c) => {\n if (c && typeof c === \"object\" && \"type\" in c) {\n search(c as TSESTree.Node);\n }\n });\n } else if (\"type\" in child) {\n search(child as TSESTree.Node);\n }\n }\n }\n }\n\n search(node);\n return found;\n}\n\nfunction extractMetadata(\n node:\n | TSESTree.FunctionDeclaration\n | TSESTree.ArrowFunctionExpression\n | TSESTree.FunctionExpression,\n name: string,\n exportedNames: Set<string>,\n defaultExportName: string | null\n): ChunkMetadata {\n const metadata: ChunkMetadata = {\n isExported: exportedNames.has(name) || defaultExportName === name,\n isDefaultExport: defaultExportName === name,\n };\n\n // Extract props from parameters\n const params = node.params;\n if (params.length > 0) {\n const firstParam = params[0];\n const props = extractPropsFromParam(firstParam);\n if (props.length > 0) {\n metadata.props = props;\n }\n }\n\n // Extract hooks and JSX elements\n const hooks: string[] = [];\n const jsxElements: string[] = [];\n\n function searchForHooksAndJSX(n: TSESTree.Node) {\n // Find hook calls\n if (\n n.type === AST_NODE_TYPES.CallExpression &&\n n.callee.type === AST_NODE_TYPES.Identifier &&\n /^use[A-Z]/.test(n.callee.name)\n ) {\n hooks.push(n.callee.name);\n }\n\n // Find JSX elements\n if (n.type === AST_NODE_TYPES.JSXOpeningElement) {\n if (n.name.type === AST_NODE_TYPES.JSXIdentifier) {\n jsxElements.push(n.name.name);\n } else if (n.name.type === AST_NODE_TYPES.JSXMemberExpression) {\n // Handle React.Fragment, etc.\n const parts: string[] = [];\n let current: TSESTree.JSXMemberExpression | TSESTree.JSXIdentifier = n.name;\n while (current.type === AST_NODE_TYPES.JSXMemberExpression) {\n if (current.property.type === AST_NODE_TYPES.JSXIdentifier) {\n parts.unshift(current.property.name);\n }\n current = current.object as TSESTree.JSXMemberExpression | TSESTree.JSXIdentifier;\n }\n if (current.type === AST_NODE_TYPES.JSXIdentifier) {\n parts.unshift(current.name);\n }\n jsxElements.push(parts.join(\".\"));\n }\n }\n\n // Recurse\n for (const key of Object.keys(n)) {\n if (key === \"parent\" || key === \"loc\" || key === \"range\") continue;\n\n const child = (n as unknown as Record<string, unknown>)[key];\n if (child && typeof child === \"object\") {\n if (Array.isArray(child)) {\n child.forEach((c) => {\n if (c && typeof c === \"object\" && \"type\" in c) {\n searchForHooksAndJSX(c as TSESTree.Node);\n }\n });\n } else if (\"type\" in child) {\n searchForHooksAndJSX(child as TSESTree.Node);\n }\n }\n }\n }\n\n searchForHooksAndJSX(node);\n\n if (hooks.length > 0) {\n metadata.hooks = [...new Set(hooks)]; // Deduplicate\n }\n if (jsxElements.length > 0) {\n metadata.jsxElements = [...new Set(jsxElements)]; // Deduplicate\n }\n\n return metadata;\n}\n\nfunction extractPropsFromParam(param: TSESTree.Parameter): string[] {\n const props: string[] = [];\n\n if (param.type === AST_NODE_TYPES.ObjectPattern) {\n for (const prop of param.properties) {\n if (prop.type === AST_NODE_TYPES.Property && prop.key.type === AST_NODE_TYPES.Identifier) {\n props.push(prop.key.name);\n } else if (\n prop.type === AST_NODE_TYPES.RestElement &&\n prop.argument.type === AST_NODE_TYPES.Identifier\n ) {\n props.push(`...${prop.argument.name}`);\n }\n }\n } else if (param.type === AST_NODE_TYPES.Identifier) {\n props.push(param.name);\n }\n\n return props;\n}\n\nfunction getDeclarationNames(\n decl:\n | TSESTree.FunctionDeclaration\n | TSESTree.VariableDeclaration\n | TSESTree.ClassDeclaration\n | TSESTree.TSInterfaceDeclaration\n | TSESTree.TSTypeAliasDeclaration\n | TSESTree.TSEnumDeclaration\n | TSESTree.TSModuleDeclaration\n | TSESTree.TSDeclareFunction\n | TSESTree.TSImportEqualsDeclaration\n): string[] {\n const names: string[] = [];\n\n if (decl.type === AST_NODE_TYPES.FunctionDeclaration && decl.id) {\n names.push(decl.id.name);\n } else if (decl.type === AST_NODE_TYPES.VariableDeclaration) {\n for (const d of decl.declarations) {\n if (d.id.type === AST_NODE_TYPES.Identifier) {\n names.push(d.id.name);\n }\n }\n } else if (decl.type === AST_NODE_TYPES.ClassDeclaration && decl.id) {\n names.push(decl.id.name);\n }\n\n return names;\n}\n\nfunction shouldIncludeChunk(\n chunk: CodeChunk,\n minLines: number,\n includeAnonymous: boolean,\n kinds?: ChunkKind[]\n): boolean {\n const lineCount = chunk.endLine - chunk.startLine + 1;\n if (lineCount < minLines) {\n return false;\n }\n if (!includeAnonymous && chunk.name === null) {\n return false;\n }\n if (kinds && !kinds.includes(chunk.kind)) {\n return false;\n }\n return true;\n}\n\n/** Maximum characters for embedding input (safe limit for nomic-embed-text with 2048 token context) */\nconst DEFAULT_MAX_EMBEDDING_CHARS = 6000;\n\nexport interface EmbeddingInputOptions {\n /** Maximum characters for the embedding input (default: 6000) */\n maxChars?: number;\n}\n\n/**\n * Prepare chunk content for embedding by enriching with context\n */\nexport function prepareEmbeddingInput(\n chunk: CodeChunk,\n options: EmbeddingInputOptions = {}\n): string {\n const { maxChars = DEFAULT_MAX_EMBEDDING_CHARS } = options;\n const parts: string[] = [];\n\n // Add structural context based on kind\n if (chunk.kind === \"component\") {\n parts.push(`React component: ${chunk.name || \"anonymous\"}`);\n if (chunk.metadata.props?.length) {\n parts.push(`Props: ${chunk.metadata.props.join(\", \")}`);\n }\n } else if (chunk.kind === \"component-summary\") {\n parts.push(`React component summary: ${chunk.name || \"anonymous\"}`);\n if (chunk.metadata.props?.length) {\n parts.push(`Props: ${chunk.metadata.props.join(\", \")}`);\n }\n parts.push(\"(Large component - see sections for JSX details)\");\n } else if (chunk.kind === \"jsx-section\") {\n const parentName = chunk.name || \"anonymous\";\n const label = chunk.sectionLabel || `section-${chunk.sectionIndex}`;\n parts.push(`JSX section from ${parentName}: ${label}`);\n } else if (chunk.kind === \"hook\") {\n parts.push(`React hook: ${chunk.name || \"anonymous\"}`);\n } else if (chunk.kind === \"function\") {\n parts.push(`Function: ${chunk.name || \"anonymous\"}`);\n } else if (chunk.kind === \"function-summary\") {\n parts.push(`Function summary: ${chunk.name || \"anonymous\"}`);\n parts.push(\"(Large function - split into sections)\");\n } else if (chunk.kind === \"function-section\") {\n const parentName = chunk.name || \"anonymous\";\n const label = chunk.sectionLabel || `section-${chunk.sectionIndex}`;\n parts.push(`Function section from ${parentName}: ${label}`);\n } else if (chunk.kind === \"jsx-fragment\") {\n parts.push(`JSX fragment: ${chunk.name || \"anonymous\"}`);\n }\n\n // Add the code\n parts.push(chunk.content);\n\n // Add JSX structure for components\n if (chunk.metadata.jsxElements?.length) {\n parts.push(`JSX elements: ${chunk.metadata.jsxElements.join(\", \")}`);\n }\n\n // Add hooks used\n if (chunk.metadata.hooks?.length) {\n parts.push(`Hooks used: ${chunk.metadata.hooks.join(\", \")}`);\n }\n\n let result = parts.join(\"\\n\\n\");\n\n // Truncate if exceeds max chars (safety net for edge cases)\n if (result.length > maxChars) {\n result = result.slice(0, maxChars - 50) + \"\\n\\n[... content truncated for embedding ...]\";\n }\n\n return result;\n}\n\n// ============================================================================\n// Large Component Splitting\n// ============================================================================\n\n/**\n * Split a large chunk into smaller chunks\n * For components, tries JSX-based splitting first, then falls back to line-based\n * For functions/hooks, uses line-based splitting\n */\nfunction splitLargeChunk(\n node: TSESTree.FunctionDeclaration | TSESTree.ArrowFunctionExpression | TSESTree.FunctionExpression,\n originalChunk: CodeChunk,\n content: string,\n lines: string[],\n maxLines: number,\n strategy: \"jsx-children\" | \"line-based\"\n): CodeChunk[] {\n // Only try JSX splitting for components\n if (strategy === \"jsx-children\" && originalChunk.kind === \"component\") {\n const jsxChunks = splitByJSXChildren(node, originalChunk, content, lines);\n if (jsxChunks.length > 0) {\n return jsxChunks;\n }\n // Fall back to line-based if no JSX children found\n }\n\n return splitByLines(originalChunk, lines, maxLines);\n}\n\n/**\n * Split a component by its top-level JSX children\n */\nfunction splitByJSXChildren(\n node: TSESTree.FunctionDeclaration | TSESTree.ArrowFunctionExpression | TSESTree.FunctionExpression,\n originalChunk: CodeChunk,\n content: string,\n lines: string[]\n): CodeChunk[] {\n // Find the return statement with JSX\n const returnStatement = findJSXReturnStatement(node);\n if (!returnStatement || !returnStatement.argument) {\n return [];\n }\n\n // Get the root JSX element\n const jsxRoot = getJSXRoot(returnStatement.argument);\n if (!jsxRoot) {\n return [];\n }\n\n // Get significant JSX children\n const children = getSignificantJSXChildren(jsxRoot);\n if (children.length < 2) {\n // Not worth splitting if there's only one child\n return [];\n }\n\n const chunks: CodeChunk[] = [];\n\n // Create a summary chunk (signature + hooks + state, without the full JSX)\n const summaryChunk = createSummaryChunk(node, originalChunk, returnStatement, lines);\n chunks.push(summaryChunk);\n\n // Create section chunks for each significant JSX child\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n const sectionChunk = createJSXSectionChunk(\n originalChunk,\n child,\n lines,\n i,\n summaryChunk.id\n );\n if (sectionChunk) {\n chunks.push(sectionChunk);\n }\n }\n\n return chunks;\n}\n\n/**\n * Find the return statement containing JSX\n */\nfunction findJSXReturnStatement(\n node: TSESTree.FunctionDeclaration | TSESTree.ArrowFunctionExpression | TSESTree.FunctionExpression\n): TSESTree.ReturnStatement | null {\n // For arrow functions with expression body, create a synthetic return\n if (node.type === AST_NODE_TYPES.ArrowFunctionExpression && node.expression) {\n if (isJSXNode(node.body)) {\n return {\n type: AST_NODE_TYPES.ReturnStatement,\n argument: node.body as TSESTree.Expression,\n loc: node.body.loc,\n range: node.body.range,\n parent: node as unknown as TSESTree.Node,\n } as TSESTree.ReturnStatement;\n }\n return null;\n }\n\n // For function bodies, find the return statement\n const body = node.body;\n if (body.type !== AST_NODE_TYPES.BlockStatement) {\n return null;\n }\n\n // Look for return statements in the body (not nested in other blocks)\n for (const stmt of body.body) {\n if (stmt.type === AST_NODE_TYPES.ReturnStatement && stmt.argument && isJSXNode(stmt.argument)) {\n return stmt;\n }\n }\n\n return null;\n}\n\n/**\n * Check if a node is a JSX element or fragment\n */\nfunction isJSXNode(node: TSESTree.Node): boolean {\n return (\n node.type === AST_NODE_TYPES.JSXElement ||\n node.type === AST_NODE_TYPES.JSXFragment\n );\n}\n\n/**\n * Get the root JSX element, unwrapping parentheses and fragments if needed\n */\nfunction getJSXRoot(\n node: TSESTree.Expression\n): TSESTree.JSXElement | TSESTree.JSXFragment | null {\n // Handle parenthesized expressions\n if (node.type === AST_NODE_TYPES.JSXElement) {\n return node;\n }\n if (node.type === AST_NODE_TYPES.JSXFragment) {\n return node;\n }\n return null;\n}\n\n/**\n * Get significant JSX children (skip whitespace-only text nodes)\n */\nfunction getSignificantJSXChildren(\n jsxRoot: TSESTree.JSXElement | TSESTree.JSXFragment\n): TSESTree.JSXChild[] {\n const children: TSESTree.JSXChild[] = [];\n\n for (const child of jsxRoot.children) {\n // Skip JSXText that's just whitespace\n if (child.type === AST_NODE_TYPES.JSXText) {\n if (child.value.trim() === \"\") {\n continue;\n }\n }\n\n // Include JSX elements, expressions, and non-empty text\n if (\n child.type === AST_NODE_TYPES.JSXElement ||\n child.type === AST_NODE_TYPES.JSXFragment ||\n child.type === AST_NODE_TYPES.JSXExpressionContainer\n ) {\n children.push(child);\n }\n }\n\n return children;\n}\n\n/**\n * Create a summary chunk containing function signature, hooks, and state\n */\nfunction createSummaryChunk(\n node: TSESTree.FunctionDeclaration | TSESTree.ArrowFunctionExpression | TSESTree.FunctionExpression,\n originalChunk: CodeChunk,\n returnStatement: TSESTree.ReturnStatement,\n lines: string[]\n): CodeChunk {\n // Get lines from function start to just before the return statement\n const startLine = originalChunk.startLine;\n const returnLine = returnStatement.loc?.start.line || originalChunk.endLine;\n\n // Include the first line of the return (e.g., \"return (\") but not the JSX body\n const summaryEndLine = Math.min(returnLine, originalChunk.endLine);\n\n // Extract the summary content\n const summaryLines = lines.slice(startLine - 1, summaryEndLine);\n\n // Add closing brace to make it syntactically valid-ish\n const summaryContent = summaryLines.join(\"\\n\") + \"\\n // ... JSX content (see sections)\\n );\";\n\n return {\n id: hashChunk(summaryContent, originalChunk.filePath, startLine),\n filePath: originalChunk.filePath,\n startLine: startLine,\n endLine: summaryEndLine,\n startColumn: originalChunk.startColumn,\n endColumn: originalChunk.endColumn,\n kind: \"component-summary\",\n name: originalChunk.name,\n content: summaryContent,\n metadata: {\n ...originalChunk.metadata,\n // Keep hooks but clear JSX elements (they're in the sections)\n jsxElements: undefined,\n },\n };\n}\n\n/**\n * Create a JSX section chunk from a JSX child element\n */\nfunction createJSXSectionChunk(\n originalChunk: CodeChunk,\n jsxChild: TSESTree.JSXChild,\n lines: string[],\n index: number,\n parentId: string\n): CodeChunk | null {\n const loc = jsxChild.loc;\n if (!loc) {\n return null;\n }\n\n const startLine = loc.start.line;\n const endLine = loc.end.line;\n const lineCount = endLine - startLine + 1;\n\n // Skip very small sections\n if (lineCount < MIN_SECTION_LINES) {\n return null;\n }\n\n // Extract the content\n const sectionContent = lines.slice(startLine - 1, endLine).join(\"\\n\");\n\n // Infer a label from the JSX element\n const label = inferSectionLabel(jsxChild, index);\n\n // Extract JSX elements in this section\n const jsxElements = extractJSXElementsFromNode(jsxChild);\n\n return {\n id: hashChunk(sectionContent, originalChunk.filePath, startLine),\n filePath: originalChunk.filePath,\n startLine,\n endLine,\n startColumn: loc.start.column,\n endColumn: loc.end.column,\n kind: \"jsx-section\",\n name: originalChunk.name,\n content: sectionContent,\n metadata: {\n jsxElements: jsxElements.length > 0 ? jsxElements : undefined,\n isExported: originalChunk.metadata.isExported,\n isDefaultExport: originalChunk.metadata.isDefaultExport,\n },\n parentId,\n sectionIndex: index,\n sectionLabel: label,\n };\n}\n\n/**\n * Infer a human-readable label for a JSX section\n */\nfunction inferSectionLabel(jsxChild: TSESTree.JSXChild, index: number): string {\n if (jsxChild.type === AST_NODE_TYPES.JSXElement) {\n const opening = jsxChild.openingElement;\n\n // Try to get a meaningful name from attributes\n for (const attr of opening.attributes) {\n if (attr.type === AST_NODE_TYPES.JSXAttribute && attr.name.type === AST_NODE_TYPES.JSXIdentifier) {\n const attrName = attr.name.name;\n\n // Look for common identifying attributes\n if (attrName === \"aria-label\" || attrName === \"aria-labelledby\") {\n if (attr.value?.type === AST_NODE_TYPES.Literal && typeof attr.value.value === \"string\") {\n return attr.value.value.toLowerCase().replace(/\\s+/g, \"-\").slice(0, 30);\n }\n }\n\n // Check className for semantic hints\n if (attrName === \"className\" || attrName === \"class\") {\n if (attr.value?.type === AST_NODE_TYPES.Literal && typeof attr.value.value === \"string\") {\n const className = attr.value.value;\n // Extract first meaningful class\n const classes = className.split(/\\s+/);\n for (const cls of classes) {\n // Skip utility classes (Tailwind patterns)\n if (!cls.match(/^(bg-|text-|p-|m-|w-|h-|flex|grid|border|rounded|shadow|hover:|focus:)/)) {\n return cls.slice(0, 30);\n }\n }\n }\n }\n }\n }\n\n // Fall back to element name\n if (opening.name.type === AST_NODE_TYPES.JSXIdentifier) {\n return `${opening.name.name}-${index}`;\n }\n }\n\n return `section-${index}`;\n}\n\n/**\n * Extract JSX element names from a node\n */\nfunction extractJSXElementsFromNode(node: TSESTree.Node): string[] {\n const elements: string[] = [];\n\n function search(n: TSESTree.Node) {\n if (n.type === AST_NODE_TYPES.JSXOpeningElement) {\n if (n.name.type === AST_NODE_TYPES.JSXIdentifier) {\n elements.push(n.name.name);\n } else if (n.name.type === AST_NODE_TYPES.JSXMemberExpression) {\n const parts: string[] = [];\n let current: TSESTree.JSXMemberExpression | TSESTree.JSXIdentifier = n.name;\n while (current.type === AST_NODE_TYPES.JSXMemberExpression) {\n if (current.property.type === AST_NODE_TYPES.JSXIdentifier) {\n parts.unshift(current.property.name);\n }\n current = current.object as TSESTree.JSXMemberExpression | TSESTree.JSXIdentifier;\n }\n if (current.type === AST_NODE_TYPES.JSXIdentifier) {\n parts.unshift(current.name);\n }\n elements.push(parts.join(\".\"));\n }\n }\n\n // Recurse\n for (const key of Object.keys(n)) {\n if (key === \"parent\" || key === \"loc\" || key === \"range\") continue;\n\n const child = (n as unknown as Record<string, unknown>)[key];\n if (child && typeof child === \"object\") {\n if (Array.isArray(child)) {\n child.forEach((c) => {\n if (c && typeof c === \"object\" && \"type\" in c) {\n search(c as TSESTree.Node);\n }\n });\n } else if (\"type\" in child) {\n search(child as TSESTree.Node);\n }\n }\n }\n }\n\n search(node);\n return [...new Set(elements)];\n}\n\n/**\n * Split a chunk by line count (fallback strategy)\n */\nfunction splitByLines(\n originalChunk: CodeChunk,\n lines: string[],\n maxLines: number\n): CodeChunk[] {\n const totalLines = originalChunk.endLine - originalChunk.startLine + 1;\n\n // If it fits, return as-is\n if (totalLines <= maxLines) {\n return [originalChunk];\n }\n\n // Determine the appropriate kinds based on original chunk type\n const isComponent = originalChunk.kind === \"component\" || originalChunk.kind === \"jsx-fragment\";\n const summaryKind: ChunkKind = isComponent ? \"component-summary\" : \"function-summary\";\n const sectionKind: ChunkKind = isComponent ? \"jsx-section\" : \"function-section\";\n\n const chunks: CodeChunk[] = [];\n const overlap = Math.min(10, Math.floor(maxLines / 5)); // 10 lines overlap, or 20% of maxLines\n\n let currentStart = originalChunk.startLine;\n let sectionIndex = 0;\n\n while (currentStart <= originalChunk.endLine) {\n const currentEnd = Math.min(currentStart + maxLines - 1, originalChunk.endLine);\n const sectionContent = lines.slice(currentStart - 1, currentEnd).join(\"\\n\");\n\n const isFirstSection = sectionIndex === 0;\n\n chunks.push({\n id: hashChunk(sectionContent, originalChunk.filePath, currentStart),\n filePath: originalChunk.filePath,\n startLine: currentStart,\n endLine: currentEnd,\n startColumn: isFirstSection ? originalChunk.startColumn : 0,\n endColumn: currentEnd === originalChunk.endLine ? originalChunk.endColumn : lines[currentEnd - 1]?.length || 0,\n kind: isFirstSection ? summaryKind : sectionKind,\n name: originalChunk.name,\n content: sectionContent,\n metadata: isFirstSection ? originalChunk.metadata : {\n isExported: originalChunk.metadata.isExported,\n isDefaultExport: originalChunk.metadata.isDefaultExport,\n },\n parentId: isFirstSection ? undefined : chunks[0]?.id,\n sectionIndex: isFirstSection ? undefined : sectionIndex,\n sectionLabel: isFirstSection ? undefined : `lines-${currentStart}-${currentEnd}`,\n });\n\n // Move to next section with overlap\n currentStart = currentEnd - overlap + 1;\n sectionIndex++;\n\n // Prevent infinite loop\n if (currentStart <= originalChunk.startLine + sectionIndex * (maxLines - overlap)) {\n currentStart = originalChunk.startLine + sectionIndex * (maxLines - overlap);\n }\n }\n\n return chunks;\n}\n","/**\n * Ollama Embedding Client\n *\n * Uses Ollama's /api/embed endpoint to generate text embeddings.\n * Follows the patterns from uilint-core's OllamaClient.\n */\n\nconst DEFAULT_BASE_URL = \"http://localhost:11434\";\nconst DEFAULT_MODEL = \"nomic-embed-text\";\nconst DEFAULT_TIMEOUT = 60000;\nconst DEFAULT_BATCH_SIZE = 10;\n\nexport interface EmbeddingOptions {\n /** Ollama embedding model (default: nomic-embed-text) */\n model?: string;\n /** Ollama server URL (default: http://localhost:11434) */\n baseUrl?: string;\n /** Request timeout in ms (default: 60000) */\n timeout?: number;\n /** Batch size for embedding multiple texts (default: 10) */\n batchSize?: number;\n}\n\nexport interface EmbeddingResult {\n /** The embedding vector */\n embedding: number[];\n /** The model used */\n model: string;\n /** Number of tokens in the input (if available) */\n promptTokens?: number;\n}\n\nexport class OllamaEmbeddingClient {\n private baseUrl: string;\n private model: string;\n private timeout: number;\n private batchSize: number;\n\n constructor(options: EmbeddingOptions = {}) {\n this.baseUrl = options.baseUrl || DEFAULT_BASE_URL;\n this.model = options.model || DEFAULT_MODEL;\n this.timeout = options.timeout || DEFAULT_TIMEOUT;\n this.batchSize = options.batchSize || DEFAULT_BATCH_SIZE;\n }\n\n /**\n * Generate embedding for a single text\n */\n async embed(text: string): Promise<EmbeddingResult> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n const response = await fetch(`${this.baseUrl}/api/embed`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n model: this.model,\n input: text,\n }),\n signal: controller.signal,\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Ollama API error (${response.status}): ${errorText}`);\n }\n\n const data = await response.json();\n\n // Ollama returns embeddings in an array even for single input\n const embedding = data.embeddings?.[0] || data.embedding;\n\n if (!embedding || !Array.isArray(embedding)) {\n throw new Error(\"Invalid embedding response from Ollama\");\n }\n\n return {\n embedding,\n model: this.model,\n promptTokens: data.prompt_eval_count,\n };\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n /**\n * Generate embeddings for multiple texts\n * Automatically batches large inputs\n */\n async embedBatch(texts: string[]): Promise<EmbeddingResult[]> {\n if (texts.length === 0) {\n return [];\n }\n\n // If small enough, embed all at once\n if (texts.length <= this.batchSize) {\n return this.embedBatchDirect(texts);\n }\n\n // Otherwise, process in batches\n const results: EmbeddingResult[] = [];\n for (let i = 0; i < texts.length; i += this.batchSize) {\n const batch = texts.slice(i, i + this.batchSize);\n const batchResults = await this.embedBatchDirect(batch);\n results.push(...batchResults);\n }\n return results;\n }\n\n /**\n * Embed a batch directly (no chunking)\n */\n private async embedBatchDirect(texts: string[]): Promise<EmbeddingResult[]> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n const response = await fetch(`${this.baseUrl}/api/embed`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n model: this.model,\n input: texts,\n }),\n signal: controller.signal,\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Ollama API error (${response.status}): ${errorText}`);\n }\n\n const data = await response.json();\n const embeddings: number[][] = data.embeddings;\n\n if (!embeddings || !Array.isArray(embeddings)) {\n throw new Error(\"Invalid batch embedding response from Ollama\");\n }\n\n return embeddings.map((embedding) => ({\n embedding,\n model: this.model,\n }));\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n /**\n * Check if Ollama is available\n */\n async isAvailable(): Promise<boolean> {\n try {\n const response = await fetch(`${this.baseUrl}/api/tags`, {\n method: \"GET\",\n signal: AbortSignal.timeout(5000),\n });\n return response.ok;\n } catch {\n return false;\n }\n }\n\n /**\n * Check if the embedding model is available\n */\n async isModelAvailable(): Promise<boolean> {\n try {\n const response = await fetch(`${this.baseUrl}/api/tags`, {\n method: \"GET\",\n signal: AbortSignal.timeout(5000),\n });\n\n if (!response.ok) return false;\n\n const data = await response.json();\n const models = data.models || [];\n\n return models.some(\n (m: { name: string }) =>\n m.name === this.model || m.name.startsWith(`${this.model}:`)\n );\n } catch {\n return false;\n }\n }\n\n /**\n * Pull the embedding model if not available\n */\n async ensureModel(): Promise<void> {\n const available = await this.isModelAvailable();\n if (available) return;\n\n console.log(`Pulling embedding model ${this.model}...`);\n\n const response = await fetch(`${this.baseUrl}/api/pull`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n model: this.model,\n stream: false,\n }),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Failed to pull model ${this.model}: ${errorText}`);\n }\n }\n\n /**\n * Get the embedding dimension for the current model\n * (Requires generating a test embedding)\n */\n async getEmbeddingDimension(): Promise<number> {\n const result = await this.embed(\"test\");\n return result.embedding.length;\n }\n\n /**\n * Get the current model name\n */\n getModel(): string {\n return this.model;\n }\n\n /**\n * Set the model name\n */\n setModel(model: string): void {\n this.model = model;\n }\n}\n\n// Default singleton instance\nlet defaultClient: OllamaEmbeddingClient | null = null;\n\nexport function getOllamaEmbeddingClient(\n options?: EmbeddingOptions\n): OllamaEmbeddingClient {\n if (!defaultClient || options) {\n defaultClient = new OllamaEmbeddingClient(options);\n }\n return defaultClient;\n}\n","/**\n * Query API for semantic duplicate detection\n *\n * High-level API for indexing, finding duplicates, and semantic search.\n */\n\nimport { resolve } from \"path\";\nimport type { ChunkKind } from \"../embeddings/types.js\";\nimport {\n IncrementalIndexer,\n createIndexer,\n type IndexerOptions,\n type IndexUpdateResult,\n} from \"../cache/incremental-indexer.js\";\nimport {\n findDuplicateGroups,\n findSimilarToLocation,\n findSimilarToQuery,\n} from \"../detection/duplicate-finder.js\";\nimport { OllamaEmbeddingClient } from \"../embeddings/ollama-embeddings.js\";\n\nexport interface IndexOptions {\n /** Embedding model to use */\n model?: string;\n /** Ollama server URL */\n baseUrl?: string;\n /** Glob patterns to exclude */\n exclude?: string[];\n /** Force reindex from scratch */\n force?: boolean;\n /** Progress callback */\n onProgress?: (message: string, current?: number, total?: number) => void;\n}\n\nexport interface FindDuplicatesOptions {\n /** Path to search (defaults to current directory) */\n path?: string;\n /** Minimum similarity threshold (0-1). Default: 0.75 */\n threshold?: number;\n /** Minimum group size. Default: 2 */\n minGroupSize?: number;\n /** Filter by kind: component, hook, function */\n kind?: ChunkKind;\n /** Minimum confidence level: \"high\", \"medium\", \"low\". Default: \"low\" */\n confidenceLevel?: \"high\" | \"medium\" | \"low\";\n /** Use structural similarity boost. Default: true */\n useStructuralBoost?: boolean;\n /** Include duplicates within the same file. Default: true */\n includeSameFile?: boolean;\n}\n\nexport interface SearchOptions {\n /** Path to search (defaults to current directory) */\n path?: string;\n /** Number of results to return. Default: 10 */\n top?: number;\n /** Minimum similarity threshold. Default: 0.5 */\n threshold?: number;\n /** Embedding model to use */\n model?: string;\n /** Ollama server URL */\n baseUrl?: string;\n}\n\nexport interface SimilarLocationOptions extends SearchOptions {\n /** File path containing the code */\n filePath: string;\n /** Line number in the file */\n line: number;\n}\n\nexport interface DuplicateGroupMember {\n /** File path */\n filePath: string;\n /** Start line */\n startLine: number;\n /** End line */\n endLine: number;\n /** Chunk name (component/function/hook name) */\n name: string | null;\n /** Kind of code */\n kind: ChunkKind;\n /** Similarity score (1.0 for the reference member) */\n score: number;\n}\n\nexport interface DuplicateGroup {\n /** Members of the duplicate group */\n members: DuplicateGroupMember[];\n /** Average similarity between all group members */\n avgSimilarity: number;\n /** The kind of code in this group */\n kind: ChunkKind;\n /** Confidence level for this group */\n confidence: \"high\" | \"medium\" | \"low\";\n}\n\nexport interface SearchResult {\n /** File path */\n filePath: string;\n /** Start line */\n startLine: number;\n /** End line */\n endLine: number;\n /** Chunk name */\n name: string | null;\n /** Kind of code */\n kind: ChunkKind;\n /** Similarity score */\n score: number;\n}\n\n// Cache for loaded indexers to avoid reloading on every query\nconst indexerCache = new Map<string, IncrementalIndexer>();\n\n/**\n * Get or create an indexer for a project path.\n */\nfunction getIndexer(path: string, options?: IndexerOptions): IncrementalIndexer {\n const projectRoot = resolve(path);\n const cacheKey = projectRoot;\n\n let indexer = indexerCache.get(cacheKey);\n if (!indexer) {\n indexer = createIndexer(projectRoot, options);\n indexerCache.set(cacheKey, indexer);\n }\n\n return indexer;\n}\n\n/**\n * Clear the indexer cache for a path.\n */\nexport function clearIndexerCache(path?: string): void {\n if (path) {\n const projectRoot = resolve(path);\n indexerCache.delete(projectRoot);\n } else {\n indexerCache.clear();\n }\n}\n\n/**\n * Index a directory for semantic duplicate detection.\n * Creates or updates the index at .uilint/.duplicates-index/\n */\nexport async function indexDirectory(\n path: string,\n options: IndexOptions = {}\n): Promise<IndexUpdateResult> {\n const projectRoot = resolve(path);\n\n // Clear cache to ensure fresh indexer\n clearIndexerCache(projectRoot);\n\n const indexer = createIndexer(projectRoot, {\n model: options.model,\n baseUrl: options.baseUrl,\n exclude: options.exclude,\n onProgress: options.onProgress,\n });\n\n // Update cache\n indexerCache.set(projectRoot, indexer);\n\n if (options.force) {\n return await indexer.indexAll(true);\n }\n\n // Try incremental update first, fall back to full index\n if (indexer.hasIndex()) {\n return await indexer.update();\n }\n\n return await indexer.indexAll(false);\n}\n\n/**\n * Find semantic duplicate groups in the indexed codebase.\n */\nexport async function findDuplicates(\n options: FindDuplicatesOptions = {}\n): Promise<DuplicateGroup[]> {\n const projectRoot = resolve(options.path || process.cwd());\n const indexer = getIndexer(projectRoot);\n\n // Load the index\n await indexer.load();\n\n if (!indexer.hasIndex()) {\n throw new Error(\n `No index found at ${projectRoot}. Run 'uilint duplicates index' first.`\n );\n }\n\n const vectorStore = indexer.getVectorStore();\n const metadataStore = indexer.getMetadataStore();\n\n const groups = findDuplicateGroups(vectorStore, metadataStore, {\n threshold: options.threshold ?? 0.75,\n minGroupSize: options.minGroupSize,\n kind: options.kind,\n confidenceFilter: options.confidenceLevel,\n useStructuralBoost: options.useStructuralBoost ?? true,\n includeSameFile: options.includeSameFile ?? true,\n });\n\n // Transform to public API format\n return groups.map((group) => ({\n members: group.members.map((m) => ({\n filePath: m.metadata.filePath,\n startLine: m.metadata.startLine,\n endLine: m.metadata.endLine,\n name: m.metadata.name,\n kind: m.metadata.kind,\n score: m.score,\n })),\n avgSimilarity: group.avgSimilarity,\n kind: group.kind,\n confidence: group.confidence,\n }));\n}\n\n/**\n * Search for code semantically similar to a text query.\n */\nexport async function searchSimilar(\n query: string,\n options: SearchOptions = {}\n): Promise<SearchResult[]> {\n const projectRoot = resolve(options.path || process.cwd());\n const indexer = getIndexer(projectRoot);\n\n // Load the index\n await indexer.load();\n\n if (!indexer.hasIndex()) {\n throw new Error(\n `No index found at ${projectRoot}. Run 'uilint duplicates index' first.`\n );\n }\n\n // Create embedding client\n const embeddingClient = new OllamaEmbeddingClient({\n model: options.model,\n baseUrl: options.baseUrl,\n });\n\n // Embed the query\n const queryResult = await embeddingClient.embed(query);\n\n const vectorStore = indexer.getVectorStore();\n const metadataStore = indexer.getMetadataStore();\n\n const results = findSimilarToQuery(vectorStore, queryResult.embedding, {\n top: options.top,\n threshold: options.threshold,\n });\n\n // Transform to public API format\n return results\n .map((r) => {\n const metadata = metadataStore.get(r.id);\n if (!metadata) return null;\n return {\n filePath: metadata.filePath,\n startLine: metadata.startLine,\n endLine: metadata.endLine,\n name: metadata.name,\n kind: metadata.kind,\n score: r.score,\n };\n })\n .filter((r): r is SearchResult => r !== null);\n}\n\n/**\n * Find code similar to a specific location (file:line).\n */\nexport async function findSimilarAtLocation(\n options: SimilarLocationOptions\n): Promise<SearchResult[]> {\n const projectRoot = resolve(options.path || process.cwd());\n const indexer = getIndexer(projectRoot);\n\n // Load the index\n await indexer.load();\n\n if (!indexer.hasIndex()) {\n throw new Error(\n `No index found at ${projectRoot}. Run 'uilint duplicates index' first.`\n );\n }\n\n const vectorStore = indexer.getVectorStore();\n const metadataStore = indexer.getMetadataStore();\n\n const results = findSimilarToLocation(\n vectorStore,\n metadataStore,\n options.filePath,\n options.line,\n {\n top: options.top,\n threshold: options.threshold,\n }\n );\n\n // Transform to public API format\n return results\n .map((r) => {\n const metadata = metadataStore.get(r.id);\n if (!metadata) return null;\n return {\n filePath: metadata.filePath,\n startLine: metadata.startLine,\n endLine: metadata.endLine,\n name: metadata.name,\n kind: metadata.kind,\n score: r.score,\n };\n })\n .filter((r): r is SearchResult => r !== null);\n}\n\n/**\n * Check if an index exists for the given path.\n */\nexport function hasIndex(path: string = process.cwd()): boolean {\n const projectRoot = resolve(path);\n const indexer = getIndexer(projectRoot);\n return indexer.hasIndex();\n}\n\n/**\n * Get index statistics.\n */\nexport async function getIndexStats(path: string = process.cwd()): Promise<{\n totalFiles: number;\n totalChunks: number;\n indexSizeBytes: number;\n embeddingModel: string | null;\n lastUpdated: string | null;\n}> {\n const projectRoot = resolve(path);\n const indexer = getIndexer(projectRoot);\n\n await indexer.load();\n\n const stats = indexer.getStats();\n return {\n totalFiles: stats.totalFiles,\n totalChunks: stats.totalChunks,\n indexSizeBytes: stats.indexSizeBytes,\n embeddingModel: stats.manifest?.embeddingModel || null,\n lastUpdated: stats.manifest?.updatedAt || null,\n };\n}\n","/**\n * Incremental Indexer\n *\n * Combines chunker, embedding client, and storage to build and update\n * the semantic index incrementally.\n */\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"fs\";\nimport { join, relative } from \"path\";\nimport { glob } from \"glob\";\nimport { chunkFile, prepareEmbeddingInput } from \"../embeddings/chunker.js\";\nimport { OllamaEmbeddingClient } from \"../embeddings/ollama-embeddings.js\";\nimport { VectorStore } from \"../index/vector-store.js\";\nimport { MetadataStore } from \"../index/metadata-store.js\";\nimport {\n FileTracker,\n hashContentSync,\n type FileChange,\n} from \"./file-tracker.js\";\nimport type { ChunkingOptions } from \"../embeddings/types.js\";\nimport type { IndexManifest, StoredChunkMetadata } from \"../index/types.js\";\n\nconst INDEX_DIR = \".uilint/.duplicates-index\";\nconst MANIFEST_FILE = \"manifest.json\";\nconst MANIFEST_VERSION = 1;\n\nexport interface IndexerOptions {\n /** Embedding model to use */\n model?: string;\n /** Ollama server URL */\n baseUrl?: string;\n /** Glob patterns to include (default: **\\/*.{ts,tsx,js,jsx}) */\n include?: string[];\n /** Glob patterns to exclude */\n exclude?: string[];\n /** Chunking options */\n chunking?: ChunkingOptions;\n /** Progress callback */\n onProgress?: (message: string, current?: number, total?: number) => void;\n}\n\nexport interface IndexUpdateResult {\n /** Number of files added */\n added: number;\n /** Number of files modified */\n modified: number;\n /** Number of files deleted */\n deleted: number;\n /** Total chunks in index */\n totalChunks: number;\n /** Duration in milliseconds */\n duration: number;\n}\n\nexport class IncrementalIndexer {\n private vectorStore: VectorStore;\n private metadataStore: MetadataStore;\n private fileTracker: FileTracker;\n private embeddingClient: OllamaEmbeddingClient;\n private projectRoot: string;\n private indexDir: string;\n private options: IndexerOptions;\n private manifest: IndexManifest | null = null;\n\n constructor(projectRoot: string, options: IndexerOptions = {}) {\n this.projectRoot = projectRoot;\n this.indexDir = join(projectRoot, INDEX_DIR);\n this.options = options;\n\n this.vectorStore = new VectorStore();\n this.metadataStore = new MetadataStore();\n this.fileTracker = new FileTracker();\n this.embeddingClient = new OllamaEmbeddingClient({\n model: options.model,\n baseUrl: options.baseUrl,\n });\n }\n\n /**\n * Get the include patterns\n */\n private getIncludePatterns(): string[] {\n return this.options.include || [\"**/*.{ts,tsx,js,jsx}\"];\n }\n\n /**\n * Get the exclude patterns\n */\n private getExcludePatterns(): string[] {\n return [\n \"**/node_modules/**\",\n \"**/dist/**\",\n \"**/build/**\",\n \"**/.git/**\",\n \"**/*.test.{ts,tsx,js,jsx}\",\n \"**/*.spec.{ts,tsx,js,jsx}\",\n \"**/__tests__/**\",\n ...(this.options.exclude || []),\n ];\n }\n\n /**\n * Find all files to index\n */\n private async findFiles(): Promise<string[]> {\n const files: string[] = [];\n\n for (const pattern of this.getIncludePatterns()) {\n const matches = await glob(pattern, {\n cwd: this.projectRoot,\n ignore: this.getExcludePatterns(),\n absolute: true,\n nodir: true,\n });\n files.push(...matches);\n }\n\n return [...new Set(files)]; // Dedupe\n }\n\n /**\n * Load existing index from disk\n */\n async load(): Promise<void> {\n if (!existsSync(this.indexDir)) {\n return;\n }\n\n try {\n // Load manifest\n const manifestPath = join(this.indexDir, MANIFEST_FILE);\n if (existsSync(manifestPath)) {\n const content = readFileSync(manifestPath, \"utf-8\");\n this.manifest = JSON.parse(content);\n }\n\n // Load stores\n await this.vectorStore.load(this.indexDir);\n await this.metadataStore.load(this.indexDir);\n await this.fileTracker.load(this.indexDir);\n } catch {\n // If loading fails, start fresh\n this.vectorStore = new VectorStore();\n this.metadataStore = new MetadataStore();\n this.fileTracker = new FileTracker();\n this.manifest = null;\n }\n }\n\n /**\n * Save index to disk\n */\n async save(): Promise<void> {\n if (!existsSync(this.indexDir)) {\n mkdirSync(this.indexDir, { recursive: true });\n }\n\n // Update and save manifest\n const now = new Date().toISOString();\n const dimension = this.vectorStore.getDimension();\n\n this.manifest = {\n version: MANIFEST_VERSION,\n createdAt: this.manifest?.createdAt || now,\n updatedAt: now,\n embeddingModel: this.embeddingClient.getModel(),\n dimension: dimension || 0,\n fileCount: this.fileTracker.getTrackedFiles().length,\n chunkCount: this.metadataStore.size(),\n };\n\n const manifestPath = join(this.indexDir, MANIFEST_FILE);\n writeFileSync(\n manifestPath,\n JSON.stringify(this.manifest, null, 2),\n \"utf-8\"\n );\n\n // Save stores\n await this.vectorStore.save(this.indexDir);\n await this.metadataStore.save(this.indexDir);\n await this.fileTracker.save(this.indexDir);\n }\n\n /**\n * Index all files from scratch\n */\n async indexAll(force: boolean = false): Promise<IndexUpdateResult> {\n const startTime = Date.now();\n const log = this.options.onProgress || (() => {});\n\n // Check if Ollama is available\n const available = await this.embeddingClient.isAvailable();\n if (!available) {\n throw new Error(\n \"Ollama is not available. Make sure it's running at \" +\n (this.options.baseUrl || \"http://localhost:11434\")\n );\n }\n\n // Ensure embedding model is pulled (auto-pulls on first run)\n log(\"Checking embedding model...\");\n await this.embeddingClient.ensureModel();\n\n // Clear existing index if force\n if (force) {\n this.vectorStore.clear();\n this.metadataStore.clear();\n this.fileTracker.clear();\n } else {\n await this.load();\n }\n\n // Find files\n log(\"Finding files...\");\n const files = await this.findFiles();\n log(`Found ${files.length} files`);\n\n // Detect changes\n const changes = force\n ? files.map((path) => ({ path, type: \"added\" as const, newHash: \"\" }))\n : await this.fileTracker.detectChanges(files);\n\n // Process changes\n const result = await this.processChanges(changes, log);\n\n // Save index\n log(\"Saving index...\");\n await this.save();\n\n return {\n ...result,\n duration: Date.now() - startTime,\n };\n }\n\n /**\n * Update index incrementally\n */\n async update(): Promise<IndexUpdateResult> {\n const startTime = Date.now();\n const log = this.options.onProgress || (() => {});\n\n // Load existing index\n await this.load();\n\n // Check if Ollama is available\n const available = await this.embeddingClient.isAvailable();\n if (!available) {\n throw new Error(\"Ollama is not available\");\n }\n\n // Ensure embedding model is pulled (auto-pulls on first run)\n log(\"Checking embedding model...\");\n await this.embeddingClient.ensureModel();\n\n // Find files and detect changes\n log(\"Detecting changes...\");\n const files = await this.findFiles();\n const changes = await this.fileTracker.detectChanges(files);\n\n if (changes.length === 0) {\n log(\"No changes detected\");\n return {\n added: 0,\n modified: 0,\n deleted: 0,\n totalChunks: this.metadataStore.size(),\n duration: Date.now() - startTime,\n };\n }\n\n log(`Found ${changes.length} changed files`);\n\n // Process changes\n const result = await this.processChanges(changes, log);\n\n // Save index\n log(\"Saving index...\");\n await this.save();\n\n return {\n ...result,\n duration: Date.now() - startTime,\n };\n }\n\n /**\n * Process file changes\n */\n private async processChanges(\n changes: FileChange[],\n log: (msg: string, current?: number, total?: number) => void\n ): Promise<Omit<IndexUpdateResult, \"duration\">> {\n let added = 0;\n let modified = 0;\n let deleted = 0;\n\n // Handle deletions first\n const deletedFiles = changes.filter((c) => c.type === \"deleted\");\n for (const change of deletedFiles) {\n const removedIds = this.metadataStore.removeByFilePath(change.path);\n for (const id of removedIds) {\n this.vectorStore.remove(id);\n }\n this.fileTracker.removeEntry(change.path);\n deleted++;\n }\n\n // Handle additions and modifications\n const filesToProcess = changes.filter((c) => c.type !== \"deleted\");\n\n for (let i = 0; i < filesToProcess.length; i++) {\n const change = filesToProcess[i];\n log(\n `Processing ${relative(this.projectRoot, change.path)}`,\n i + 1,\n filesToProcess.length\n );\n\n try {\n // Read file content\n const content = readFileSync(change.path, \"utf-8\");\n\n // Remove old chunks if modified\n if (change.type === \"modified\") {\n const removedIds = this.metadataStore.removeByFilePath(change.path);\n for (const id of removedIds) {\n this.vectorStore.remove(id);\n }\n modified++;\n } else {\n added++;\n }\n\n // Chunk the file\n const chunks = chunkFile(change.path, content, this.options.chunking);\n\n if (chunks.length === 0) {\n // No chunks to embed, but still track the file\n await this.fileTracker.updateFile(change.path, content, []);\n continue;\n }\n\n // Prepare embedding inputs\n const embeddingInputs = chunks.map((c) => prepareEmbeddingInput(c));\n\n // Generate embeddings\n const embeddings =\n await this.embeddingClient.embedBatch(embeddingInputs);\n\n // Store chunks and embeddings\n const chunkIds: string[] = [];\n for (let j = 0; j < chunks.length; j++) {\n const chunk = chunks[j];\n const embedding = embeddings[j].embedding;\n\n // Store vector\n this.vectorStore.add(chunk.id, embedding);\n\n // Store metadata with relative path for portability across environments\n const relativeFilePath = relative(this.projectRoot, chunk.filePath);\n const metadata: StoredChunkMetadata = {\n filePath: relativeFilePath,\n startLine: chunk.startLine,\n endLine: chunk.endLine,\n startColumn: chunk.startColumn,\n endColumn: chunk.endColumn,\n kind: chunk.kind,\n name: chunk.name,\n contentHash: hashContentSync(chunk.content),\n metadata: {\n props: chunk.metadata.props,\n hooks: chunk.metadata.hooks,\n jsxElements: chunk.metadata.jsxElements,\n isExported: chunk.metadata.isExported,\n isDefaultExport: chunk.metadata.isDefaultExport,\n },\n };\n this.metadataStore.set(chunk.id, metadata);\n\n chunkIds.push(chunk.id);\n }\n\n // Update file tracker\n await this.fileTracker.updateFile(change.path, content, chunkIds);\n } catch (error) {\n console.warn(`Error processing ${change.path}:`, error);\n }\n }\n\n return {\n added,\n modified,\n deleted,\n totalChunks: this.metadataStore.size(),\n };\n }\n\n /**\n * Get index statistics\n */\n getStats(): {\n totalFiles: number;\n totalChunks: number;\n indexSizeBytes: number;\n manifest: IndexManifest | null;\n } {\n return {\n totalFiles: this.fileTracker.getTrackedFiles().length,\n totalChunks: this.metadataStore.size(),\n indexSizeBytes: this.vectorStore.getStats().memoryBytes,\n manifest: this.manifest,\n };\n }\n\n /**\n * Get the vector store (for queries)\n */\n getVectorStore(): VectorStore {\n return this.vectorStore;\n }\n\n /**\n * Get the metadata store (for queries)\n */\n getMetadataStore(): MetadataStore {\n return this.metadataStore;\n }\n\n /**\n * Check if index exists\n */\n hasIndex(): boolean {\n return existsSync(join(this.indexDir, MANIFEST_FILE));\n }\n}\n\n/**\n * Create an indexer for a project\n */\nexport function createIndexer(\n projectRoot: string,\n options?: IndexerOptions\n): IncrementalIndexer {\n return new IncrementalIndexer(projectRoot, options);\n}\n","/**\n * Vector Store\n *\n * File-based vector storage with cosine similarity search.\n * Uses binary Float32 format for efficient storage.\n */\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"fs\";\nimport { join } from \"path\";\n\nexport interface SimilarityResult {\n /** Chunk ID */\n id: string;\n /** Cosine similarity score (0-1) */\n score: number;\n /** Distance (1 - score) */\n distance: number;\n}\n\nexport interface VectorStoreOptions {\n /** Expected dimension of vectors (validated on add) */\n dimension?: number;\n}\n\n/**\n * Compute cosine similarity between two vectors\n */\nfunction cosineSimilarity(a: number[], b: number[]): number {\n if (a.length !== b.length) {\n throw new Error(`Vector dimension mismatch: ${a.length} vs ${b.length}`);\n }\n\n let dotProduct = 0;\n let normA = 0;\n let normB = 0;\n\n for (let i = 0; i < a.length; i++) {\n dotProduct += a[i] * b[i];\n normA += a[i] * a[i];\n normB += b[i] * b[i];\n }\n\n normA = Math.sqrt(normA);\n normB = Math.sqrt(normB);\n\n if (normA === 0 || normB === 0) {\n return 0;\n }\n\n return dotProduct / (normA * normB);\n}\n\nexport class VectorStore {\n private vectors: Map<string, number[]> = new Map();\n private dimension: number | null = null;\n private idIndex: string[] = []; // Ordered list of IDs for binary storage\n\n constructor(options: VectorStoreOptions = {}) {\n if (options.dimension) {\n this.dimension = options.dimension;\n }\n }\n\n /**\n * Add a vector to the store\n */\n add(id: string, vector: number[]): void {\n // Validate dimension\n if (this.dimension === null) {\n this.dimension = vector.length;\n } else if (vector.length !== this.dimension) {\n throw new Error(\n `Vector dimension mismatch: expected ${this.dimension}, got ${vector.length}`\n );\n }\n\n // Add to store\n if (!this.vectors.has(id)) {\n this.idIndex.push(id);\n }\n this.vectors.set(id, vector);\n }\n\n /**\n * Add multiple vectors at once\n */\n addBatch(items: Array<{ id: string; vector: number[] }>): void {\n for (const { id, vector } of items) {\n this.add(id, vector);\n }\n }\n\n /**\n * Remove a vector from the store\n */\n remove(id: string): boolean {\n if (!this.vectors.has(id)) {\n return false;\n }\n this.vectors.delete(id);\n this.idIndex = this.idIndex.filter((i) => i !== id);\n return true;\n }\n\n /**\n * Get a vector by ID\n */\n get(id: string): number[] | null {\n return this.vectors.get(id) || null;\n }\n\n /**\n * Check if a vector exists\n */\n has(id: string): boolean {\n return this.vectors.has(id);\n }\n\n /**\n * Find the most similar vectors to a query vector\n */\n findSimilar(\n query: number[],\n k: number = 10,\n threshold: number = 0\n ): SimilarityResult[] {\n if (this.dimension !== null && query.length !== this.dimension) {\n throw new Error(\n `Query vector dimension mismatch: expected ${this.dimension}, got ${query.length}`\n );\n }\n\n const results: SimilarityResult[] = [];\n\n for (const [id, vector] of this.vectors) {\n const score = cosineSimilarity(query, vector);\n if (score >= threshold) {\n results.push({\n id,\n score,\n distance: 1 - score,\n });\n }\n }\n\n // Sort by score descending\n results.sort((a, b) => b.score - a.score);\n\n // Return top k\n return results.slice(0, k);\n }\n\n /**\n * Get the number of vectors in the store\n */\n size(): number {\n return this.vectors.size;\n }\n\n /**\n * Get the dimension of vectors\n */\n getDimension(): number | null {\n return this.dimension;\n }\n\n /**\n * Get all IDs\n */\n getIds(): string[] {\n return [...this.idIndex];\n }\n\n /**\n * Clear all vectors\n */\n clear(): void {\n this.vectors.clear();\n this.idIndex = [];\n this.dimension = null;\n }\n\n /**\n * Save the vector store to disk\n *\n * Format:\n * - embeddings.bin: Binary Float32 vectors\n * - ids.json: Ordered array of IDs matching vector positions\n */\n async save(dirPath: string): Promise<void> {\n // Ensure directory exists\n if (!existsSync(dirPath)) {\n mkdirSync(dirPath, { recursive: true });\n }\n\n // Save IDs\n const idsPath = join(dirPath, \"ids.json\");\n writeFileSync(idsPath, JSON.stringify(this.idIndex), \"utf-8\");\n\n // Save vectors as binary\n const embeddingsPath = join(dirPath, \"embeddings.bin\");\n\n if (this.vectors.size === 0) {\n // Write empty file with header only\n const header = new Uint32Array([0, 0]); // dimension=0, count=0\n writeFileSync(embeddingsPath, Buffer.from(header.buffer));\n return;\n }\n\n const dimension = this.dimension!;\n const count = this.vectors.size;\n\n // Create buffer: 8 bytes header (2 uint32) + vectors\n const headerSize = 8;\n const vectorsSize = count * dimension * 4; // Float32 = 4 bytes\n const buffer = Buffer.alloc(headerSize + vectorsSize);\n\n // Write header\n buffer.writeUInt32LE(dimension, 0);\n buffer.writeUInt32LE(count, 4);\n\n // Write vectors in ID order\n let offset = headerSize;\n for (const id of this.idIndex) {\n const vector = this.vectors.get(id)!;\n for (const value of vector) {\n buffer.writeFloatLE(value, offset);\n offset += 4;\n }\n }\n\n writeFileSync(embeddingsPath, buffer);\n }\n\n /**\n * Load the vector store from disk\n */\n async load(dirPath: string): Promise<void> {\n const idsPath = join(dirPath, \"ids.json\");\n const embeddingsPath = join(dirPath, \"embeddings.bin\");\n\n if (!existsSync(idsPath) || !existsSync(embeddingsPath)) {\n throw new Error(`Vector store files not found in ${dirPath}`);\n }\n\n // Clear current state\n this.clear();\n\n // Load IDs\n const idsContent = readFileSync(idsPath, \"utf-8\");\n this.idIndex = JSON.parse(idsContent);\n\n // Load vectors\n const buffer = readFileSync(embeddingsPath);\n\n // Read header\n const dimension = buffer.readUInt32LE(0);\n const count = buffer.readUInt32LE(4);\n\n if (count === 0) {\n // Empty store\n return;\n }\n\n this.dimension = dimension;\n\n // Read vectors\n let offset = 8;\n for (let i = 0; i < count; i++) {\n const vector: number[] = [];\n for (let j = 0; j < dimension; j++) {\n vector.push(buffer.readFloatLE(offset));\n offset += 4;\n }\n this.vectors.set(this.idIndex[i], vector);\n }\n }\n\n /**\n * Iterate over all vectors\n */\n *entries(): IterableIterator<[string, number[]]> {\n for (const id of this.idIndex) {\n yield [id, this.vectors.get(id)!];\n }\n }\n\n /**\n * Get stats about the store\n */\n getStats(): { size: number; dimension: number | null; memoryBytes: number } {\n const memoryBytes = this.dimension\n ? this.vectors.size * this.dimension * 4 + this.idIndex.length * 50 // Rough estimate\n : 0;\n\n return {\n size: this.vectors.size,\n dimension: this.dimension,\n memoryBytes,\n };\n }\n}\n","/**\n * Metadata Store\n *\n * JSON-based storage for chunk metadata (file paths, line numbers, etc.)\n */\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"fs\";\nimport { join } from \"path\";\nimport type { StoredChunkMetadata } from \"./types.js\";\n\nexport class MetadataStore {\n private chunks: Map<string, StoredChunkMetadata> = new Map();\n\n /**\n * Add or update chunk metadata\n */\n set(id: string, metadata: StoredChunkMetadata): void {\n this.chunks.set(id, metadata);\n }\n\n /**\n * Add multiple chunks at once\n */\n setBatch(items: Array<{ id: string; metadata: StoredChunkMetadata }>): void {\n for (const { id, metadata } of items) {\n this.set(id, metadata);\n }\n }\n\n /**\n * Get chunk metadata by ID\n */\n get(id: string): StoredChunkMetadata | null {\n return this.chunks.get(id) || null;\n }\n\n /**\n * Check if a chunk exists\n */\n has(id: string): boolean {\n return this.chunks.has(id);\n }\n\n /**\n * Remove chunk metadata\n */\n remove(id: string): boolean {\n return this.chunks.delete(id);\n }\n\n /**\n * Remove all chunks for a given file path\n */\n removeByFilePath(filePath: string): string[] {\n const removedIds: string[] = [];\n for (const [id, metadata] of this.chunks) {\n if (metadata.filePath === filePath) {\n this.chunks.delete(id);\n removedIds.push(id);\n }\n }\n return removedIds;\n }\n\n /**\n * Get all chunks for a given file path\n */\n getByFilePath(\n filePath: string\n ): Array<{ id: string; metadata: StoredChunkMetadata }> {\n const results: Array<{ id: string; metadata: StoredChunkMetadata }> = [];\n for (const [id, metadata] of this.chunks) {\n if (metadata.filePath === filePath) {\n results.push({ id, metadata });\n }\n }\n return results;\n }\n\n /**\n * Get chunk by content hash\n */\n getByContentHash(\n contentHash: string\n ): { id: string; metadata: StoredChunkMetadata } | null {\n for (const [id, metadata] of this.chunks) {\n if (metadata.contentHash === contentHash) {\n return { id, metadata };\n }\n }\n return null;\n }\n\n /**\n * Get chunk at a specific location\n */\n getAtLocation(\n filePath: string,\n line: number\n ): { id: string; metadata: StoredChunkMetadata } | null {\n for (const [id, metadata] of this.chunks) {\n if (\n metadata.filePath === filePath &&\n metadata.startLine <= line &&\n metadata.endLine >= line\n ) {\n return { id, metadata };\n }\n }\n return null;\n }\n\n /**\n * Get all unique file paths\n */\n getFilePaths(): string[] {\n const paths = new Set<string>();\n for (const metadata of this.chunks.values()) {\n paths.add(metadata.filePath);\n }\n return [...paths];\n }\n\n /**\n * Get number of chunks\n */\n size(): number {\n return this.chunks.size;\n }\n\n /**\n * Clear all metadata\n */\n clear(): void {\n this.chunks.clear();\n }\n\n /**\n * Iterate over all chunks\n */\n *entries(): IterableIterator<[string, StoredChunkMetadata]> {\n yield* this.chunks.entries();\n }\n\n /**\n * Get all IDs\n */\n getIds(): string[] {\n return [...this.chunks.keys()];\n }\n\n /**\n * Save to disk\n */\n async save(dirPath: string): Promise<void> {\n if (!existsSync(dirPath)) {\n mkdirSync(dirPath, { recursive: true });\n }\n\n const metadataPath = join(dirPath, \"metadata.json\");\n const data = Object.fromEntries(this.chunks);\n writeFileSync(metadataPath, JSON.stringify(data, null, 2), \"utf-8\");\n }\n\n /**\n * Load from disk\n */\n async load(dirPath: string): Promise<void> {\n const metadataPath = join(dirPath, \"metadata.json\");\n\n if (!existsSync(metadataPath)) {\n throw new Error(`Metadata file not found: ${metadataPath}`);\n }\n\n this.clear();\n const content = readFileSync(metadataPath, \"utf-8\");\n const data = JSON.parse(content) as Record<string, StoredChunkMetadata>;\n\n for (const [id, metadata] of Object.entries(data)) {\n this.chunks.set(id, metadata);\n }\n }\n\n /**\n * Filter chunks by kind\n */\n filterByKind(\n kind: string\n ): Array<{ id: string; metadata: StoredChunkMetadata }> {\n const results: Array<{ id: string; metadata: StoredChunkMetadata }> = [];\n for (const [id, metadata] of this.chunks) {\n if (metadata.kind === kind) {\n results.push({ id, metadata });\n }\n }\n return results;\n }\n\n /**\n * Search by name (case-insensitive partial match)\n */\n searchByName(\n query: string\n ): Array<{ id: string; metadata: StoredChunkMetadata }> {\n const lowerQuery = query.toLowerCase();\n const results: Array<{ id: string; metadata: StoredChunkMetadata }> = [];\n for (const [id, metadata] of this.chunks) {\n if (metadata.name && metadata.name.toLowerCase().includes(lowerQuery)) {\n results.push({ id, metadata });\n }\n }\n return results;\n }\n}\n","/**\n * File Tracker\n *\n * Tracks file content hashes for incremental updates.\n * Uses xxhash for fast hashing (following uilint-eslint patterns).\n */\n\nimport {\n existsSync,\n mkdirSync,\n readFileSync,\n writeFileSync,\n statSync,\n} from \"fs\";\nimport { join } from \"path\";\n\n// Lazy-loaded xxhash\nlet xxhashInstance: Awaited<\n ReturnType<typeof import(\"xxhash-wasm\")[\"default\"]>\n> | null = null;\n\nasync function getXxhash() {\n if (!xxhashInstance) {\n const xxhash = await import(\"xxhash-wasm\");\n xxhashInstance = await xxhash.default();\n }\n return xxhashInstance;\n}\n\n/**\n * Synchronous hash using djb2 algorithm (fallback)\n */\nfunction djb2Hash(str: string): string {\n let hash = 5381;\n for (let i = 0; i < str.length; i++) {\n hash = (hash * 33) ^ str.charCodeAt(i);\n }\n return (hash >>> 0).toString(16);\n}\n\n/**\n * Hash content using xxhash (async) or djb2 (sync fallback)\n */\nexport async function hashContent(content: string): Promise<string> {\n try {\n const xxhash = await getXxhash();\n return xxhash.h64ToString(content);\n } catch {\n return djb2Hash(content);\n }\n}\n\n/**\n * Synchronous hash for when async is not possible\n */\nexport function hashContentSync(content: string): string {\n return djb2Hash(content);\n}\n\nexport interface FileHashEntry {\n /** xxhash of file content */\n contentHash: string;\n /** Last modification time in ms */\n mtimeMs: number;\n /** IDs of chunks from this file */\n chunkIds: string[];\n}\n\nexport interface HashStore {\n version: number;\n files: Record<string, FileHashEntry>;\n}\n\nexport interface FileChange {\n path: string;\n type: \"added\" | \"modified\" | \"deleted\";\n oldHash?: string;\n newHash?: string;\n}\n\nconst HASH_STORE_VERSION = 1;\n\nexport class FileTracker {\n private store: HashStore = {\n version: HASH_STORE_VERSION,\n files: {},\n };\n\n /**\n * Get the hash entry for a file\n */\n getEntry(filePath: string): FileHashEntry | null {\n return this.store.files[filePath] || null;\n }\n\n /**\n * Set the hash entry for a file\n */\n setEntry(filePath: string, entry: FileHashEntry): void {\n this.store.files[filePath] = entry;\n }\n\n /**\n * Remove the hash entry for a file\n */\n removeEntry(filePath: string): boolean {\n if (this.store.files[filePath]) {\n delete this.store.files[filePath];\n return true;\n }\n return false;\n }\n\n /**\n * Get all tracked file paths\n */\n getTrackedFiles(): string[] {\n return Object.keys(this.store.files);\n }\n\n /**\n * Clear all entries\n */\n clear(): void {\n this.store = {\n version: HASH_STORE_VERSION,\n files: {},\n };\n }\n\n /**\n * Detect changes between current files and stored hashes\n */\n async detectChanges(files: string[]): Promise<FileChange[]> {\n const changes: FileChange[] = [];\n const currentFiles = new Set(files);\n\n // Check for deleted files\n for (const storedPath of Object.keys(this.store.files)) {\n if (!currentFiles.has(storedPath)) {\n changes.push({\n path: storedPath,\n type: \"deleted\",\n oldHash: this.store.files[storedPath].contentHash,\n });\n }\n }\n\n // Check for added or modified files\n for (const filePath of files) {\n try {\n const content = readFileSync(filePath, \"utf-8\");\n const newHash = await hashContent(content);\n const entry = this.store.files[filePath];\n\n if (!entry) {\n // New file\n changes.push({\n path: filePath,\n type: \"added\",\n newHash,\n });\n } else if (entry.contentHash !== newHash) {\n // Modified file\n changes.push({\n path: filePath,\n type: \"modified\",\n oldHash: entry.contentHash,\n newHash,\n });\n }\n // If hash matches and mtime is similar, no change\n } catch {\n // File might be deleted or unreadable\n if (this.store.files[filePath]) {\n changes.push({\n path: filePath,\n type: \"deleted\",\n oldHash: this.store.files[filePath].contentHash,\n });\n }\n }\n }\n\n return changes;\n }\n\n /**\n * Update stored hash for a file\n */\n async updateFile(\n filePath: string,\n content: string,\n chunkIds: string[]\n ): Promise<void> {\n const hash = await hashContent(content);\n const stat = statSync(filePath);\n\n this.store.files[filePath] = {\n contentHash: hash,\n mtimeMs: stat.mtimeMs,\n chunkIds,\n };\n }\n\n /**\n * Save to disk\n */\n async save(dirPath: string): Promise<void> {\n if (!existsSync(dirPath)) {\n mkdirSync(dirPath, { recursive: true });\n }\n\n const hashesPath = join(dirPath, \"hashes.json\");\n writeFileSync(hashesPath, JSON.stringify(this.store, null, 2), \"utf-8\");\n }\n\n /**\n * Load from disk\n */\n async load(dirPath: string): Promise<void> {\n const hashesPath = join(dirPath, \"hashes.json\");\n\n if (!existsSync(hashesPath)) {\n // No existing hash store - start fresh\n this.clear();\n return;\n }\n\n const content = readFileSync(hashesPath, \"utf-8\");\n const data = JSON.parse(content) as HashStore;\n\n // Version check\n if (data.version !== HASH_STORE_VERSION) {\n // Incompatible version - start fresh\n this.clear();\n return;\n }\n\n this.store = data;\n }\n\n /**\n * Get stats\n */\n getStats(): { trackedFiles: number } {\n return {\n trackedFiles: Object.keys(this.store.files).length,\n };\n }\n}\n","/**\n * Duplicate Scorer\n *\n * Provides scoring functions for ranking duplicate code groups.\n */\n\nimport type { StoredChunkMetadata } from \"../index/types.js\";\n\nexport interface DuplicateScore {\n /** Embedding cosine similarity (0-1) */\n similarity: number;\n /** Ratio of code size similarity (0-1) */\n sizeRatio: number;\n /** Weighted combined score */\n combinedScore: number;\n}\n\n/**\n * Calculate the size ratio between two code chunks.\n * Returns a value between 0 and 1 where 1 means identical size.\n */\nexport function calculateSizeRatio(\n chunk1: StoredChunkMetadata,\n chunk2: StoredChunkMetadata\n): number {\n const lines1 = chunk1.endLine - chunk1.startLine + 1;\n const lines2 = chunk2.endLine - chunk2.startLine + 1;\n\n const minLines = Math.min(lines1, lines2);\n const maxLines = Math.max(lines1, lines2);\n\n return maxLines > 0 ? minLines / maxLines : 1;\n}\n\n/**\n * Calculate a combined duplicate score.\n */\nexport function calculateDuplicateScore(\n similarity: number,\n chunk1: StoredChunkMetadata,\n chunk2: StoredChunkMetadata\n): DuplicateScore {\n const sizeRatio = calculateSizeRatio(chunk1, chunk2);\n\n // Weighted score: 85% similarity, 15% size ratio\n const combinedScore = similarity * 0.85 + sizeRatio * 0.15;\n\n return {\n similarity,\n sizeRatio,\n combinedScore,\n };\n}\n\n/**\n * Calculate the average similarity of a duplicate group.\n */\nexport function calculateGroupAverageSimilarity(\n similarities: number[]\n): number {\n if (similarities.length === 0) return 0;\n return similarities.reduce((sum, s) => sum + s, 0) / similarities.length;\n}\n\n/**\n * Sort duplicate groups by relevance.\n * Groups are sorted by: member count (desc), then average similarity (desc).\n */\nexport function sortDuplicateGroups<T extends { avgSimilarity: number; members: unknown[] }>(\n groups: T[]\n): T[] {\n return [...groups].sort((a, b) => {\n // First by member count (more members = more important)\n const countDiff = b.members.length - a.members.length;\n if (countDiff !== 0) return countDiff;\n\n // Then by average similarity\n return b.avgSimilarity - a.avgSimilarity;\n });\n}\n","/**\n * Structural Similarity Scorer\n *\n * Calculates similarity based on code structure (props, hooks, JSX elements)\n * independent of semantic embeddings. This complements embedding-based\n * similarity by catching cases where code structure is similar but\n * variable/prop names differ.\n */\n\nimport type { StoredChunkMetadata } from \"../index/types.js\";\n\nexport interface StructuralScore {\n /** Jaccard similarity of prop names (0-1) */\n propsOverlap: number;\n /** Jaccard similarity of JSX elements (0-1) */\n jsxOverlap: number;\n /** Jaccard similarity of hooks used (0-1) */\n hooksOverlap: number;\n /** Line count ratio (0-1, 1 = same size) */\n sizeRatio: number;\n /** Combined weighted score (0-1) */\n combined: number;\n}\n\nexport interface StructuralScorerWeights {\n /** Weight for props overlap (default: 0.25) */\n props: number;\n /** Weight for JSX elements overlap (default: 0.35) */\n jsx: number;\n /** Weight for hooks overlap (default: 0.25) */\n hooks: number;\n /** Weight for size similarity (default: 0.15) */\n size: number;\n}\n\nexport const DEFAULT_STRUCTURAL_WEIGHTS: StructuralScorerWeights = {\n props: 0.25,\n jsx: 0.35,\n hooks: 0.25,\n size: 0.15,\n};\n\n/**\n * Calculate Jaccard similarity between two sets of strings.\n * Returns 1 if both sets are empty (vacuously similar).\n */\nexport function jaccard(a: string[], b: string[]): number {\n if (a.length === 0 && b.length === 0) return 1;\n if (a.length === 0 || b.length === 0) return 0;\n\n // Normalize to lowercase for comparison\n const setA = new Set(a.map((s) => s.toLowerCase()));\n const setB = new Set(b.map((s) => s.toLowerCase()));\n\n const intersection = new Set([...setA].filter((x) => setB.has(x)));\n const union = new Set([...setA, ...setB]);\n\n return intersection.size / union.size;\n}\n\n/**\n * Calculate size ratio between two code chunks.\n * Returns a value between 0 and 1, where 1 means identical size.\n */\nexport function calculateSizeRatio(linesA: number, linesB: number): number {\n if (linesA === 0 && linesB === 0) return 1;\n if (linesA === 0 || linesB === 0) return 0;\n\n const min = Math.min(linesA, linesB);\n const max = Math.max(linesA, linesB);\n\n return min / max;\n}\n\n/**\n * Extract structural features from chunk metadata.\n * Handles cases where metadata fields may be missing.\n * Note: StoredChunkMetadata has a nested `metadata` field containing props, hooks, etc.\n */\nfunction extractFeatures(storedMeta: StoredChunkMetadata): {\n props: string[];\n jsxElements: string[];\n hooks: string[];\n lines: number;\n} {\n const meta = storedMeta.metadata ?? {};\n return {\n props: meta.props ?? [],\n jsxElements: meta.jsxElements ?? [],\n hooks: meta.hooks ?? [],\n lines: (storedMeta.endLine ?? 0) - (storedMeta.startLine ?? 0) + 1,\n };\n}\n\n/**\n * Calculate structural similarity between two chunks.\n *\n * This function compares the structural features of two code chunks:\n * - Props/parameters they accept\n * - JSX elements they render\n * - Hooks they use\n * - Relative size\n *\n * @param a First chunk metadata\n * @param b Second chunk metadata\n * @param weights Optional custom weights for each feature\n * @returns Structural similarity score with component breakdowns\n */\nexport function calculateStructuralSimilarity(\n a: StoredChunkMetadata,\n b: StoredChunkMetadata,\n weights: StructuralScorerWeights = DEFAULT_STRUCTURAL_WEIGHTS\n): StructuralScore {\n const featuresA = extractFeatures(a);\n const featuresB = extractFeatures(b);\n\n const propsOverlap = jaccard(featuresA.props, featuresB.props);\n const jsxOverlap = jaccard(featuresA.jsxElements, featuresB.jsxElements);\n const hooksOverlap = jaccard(featuresA.hooks, featuresB.hooks);\n const sizeRatio = calculateSizeRatio(featuresA.lines, featuresB.lines);\n\n // Calculate weighted combined score\n const combined =\n propsOverlap * weights.props +\n jsxOverlap * weights.jsx +\n hooksOverlap * weights.hooks +\n sizeRatio * weights.size;\n\n return {\n propsOverlap,\n jsxOverlap,\n hooksOverlap,\n sizeRatio,\n combined,\n };\n}\n\n/**\n * Quick check if two chunks have high structural similarity.\n * Useful for fast pre-filtering before expensive embedding comparison.\n *\n * @param a First chunk metadata\n * @param b Second chunk metadata\n * @param threshold Minimum combined score to consider similar (default: 0.5)\n */\nexport function hasHighStructuralSimilarity(\n a: StoredChunkMetadata,\n b: StoredChunkMetadata,\n threshold: number = 0.5\n): boolean {\n const score = calculateStructuralSimilarity(a, b);\n return score.combined >= threshold;\n}\n\n/**\n * Find structurally similar chunks from a list.\n * Returns chunks sorted by structural similarity (highest first).\n *\n * @param target The chunk to compare against\n * @param candidates List of candidate chunks to compare\n * @param threshold Minimum similarity threshold\n * @param limit Maximum number of results to return\n */\nexport function findStructurallySimilar(\n target: StoredChunkMetadata,\n candidates: StoredChunkMetadata[],\n threshold: number = 0.5,\n limit: number = 10\n): Array<{ metadata: StoredChunkMetadata; score: StructuralScore }> {\n const results: Array<{ metadata: StoredChunkMetadata; score: StructuralScore }> = [];\n\n for (const candidate of candidates) {\n // Skip self-comparison\n if (candidate.filePath === target.filePath && candidate.startLine === target.startLine) {\n continue;\n }\n\n const score = calculateStructuralSimilarity(target, candidate);\n if (score.combined >= threshold) {\n results.push({ metadata: candidate, score });\n }\n }\n\n // Sort by combined score descending\n results.sort((a, b) => b.score.combined - a.score.combined);\n\n return results.slice(0, limit);\n}\n","/**\n * Confidence Level System\n *\n * Provides confidence levels for duplicate detection results\n * to help users prioritize which duplicates to address.\n *\n * Confidence levels:\n * - HIGH: Likely copy-paste or near-identical implementation. Should consolidate.\n * - MEDIUM: Semantically similar code. Worth reviewing for potential abstraction.\n * - LOW: Possibly related patterns. Optional to review.\n */\n\nexport type ConfidenceLevel = \"high\" | \"medium\" | \"low\";\n\nexport interface ConfidenceConfig {\n /** Threshold for high confidence (default: 0.90) */\n highThreshold: number;\n /** Threshold for medium confidence (default: 0.75) */\n mediumThreshold: number;\n /** Threshold for low confidence / minimum reporting (default: 0.60) */\n lowThreshold: number;\n}\n\nexport const DEFAULT_CONFIDENCE_CONFIG: ConfidenceConfig = {\n highThreshold: 0.9,\n mediumThreshold: 0.75,\n lowThreshold: 0.6,\n};\n\nexport interface ConfidenceResult {\n /** The confidence level */\n level: ConfidenceLevel;\n /** The raw similarity score (0-1) */\n score: number;\n /** Human-readable description of what this confidence level means */\n description: string;\n /** Recommended action for the user */\n action: string;\n /** Color for CLI/UI display */\n color: \"red\" | \"yellow\" | \"green\";\n}\n\n/**\n * Determine confidence level from a similarity score.\n *\n * @param score Similarity score between 0 and 1\n * @param config Optional custom threshold configuration\n * @returns The confidence level\n */\nexport function getConfidenceLevel(\n score: number,\n config: ConfidenceConfig = DEFAULT_CONFIDENCE_CONFIG\n): ConfidenceLevel {\n if (score >= config.highThreshold) return \"high\";\n if (score >= config.mediumThreshold) return \"medium\";\n return \"low\";\n}\n\n/**\n * Check if a score meets the minimum threshold for reporting.\n *\n * @param score Similarity score\n * @param config Optional custom threshold configuration\n * @returns True if the score should be reported\n */\nexport function meetsMinimumThreshold(\n score: number,\n config: ConfidenceConfig = DEFAULT_CONFIDENCE_CONFIG\n): boolean {\n return score >= config.lowThreshold;\n}\n\n/**\n * Get detailed confidence result with actionable guidance.\n *\n * @param score Similarity score between 0 and 1\n * @param config Optional custom threshold configuration\n * @returns Full confidence result with guidance\n */\nexport function getConfidenceResult(\n score: number,\n config: ConfidenceConfig = DEFAULT_CONFIDENCE_CONFIG\n): ConfidenceResult {\n const level = getConfidenceLevel(score, config);\n\n switch (level) {\n case \"high\":\n return {\n level,\n score,\n description:\n \"High confidence duplicate - likely copy-paste or near-identical implementation\",\n action: \"Strongly recommend consolidating into a single reusable component/function\",\n color: \"red\",\n };\n case \"medium\":\n return {\n level,\n score,\n description:\n \"Medium confidence - semantically similar code with different implementation details\",\n action: \"Review for potential consolidation or shared abstraction\",\n color: \"yellow\",\n };\n case \"low\":\n return {\n level,\n score,\n description: \"Low confidence - possibly related patterns or partial structural overlap\",\n action: \"Optional review - differences may be intentional\",\n color: \"green\",\n };\n }\n}\n\n/**\n * Get emoji indicator for confidence level (for CLI output).\n */\nexport function getConfidenceEmoji(level: ConfidenceLevel): string {\n switch (level) {\n case \"high\":\n return \"🔴\";\n case \"medium\":\n return \"🟡\";\n case \"low\":\n return \"🟢\";\n }\n}\n\n/**\n * Get ANSI color code for confidence level (for CLI output).\n */\nexport function getConfidenceAnsiColor(level: ConfidenceLevel): string {\n switch (level) {\n case \"high\":\n return \"\\x1b[31m\"; // Red\n case \"medium\":\n return \"\\x1b[33m\"; // Yellow\n case \"low\":\n return \"\\x1b[32m\"; // Green\n }\n}\n\n/**\n * Format confidence for display in CLI.\n *\n * @param result Confidence result to format\n * @param useEmoji Whether to include emoji (default: true)\n * @param useColor Whether to include ANSI colors (default: false)\n * @returns Formatted string\n */\nexport function formatConfidence(\n result: ConfidenceResult,\n useEmoji: boolean = true,\n useColor: boolean = false\n): string {\n const percent = Math.round(result.score * 100);\n const emoji = useEmoji ? getConfidenceEmoji(result.level) + \" \" : \"\";\n const colorStart = useColor ? getConfidenceAnsiColor(result.level) : \"\";\n const colorEnd = useColor ? \"\\x1b[0m\" : \"\";\n\n return `${emoji}${colorStart}${percent}% similarity (${result.level} confidence)${colorEnd}`;\n}\n\n/**\n * Format confidence with full details for verbose output.\n */\nexport function formatConfidenceVerbose(result: ConfidenceResult): string {\n const lines = [\n formatConfidence(result),\n ` ${result.description}`,\n ` → ${result.action}`,\n ];\n return lines.join(\"\\n\");\n}\n\n/**\n * Compare two confidence levels.\n * Returns: -1 if a < b, 0 if equal, 1 if a > b\n */\nexport function compareConfidenceLevels(a: ConfidenceLevel, b: ConfidenceLevel): number {\n const order: Record<ConfidenceLevel, number> = { high: 3, medium: 2, low: 1 };\n return order[a] - order[b];\n}\n\n/**\n * Filter results by minimum confidence level.\n */\nexport function filterByConfidence<T extends { score: number }>(\n results: T[],\n minLevel: ConfidenceLevel,\n config: ConfidenceConfig = DEFAULT_CONFIDENCE_CONFIG\n): T[] {\n const minThreshold =\n minLevel === \"high\"\n ? config.highThreshold\n : minLevel === \"medium\"\n ? config.mediumThreshold\n : config.lowThreshold;\n\n return results.filter((r) => r.score >= minThreshold);\n}\n","/**\n * Duplicate Finder\n *\n * Finds groups of semantically similar code chunks using the vector index.\n * Enhanced with structural similarity scoring and confidence levels.\n */\n\nimport type { VectorStore, SimilarityResult } from \"../index/vector-store.js\";\nimport type { MetadataStore } from \"../index/metadata-store.js\";\nimport type { StoredChunkMetadata } from \"../index/types.js\";\nimport type { ChunkKind } from \"../embeddings/types.js\";\nimport {\n calculateGroupAverageSimilarity,\n sortDuplicateGroups,\n} from \"./scorer.js\";\nimport { calculateStructuralSimilarity } from \"./structural-scorer.js\";\nimport {\n getConfidenceLevel,\n type ConfidenceLevel,\n} from \"./confidence.js\";\n\nexport interface DuplicateMember {\n /** Chunk ID */\n id: string;\n /** Chunk metadata */\n metadata: StoredChunkMetadata;\n /** Similarity score to the group centroid/first member (semantic only) */\n score: number;\n /** Combined score (semantic + structural) */\n combinedScore?: number;\n /** Structural similarity score */\n structuralScore?: number;\n /** Confidence level for this match */\n confidence?: ConfidenceLevel;\n}\n\nexport interface DuplicateGroup {\n /** Members of the duplicate group */\n members: DuplicateMember[];\n /** Average similarity between all group members */\n avgSimilarity: number;\n /** The kind of code in this group (component, hook, function) */\n kind: ChunkKind;\n /** Overall confidence level for the group */\n confidence: ConfidenceLevel;\n}\n\nexport interface FindDuplicatesOptions {\n /** Minimum cosine similarity threshold (0-1). Default: 0.75 (lowered from 0.85) */\n threshold?: number;\n /** Minimum group size. Default: 2 */\n minGroupSize?: number;\n /** Filter by chunk kind */\n kind?: ChunkKind;\n /** Exclude specific file paths */\n excludePaths?: string[];\n /** Include duplicates within the same file. Default: true */\n includeSameFile?: boolean;\n /** Use structural similarity to boost scores. Default: true */\n useStructuralBoost?: boolean;\n /** Filter results by minimum confidence level */\n confidenceFilter?: ConfidenceLevel;\n}\n\n/**\n * Calculate combined score from semantic and structural similarity.\n * Weights: 60% semantic, 40% structural.\n */\nfunction calculateCombinedSimilarity(\n semanticScore: number,\n metadataA: StoredChunkMetadata,\n metadataB: StoredChunkMetadata\n): { combined: number; structural: number } {\n const structuralResult = calculateStructuralSimilarity(metadataA, metadataB);\n const structural = structuralResult.combined;\n\n // Weighted combination: 60% semantic, 40% structural\n const combined = semanticScore * 0.6 + structural * 0.4;\n\n return { combined, structural };\n}\n\n/**\n * Get minimum threshold for confidence level filter.\n */\nfunction getConfidenceThreshold(level: ConfidenceLevel): number {\n switch (level) {\n case \"high\":\n return 0.9;\n case \"medium\":\n return 0.75;\n case \"low\":\n return 0.6;\n }\n}\n\n/**\n * Find groups of semantically similar code.\n *\n * Algorithm:\n * 1. Iterate through all chunks\n * 2. For each unprocessed chunk, find similar chunks above threshold\n * 3. Calculate combined score (semantic + structural)\n * 4. Group similar chunks together\n * 5. Assign confidence levels\n * 6. Sort groups by size and similarity\n */\nexport function findDuplicateGroups(\n vectorStore: VectorStore,\n metadataStore: MetadataStore,\n options: FindDuplicatesOptions = {}\n): DuplicateGroup[] {\n const {\n threshold = 0.75, // Lowered from 0.85\n minGroupSize = 2,\n kind,\n excludePaths = [],\n includeSameFile = true,\n useStructuralBoost = true,\n confidenceFilter,\n } = options;\n\n const groups: DuplicateGroup[] = [];\n const processed = new Set<string>();\n\n // Get all entries and filter by kind if specified\n let entries = [...metadataStore.entries()];\n\n if (kind) {\n entries = entries.filter(([, meta]) => meta.kind === kind);\n }\n\n // Exclude specified paths\n if (excludePaths.length > 0) {\n entries = entries.filter(\n ([, meta]) => !excludePaths.some((p) => meta.filePath.includes(p))\n );\n }\n\n for (const [id, metadata] of entries) {\n if (processed.has(id)) continue;\n\n const vector = vectorStore.get(id);\n if (!vector) continue;\n\n // Find similar chunks - use lower threshold for initial search\n // to catch candidates that might be boosted by structural similarity\n const searchThreshold = useStructuralBoost ? threshold * 0.8 : threshold;\n const similar = vectorStore.findSimilar(vector, 50, searchThreshold);\n\n // Filter out self, already-processed, and potentially filter by kind\n let candidates = similar.filter((s) => {\n if (s.id === id) return false;\n if (processed.has(s.id)) return false;\n\n const candidateMeta = metadataStore.get(s.id);\n if (!candidateMeta) return false;\n\n // If kind filter is set, only include same kind\n if (kind && candidateMeta.kind !== kind) return false;\n\n // Exclude paths\n if (excludePaths.some((p) => candidateMeta.filePath.includes(p)))\n return false;\n\n // Optionally exclude same-file matches\n if (!includeSameFile && candidateMeta.filePath === metadata.filePath)\n return false;\n\n return true;\n });\n\n // Calculate combined scores if structural boost is enabled\n if (useStructuralBoost) {\n candidates = candidates\n .map((c) => {\n const candidateMeta = metadataStore.get(c.id);\n if (!candidateMeta) return { ...c, combinedScore: c.score };\n\n const { combined, structural } = calculateCombinedSimilarity(\n c.score,\n metadata,\n candidateMeta\n );\n return { ...c, combinedScore: combined, structuralScore: structural };\n })\n .filter((c) => (c.combinedScore ?? c.score) >= threshold)\n .sort((a, b) => (b.combinedScore ?? b.score) - (a.combinedScore ?? a.score));\n }\n\n // If not filtering by kind, prefer same-kind groupings\n if (!kind && candidates.length > 0) {\n const sameKindCandidates = candidates.filter((c) => {\n const meta = metadataStore.get(c.id);\n return meta?.kind === metadata.kind;\n });\n if (sameKindCandidates.length > 0) {\n candidates = sameKindCandidates;\n }\n }\n\n // Check if we have enough candidates for a group\n if (candidates.length >= minGroupSize - 1) {\n const members: DuplicateMember[] = [\n {\n id,\n metadata,\n score: 1.0,\n combinedScore: 1.0,\n confidence: \"high\",\n },\n ];\n\n const similarities: number[] = [];\n\n for (const candidate of candidates) {\n const candidateMeta = metadataStore.get(candidate.id);\n if (candidateMeta) {\n const combinedScore =\n (candidate as { combinedScore?: number }).combinedScore ?? candidate.score;\n const structuralScore =\n (candidate as { structuralScore?: number }).structuralScore;\n const confidence = getConfidenceLevel(combinedScore);\n\n members.push({\n id: candidate.id,\n metadata: candidateMeta,\n score: candidate.score,\n combinedScore,\n structuralScore,\n confidence,\n });\n similarities.push(combinedScore);\n processed.add(candidate.id);\n }\n }\n\n // Mark the original chunk as processed\n processed.add(id);\n\n const avgSimilarity = calculateGroupAverageSimilarity(similarities);\n const groupConfidence = getConfidenceLevel(avgSimilarity);\n\n groups.push({\n members,\n avgSimilarity,\n kind: metadata.kind,\n confidence: groupConfidence,\n });\n }\n }\n\n // Filter by confidence level if specified\n let result = groups;\n if (confidenceFilter) {\n const minThreshold = getConfidenceThreshold(confidenceFilter);\n result = groups.filter((g) => g.avgSimilarity >= minThreshold);\n }\n\n // Sort groups by relevance\n return sortDuplicateGroups(result);\n}\n\n/**\n * Find similar code to a given location (file:line).\n */\nexport function findSimilarToLocation(\n vectorStore: VectorStore,\n metadataStore: MetadataStore,\n filePath: string,\n line: number,\n options: { top?: number; threshold?: number } = {}\n): SimilarityResult[] {\n const { top = 10, threshold = 0.5 } = options;\n\n // Find the chunk at this location\n const chunk = metadataStore.getAtLocation(filePath, line);\n if (!chunk) {\n return [];\n }\n\n // Get the vector for this chunk\n const vector = vectorStore.get(chunk.id);\n if (!vector) {\n return [];\n }\n\n // Find similar chunks (excluding self)\n const similar = vectorStore.findSimilar(vector, top + 1, threshold);\n\n return similar.filter((s) => s.id !== chunk.id).slice(0, top);\n}\n\n/**\n * Search for code similar to a text query.\n * Requires embedding the query first.\n */\nexport function findSimilarToQuery(\n vectorStore: VectorStore,\n queryEmbedding: number[],\n options: { top?: number; threshold?: number } = {}\n): SimilarityResult[] {\n const { top = 10, threshold = 0.5 } = options;\n\n return vectorStore.findSimilar(queryEmbedding, top, threshold);\n}\n","/**\n * Code Normalizer\n *\n * Normalizes code before comparison to improve duplicate detection:\n * 1. Replaces identifiers with canonical placeholders (for near-identical detection)\n * 2. Normalizes semantic equivalents (size/dimension, onClick/onPress)\n * 3. Strips comments and normalizes whitespace\n *\n * This is particularly useful for detecting utility functions that are\n * copy-pasted with only variable name changes.\n */\n\nexport interface NormalizationOptions {\n /** Replace all local identifiers with placeholders (aggressive) */\n normalizeIdentifiers?: boolean;\n /** Normalize semantic equivalents like size/dimension */\n normalizeSemantics?: boolean;\n /** Strip comments from code */\n stripComments?: boolean;\n /** Normalize whitespace to single spaces */\n normalizeWhitespace?: boolean;\n}\n\nexport const DEFAULT_NORMALIZATION_OPTIONS: NormalizationOptions = {\n normalizeIdentifiers: false,\n normalizeSemantics: true,\n stripComments: true,\n normalizeWhitespace: true,\n};\n\n/**\n * Semantic equivalent patterns.\n * Maps common naming variations to canonical forms.\n */\nconst SEMANTIC_EQUIVALENTS: Array<[RegExp, string]> = [\n // Size-related props\n [/\\b(size|dimension|scale|magnitude)\\b/gi, \"__SIZE__\"],\n // Variant-related props\n [/\\b(variant|type|kind|style|mode)\\b/gi, \"__VARIANT__\"],\n // Click/press handlers\n [/\\b(onClick|onPress|onTap|handleClick|handlePress|onSelect)\\b/g, \"__CLICK_HANDLER__\"],\n // Change handlers\n [/\\b(onChange|onInput|handleChange|handleInput)\\b/g, \"__CHANGE_HANDLER__\"],\n // Submit handlers\n [/\\b(onSubmit|handleSubmit)\\b/g, \"__SUBMIT_HANDLER__\"],\n // Loading states\n [/\\b(loading|isLoading|pending|isFetching|isBusy)\\b/gi, \"__LOADING__\"],\n // Error states\n [/\\b(error|err|errorMsg|errorMessage|failure)\\b/gi, \"__ERROR__\"],\n // Success states\n [/\\b(success|isSuccess|succeeded|done)\\b/gi, \"__SUCCESS__\"],\n // Data/items collections\n [/\\b(data|items|list|results|entries|records)\\b/gi, \"__DATA__\"],\n // Children/content slots\n [/\\b(children|content|body|slot|inner)\\b/gi, \"__CHILDREN__\"],\n // Label/title text\n [/\\b(label|title|heading|name|text)\\b/gi, \"__LABEL__\"],\n // Description/message\n [/\\b(description|message|subtitle|detail|info)\\b/gi, \"__DESCRIPTION__\"],\n // Value/amount\n [/\\b(value|amount|total|count|number)\\b/gi, \"__VALUE__\"],\n // Disabled state\n [/\\b(disabled|isDisabled|readonly|readOnly)\\b/gi, \"__DISABLED__\"],\n // Visible/shown state\n [/\\b(visible|isVisible|shown|isShown|open|isOpen)\\b/gi, \"__VISIBLE__\"],\n // Class names\n [/\\b(className|classes|style|styles)\\b/gi, \"__CLASSNAME__\"],\n];\n\n/**\n * Strip comments from code.\n */\nfunction stripComments(code: string): string {\n // Remove single-line comments\n let result = code.replace(/\\/\\/.*$/gm, \"\");\n // Remove multi-line comments\n result = result.replace(/\\/\\*[\\s\\S]*?\\*\\//g, \"\");\n return result;\n}\n\n/**\n * Normalize whitespace to single spaces.\n */\nfunction normalizeWhitespace(code: string): string {\n return code\n .replace(/\\s+/g, \" \")\n .replace(/\\s*([{}[\\]();,:<>])\\s*/g, \"$1\")\n .trim();\n}\n\n/**\n * Apply semantic normalization patterns.\n */\nfunction applySemanticNormalization(code: string): string {\n let result = code;\n for (const [pattern, replacement] of SEMANTIC_EQUIVALENTS) {\n result = result.replace(pattern, replacement);\n }\n return result;\n}\n\n/**\n * Normalize identifiers by replacing them with sequential placeholders.\n * This is an aggressive normalization that makes structurally identical\n * code with different variable names appear identical.\n */\nfunction normalizeIdentifiersSimple(code: string): string {\n const identifierMap = new Map<string, string>();\n let counter = 0;\n\n // Match potential identifiers (simplified approach without full AST parsing)\n // This matches word characters that look like identifiers\n const identifierPattern = /\\b([a-z_$][a-z0-9_$]*)\\b/gi;\n\n // Built-in keywords and common globals to preserve\n const preserveList = new Set([\n // JavaScript keywords\n \"const\",\n \"let\",\n \"var\",\n \"function\",\n \"return\",\n \"if\",\n \"else\",\n \"for\",\n \"while\",\n \"do\",\n \"switch\",\n \"case\",\n \"break\",\n \"continue\",\n \"default\",\n \"try\",\n \"catch\",\n \"finally\",\n \"throw\",\n \"new\",\n \"this\",\n \"class\",\n \"extends\",\n \"super\",\n \"import\",\n \"export\",\n \"from\",\n \"as\",\n \"async\",\n \"await\",\n \"yield\",\n \"typeof\",\n \"instanceof\",\n \"in\",\n \"of\",\n \"void\",\n \"delete\",\n \"true\",\n \"false\",\n \"null\",\n \"undefined\",\n // TypeScript keywords\n \"interface\",\n \"type\",\n \"enum\",\n \"implements\",\n \"private\",\n \"public\",\n \"protected\",\n \"readonly\",\n \"abstract\",\n \"declare\",\n \"namespace\",\n \"module\",\n // React hooks\n \"useState\",\n \"useEffect\",\n \"useCallback\",\n \"useMemo\",\n \"useRef\",\n \"useContext\",\n \"useReducer\",\n \"useLayoutEffect\",\n \"useImperativeHandle\",\n \"useDebugValue\",\n \"useDeferredValue\",\n \"useTransition\",\n \"useId\",\n \"useSyncExternalStore\",\n \"useInsertionEffect\",\n // React\n \"React\",\n \"Component\",\n \"Fragment\",\n \"Suspense\",\n \"memo\",\n \"forwardRef\",\n \"createContext\",\n \"createElement\",\n // Common globals\n \"console\",\n \"window\",\n \"document\",\n \"Math\",\n \"Date\",\n \"JSON\",\n \"Object\",\n \"Array\",\n \"String\",\n \"Number\",\n \"Boolean\",\n \"Promise\",\n \"Set\",\n \"Map\",\n \"WeakSet\",\n \"WeakMap\",\n \"Symbol\",\n \"Error\",\n \"RegExp\",\n \"Intl\",\n \"setTimeout\",\n \"setInterval\",\n \"clearTimeout\",\n \"clearInterval\",\n \"fetch\",\n \"require\",\n // Common type names\n \"string\",\n \"number\",\n \"boolean\",\n \"object\",\n \"any\",\n \"unknown\",\n \"never\",\n \"void\",\n // Normalized placeholders (preserve these)\n \"__SIZE__\",\n \"__VARIANT__\",\n \"__CLICK_HANDLER__\",\n \"__CHANGE_HANDLER__\",\n \"__SUBMIT_HANDLER__\",\n \"__LOADING__\",\n \"__ERROR__\",\n \"__SUCCESS__\",\n \"__DATA__\",\n \"__CHILDREN__\",\n \"__LABEL__\",\n \"__DESCRIPTION__\",\n \"__VALUE__\",\n \"__DISABLED__\",\n \"__VISIBLE__\",\n \"__CLASSNAME__\",\n ]);\n\n return code.replace(identifierPattern, (match) => {\n // Preserve keywords and built-ins\n if (preserveList.has(match) || preserveList.has(match.toLowerCase())) {\n return match;\n }\n\n // Get or create placeholder for this identifier\n const key = match.toLowerCase();\n if (!identifierMap.has(key)) {\n identifierMap.set(key, `_ID${counter++}_`);\n }\n return identifierMap.get(key)!;\n });\n}\n\n/**\n * Normalize code for comparison.\n *\n * @param code The source code to normalize\n * @param options Normalization options\n * @returns Normalized code string\n */\nexport function normalizeCode(\n code: string,\n options: NormalizationOptions = DEFAULT_NORMALIZATION_OPTIONS\n): string {\n let result = code;\n\n // Strip comments first\n if (options.stripComments) {\n result = stripComments(result);\n }\n\n // Apply semantic normalization\n if (options.normalizeSemantics) {\n result = applySemanticNormalization(result);\n }\n\n // Normalize identifiers (most aggressive, do last before whitespace)\n if (options.normalizeIdentifiers) {\n result = normalizeIdentifiersSimple(result);\n }\n\n // Normalize whitespace last\n if (options.normalizeWhitespace) {\n result = normalizeWhitespace(result);\n }\n\n return result;\n}\n\n/**\n * Calculate Levenshtein distance between two strings.\n * Used for fuzzy matching of normalized code.\n */\nexport function levenshteinDistance(a: string, b: string): number {\n // Early termination for identical strings\n if (a === b) return 0;\n\n // Early termination for empty strings\n if (a.length === 0) return b.length;\n if (b.length === 0) return a.length;\n\n // Use two-row optimization for memory efficiency\n let previousRow = new Array(b.length + 1);\n let currentRow = new Array(b.length + 1);\n\n // Initialize first row\n for (let j = 0; j <= b.length; j++) {\n previousRow[j] = j;\n }\n\n // Fill in the rest of the matrix\n for (let i = 1; i <= a.length; i++) {\n currentRow[0] = i;\n\n for (let j = 1; j <= b.length; j++) {\n const cost = a[i - 1] === b[j - 1] ? 0 : 1;\n currentRow[j] = Math.min(\n previousRow[j] + 1, // Deletion\n currentRow[j - 1] + 1, // Insertion\n previousRow[j - 1] + cost // Substitution\n );\n }\n\n // Swap rows\n [previousRow, currentRow] = [currentRow, previousRow];\n }\n\n return previousRow[b.length];\n}\n\n/**\n * Calculate normalized similarity between two code snippets.\n * Returns 1.0 for identical normalized code, lower for differences.\n *\n * @param codeA First code snippet\n * @param codeB Second code snippet\n * @param options Normalization options\n * @returns Similarity score between 0 and 1\n */\nexport function calculateNormalizedSimilarity(\n codeA: string,\n codeB: string,\n options: NormalizationOptions = { normalizeIdentifiers: true, normalizeSemantics: true }\n): number {\n const normalizedA = normalizeCode(codeA, options);\n const normalizedB = normalizeCode(codeB, options);\n\n // Exact match after normalization\n if (normalizedA === normalizedB) {\n return 1.0;\n }\n\n // Calculate Levenshtein-based similarity\n const distance = levenshteinDistance(normalizedA, normalizedB);\n const maxLen = Math.max(normalizedA.length, normalizedB.length);\n\n if (maxLen === 0) return 1.0;\n\n return 1 - distance / maxLen;\n}\n\n/**\n * Quick check if two code snippets are near-identical after normalization.\n *\n * @param codeA First code snippet\n * @param codeB Second code snippet\n * @param threshold Minimum similarity to consider near-identical (default: 0.95)\n * @returns True if the code is near-identical\n */\nexport function isNearIdentical(\n codeA: string,\n codeB: string,\n threshold: number = 0.95\n): boolean {\n return calculateNormalizedSimilarity(codeA, codeB) >= threshold;\n}\n\n/**\n * Prepare code for embedding by applying light normalization.\n * This is less aggressive than full normalization and is meant\n * to improve embedding quality without losing semantic meaning.\n *\n * @param code The source code\n * @returns Lightly normalized code for embedding\n */\nexport function prepareForEmbedding(code: string): string {\n return normalizeCode(code, {\n normalizeIdentifiers: false,\n normalizeSemantics: true,\n stripComments: true,\n normalizeWhitespace: false, // Preserve structure for embedding\n });\n}\n","/**\n * Combined Scorer\n *\n * Combines multiple similarity signals into a final score:\n * - Semantic similarity (from embeddings)\n * - Structural similarity (from metadata: props, JSX, hooks)\n * - Normalized similarity (from AST normalization - optional, expensive)\n *\n * The combined approach catches more duplicates than embedding alone:\n * - Structural catches same-structure/different-names cases\n * - Normalization catches copy-paste with renamed variables\n * - Semantic catches conceptually similar but differently structured code\n */\n\nimport type { StoredChunkMetadata } from \"../index/types.js\";\nimport {\n calculateStructuralSimilarity,\n type StructuralScore,\n} from \"./structural-scorer.js\";\nimport { calculateNormalizedSimilarity } from \"./normalizer.js\";\nimport {\n getConfidenceLevel,\n getConfidenceResult,\n type ConfidenceLevel,\n type ConfidenceResult,\n} from \"./confidence.js\";\n\nexport interface CombinedScore {\n /** Final combined score (0-1) */\n final: number;\n /** Semantic embedding similarity (0-1) */\n semantic: number;\n /** Structural metadata similarity (0-1) */\n structural: number;\n /** Detailed structural breakdown */\n structuralDetails: StructuralScore;\n /** Normalized code similarity (0-1, only if computed) */\n normalized?: number;\n /** Confidence level based on final score */\n confidence: ConfidenceLevel;\n /** Detailed confidence result */\n confidenceDetails: ConfidenceResult;\n}\n\nexport interface CombinedScorerOptions {\n /** Weight for semantic similarity (default: 0.5) */\n semanticWeight?: number;\n /** Weight for structural similarity (default: 0.3) */\n structuralWeight?: number;\n /** Weight for normalized similarity (default: 0.2) */\n normalizedWeight?: number;\n /** Whether to compute normalized similarity (expensive) */\n includeNormalized?: boolean;\n}\n\nexport const DEFAULT_COMBINED_SCORER_OPTIONS: Required<CombinedScorerOptions> = {\n semanticWeight: 0.5,\n structuralWeight: 0.3,\n normalizedWeight: 0.2,\n includeNormalized: false,\n};\n\n/**\n * Calculate combined similarity score using multiple signals.\n *\n * @param semanticScore Embedding-based similarity score (0-1)\n * @param metadataA Metadata for first chunk\n * @param metadataB Metadata for second chunk\n * @param codeA Source code of first chunk (optional, needed for normalization)\n * @param codeB Source code of second chunk (optional, needed for normalization)\n * @param options Scoring options\n * @returns Combined score with all components\n */\nexport function calculateCombinedScore(\n semanticScore: number,\n metadataA: StoredChunkMetadata,\n metadataB: StoredChunkMetadata,\n codeA?: string,\n codeB?: string,\n options: CombinedScorerOptions = {}\n): CombinedScore {\n const opts = { ...DEFAULT_COMBINED_SCORER_OPTIONS, ...options };\n\n // Calculate structural similarity\n const structuralDetails = calculateStructuralSimilarity(metadataA, metadataB);\n const structural = structuralDetails.combined;\n\n // Calculate normalized similarity if requested and code is available\n let normalized: number | undefined;\n if (opts.includeNormalized && codeA && codeB) {\n normalized = calculateNormalizedSimilarity(codeA, codeB);\n }\n\n // Calculate final score based on available signals\n let final: number;\n\n if (normalized !== undefined) {\n // All three signals available\n final =\n semanticScore * opts.semanticWeight +\n structural * opts.structuralWeight +\n normalized * opts.normalizedWeight;\n } else {\n // Only semantic and structural available\n // Redistribute normalized weight proportionally\n const totalWeight = opts.semanticWeight + opts.structuralWeight;\n const adjustedSemanticWeight = opts.semanticWeight / totalWeight;\n const adjustedStructuralWeight = opts.structuralWeight / totalWeight;\n\n final =\n semanticScore * adjustedSemanticWeight + structural * adjustedStructuralWeight;\n }\n\n // Boost score if any single signal is very high (catch obvious duplicates)\n final = applyBoostForHighSignals(final, semanticScore, structural, normalized);\n\n // Ensure final is clamped to [0, 1]\n final = Math.max(0, Math.min(1, final));\n\n const confidence = getConfidenceLevel(final);\n const confidenceDetails = getConfidenceResult(final);\n\n return {\n final,\n semantic: semanticScore,\n structural,\n structuralDetails,\n normalized,\n confidence,\n confidenceDetails,\n };\n}\n\n/**\n * Apply boost to final score if any individual signal is very high.\n * This ensures that obvious duplicates (e.g., 98% normalized similarity)\n * are not penalized by lower scores in other dimensions.\n */\nfunction applyBoostForHighSignals(\n baseScore: number,\n semantic: number,\n structural: number,\n normalized?: number\n): number {\n const HIGH_SIGNAL_THRESHOLD = 0.95;\n const BOOST_FACTOR = 0.1;\n\n let boost = 0;\n\n // If normalized similarity is very high, this is almost certainly a duplicate\n if (normalized !== undefined && normalized >= HIGH_SIGNAL_THRESHOLD) {\n boost = Math.max(boost, (normalized - HIGH_SIGNAL_THRESHOLD) * 2);\n }\n\n // If semantic similarity is very high\n if (semantic >= HIGH_SIGNAL_THRESHOLD) {\n boost = Math.max(boost, (semantic - HIGH_SIGNAL_THRESHOLD) * 1.5);\n }\n\n // If structural similarity is very high\n if (structural >= HIGH_SIGNAL_THRESHOLD) {\n boost = Math.max(boost, (structural - HIGH_SIGNAL_THRESHOLD) * 1.5);\n }\n\n return baseScore + boost * BOOST_FACTOR;\n}\n\n/**\n * Quick pre-filter check using only structural similarity.\n * Use this to avoid expensive embedding comparisons for obviously dissimilar code.\n *\n * @param metadataA First chunk metadata\n * @param metadataB Second chunk metadata\n * @param threshold Minimum structural similarity to consider (default: 0.3)\n * @returns True if chunks are potentially similar enough to warrant full comparison\n */\nexport function isPotentialDuplicate(\n metadataA: StoredChunkMetadata,\n metadataB: StoredChunkMetadata,\n threshold: number = 0.3\n): boolean {\n const structural = calculateStructuralSimilarity(metadataA, metadataB);\n return structural.combined >= threshold;\n}\n\n/**\n * Calculate quick similarity using only structural features.\n * Useful when embedding scores are not available.\n */\nexport function calculateQuickScore(\n metadataA: StoredChunkMetadata,\n metadataB: StoredChunkMetadata\n): { score: number; confidence: ConfidenceLevel } {\n const structural = calculateStructuralSimilarity(metadataA, metadataB);\n const confidence = getConfidenceLevel(structural.combined);\n return { score: structural.combined, confidence };\n}\n\n/**\n * Determine the best action based on combined score.\n */\nexport function getRecommendedAction(score: CombinedScore): string {\n if (score.normalized !== undefined && score.normalized >= 0.95) {\n return \"These appear to be near-identical. Consolidate into a single implementation.\";\n }\n\n if (score.final >= 0.9) {\n return \"High similarity detected. Strongly consider consolidating into a shared component/function.\";\n }\n\n if (score.final >= 0.75) {\n return \"Moderate similarity. Review for potential abstraction into a shared utility.\";\n }\n\n if (score.structural >= 0.8 && score.semantic < 0.7) {\n return \"Similar structure but different semantics. May be intentionally different implementations.\";\n }\n\n if (score.semantic >= 0.8 && score.structural < 0.5) {\n return \"Similar purpose but different structure. Consider if a common abstraction makes sense.\";\n }\n\n return \"Low similarity. Likely different implementations that happen to share some patterns.\";\n}\n\n/**\n * Format combined score for display.\n */\nexport function formatCombinedScore(score: CombinedScore, verbose: boolean = false): string {\n const percent = Math.round(score.final * 100);\n const lines: string[] = [];\n\n lines.push(`${percent}% similar (${score.confidence} confidence)`);\n\n if (verbose) {\n lines.push(` Semantic: ${Math.round(score.semantic * 100)}%`);\n lines.push(` Structural: ${Math.round(score.structural * 100)}%`);\n if (score.normalized !== undefined) {\n lines.push(` Normalized: ${Math.round(score.normalized * 100)}%`);\n }\n lines.push(` → ${getRecommendedAction(score)}`);\n }\n\n return lines.join(\"\\n\");\n}\n"],"mappings":"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","names":["existsSync","mkdirSync","readFileSync","writeFileSync","join","existsSync","mkdirSync","readFileSync","writeFileSync","join","existsSync","mkdirSync","readFileSync","writeFileSync","join","join","existsSync","readFileSync","mkdirSync","writeFileSync","calculateSizeRatio"]}
package/dist/index.js CHANGED
@@ -50,7 +50,7 @@ import {
50
50
  prepareForEmbedding,
51
51
  searchSimilar,
52
52
  sortDuplicateGroups
53
- } from "./chunk-7YAFHXIU.js";
53
+ } from "./chunk-F2HSHCUO.js";
54
54
  import {
55
55
  duplicatesPlugin
56
56
  } from "./chunk-FC6VOAQ7.js";
package/dist/node.js CHANGED
@@ -50,7 +50,7 @@ import {
50
50
  prepareForEmbedding,
51
51
  searchSimilar,
52
52
  sortDuplicateGroups
53
- } from "./chunk-7YAFHXIU.js";
53
+ } from "./chunk-F2HSHCUO.js";
54
54
  import {
55
55
  duplicatesPlugin
56
56
  } from "./chunk-FC6VOAQ7.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "uilint-duplicates",
3
- "version": "0.2.156",
3
+ "version": "0.2.158",
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.156",
79
- "uilint-eslint": "0.2.156"
78
+ "uilint-core": "0.2.158",
79
+ "uilint-eslint": "0.2.158"
80
80
  },
81
81
  "keywords": [
82
82
  "duplicate-detection",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/embeddings/chunker.ts","../src/embeddings/ollama-embeddings.ts","../src/query/api.ts","../src/cache/incremental-indexer.ts","../src/index/vector-store.ts","../src/index/metadata-store.ts","../src/cache/file-tracker.ts","../src/detection/scorer.ts","../src/detection/structural-scorer.ts","../src/detection/confidence.ts","../src/detection/duplicate-finder.ts","../src/detection/normalizer.ts","../src/detection/combined-scorer.ts"],"sourcesContent":["/**\n * Code chunker - extracts meaningful code units from TypeScript/TSX files\n *\n * Uses @typescript-eslint/typescript-estree for parsing.\n * Supports splitting large components into smaller, embeddable chunks.\n */\n\nimport { parse, TSESTree, AST_NODE_TYPES } from \"@typescript-eslint/typescript-estree\";\nimport type { CodeChunk, ChunkKind, ChunkMetadata, ChunkingOptions } from \"./types.js\";\n\nconst DEFAULT_MAX_LINES = 100;\nconst MIN_SECTION_LINES = 3;\n\n/**\n * Hash function for generating chunk IDs\n * Simple djb2 hash - consistent with existing codebase pattern\n */\nfunction hashChunk(content: string, filePath: string, startLine: number): string {\n let hash = 5381;\n const input = `${filePath}:${startLine}:${content}`;\n for (let i = 0; i < input.length; i++) {\n hash = (hash * 33) ^ input.charCodeAt(i);\n }\n return (hash >>> 0).toString(16).padStart(8, \"0\");\n}\n\n/**\n * Parse a file and extract code chunks\n */\nexport function chunkFile(\n filePath: string,\n content: string,\n options: ChunkingOptions = {}\n): CodeChunk[] {\n const {\n minLines = 3,\n maxLines = DEFAULT_MAX_LINES,\n includeAnonymous = false,\n kinds,\n splitStrategy = \"jsx-children\",\n } = options;\n\n // Parse the file\n let ast: TSESTree.Program;\n try {\n ast = parse(content, {\n jsx: true,\n loc: true,\n range: true,\n tokens: false,\n comment: false,\n });\n } catch (error) {\n // Return empty array if parsing fails\n console.warn(`Failed to parse ${filePath}:`, error);\n return [];\n }\n\n const chunks: CodeChunk[] = [];\n const lines = content.split(\"\\n\");\n\n // Track exports for metadata\n const exportedNames = new Set<string>();\n let defaultExportName: string | null = null;\n\n // First pass: collect exports\n for (const node of ast.body) {\n if (node.type === AST_NODE_TYPES.ExportNamedDeclaration) {\n if (node.declaration) {\n const names = getDeclarationNames(node.declaration);\n names.forEach((name) => exportedNames.add(name));\n }\n if (node.specifiers) {\n node.specifiers.forEach((spec) => {\n if (spec.type === AST_NODE_TYPES.ExportSpecifier) {\n exportedNames.add(\n spec.exported.type === AST_NODE_TYPES.Identifier\n ? spec.exported.name\n : spec.exported.value\n );\n }\n });\n }\n } else if (node.type === AST_NODE_TYPES.ExportDefaultDeclaration) {\n if (node.declaration.type === AST_NODE_TYPES.Identifier) {\n defaultExportName = node.declaration.name;\n } else if (\n node.declaration.type === AST_NODE_TYPES.FunctionDeclaration &&\n node.declaration.id\n ) {\n defaultExportName = node.declaration.id.name;\n }\n }\n }\n\n // Second pass: extract chunks\n function visit(node: TSESTree.Node) {\n // Check function declarations\n if (node.type === AST_NODE_TYPES.FunctionDeclaration && node.id) {\n const chunk = processFunction(\n node,\n node.id.name,\n filePath,\n content,\n lines,\n exportedNames,\n defaultExportName\n );\n if (chunk && shouldIncludeChunk(chunk, minLines, includeAnonymous, kinds)) {\n // Check if chunk needs splitting\n const lineCount = chunk.endLine - chunk.startLine + 1;\n if (lineCount > maxLines && splitStrategy !== \"none\") {\n const splitChunks = splitLargeChunk(node, chunk, content, lines, maxLines, splitStrategy);\n chunks.push(...splitChunks.filter(c => shouldIncludeChunk(c, minLines, includeAnonymous, kinds)));\n } else {\n chunks.push(chunk);\n }\n }\n }\n\n // Check variable declarations with arrow functions\n if (node.type === AST_NODE_TYPES.VariableDeclaration) {\n for (const decl of node.declarations) {\n if (\n decl.id.type === AST_NODE_TYPES.Identifier &&\n decl.init &&\n (decl.init.type === AST_NODE_TYPES.ArrowFunctionExpression ||\n decl.init.type === AST_NODE_TYPES.FunctionExpression)\n ) {\n const chunk = processFunction(\n decl.init,\n decl.id.name,\n filePath,\n content,\n lines,\n exportedNames,\n defaultExportName,\n node // Use the variable declaration for location\n );\n if (chunk && shouldIncludeChunk(chunk, minLines, includeAnonymous, kinds)) {\n // Check if chunk needs splitting\n const lineCount = chunk.endLine - chunk.startLine + 1;\n if (lineCount > maxLines && splitStrategy !== \"none\") {\n const splitChunks = splitLargeChunk(decl.init, chunk, content, lines, maxLines, splitStrategy);\n chunks.push(...splitChunks.filter(c => shouldIncludeChunk(c, minLines, includeAnonymous, kinds)));\n } else {\n chunks.push(chunk);\n }\n }\n }\n }\n }\n\n // Recursively visit children\n for (const key of Object.keys(node)) {\n if (key === \"parent\" || key === \"loc\" || key === \"range\") continue;\n\n const child = (node as unknown as Record<string, unknown>)[key];\n if (child && typeof child === \"object\") {\n if (Array.isArray(child)) {\n child.forEach((c) => {\n if (c && typeof c === \"object\" && \"type\" in c) {\n visit(c as TSESTree.Node);\n }\n });\n } else if (\"type\" in child) {\n visit(child as TSESTree.Node);\n }\n }\n }\n }\n\n visit(ast);\n return chunks;\n}\n\nfunction processFunction(\n node:\n | TSESTree.FunctionDeclaration\n | TSESTree.ArrowFunctionExpression\n | TSESTree.FunctionExpression,\n name: string,\n filePath: string,\n content: string,\n lines: string[],\n exportedNames: Set<string>,\n defaultExportName: string | null,\n locationNode?: TSESTree.Node\n): CodeChunk | null {\n const loc = (locationNode || node).loc;\n if (!loc) return null;\n\n const startLine = loc.start.line;\n const endLine = loc.end.line;\n const startColumn = loc.start.column;\n const endColumn = loc.end.column;\n\n // Extract the chunk content\n const chunkContent = lines.slice(startLine - 1, endLine).join(\"\\n\");\n\n // Determine the kind\n const kind = classifyFunction(name, node);\n\n // Extract metadata\n const metadata = extractMetadata(node, name, exportedNames, defaultExportName);\n\n return {\n id: hashChunk(chunkContent, filePath, startLine),\n filePath,\n startLine,\n endLine,\n startColumn,\n endColumn,\n kind,\n name,\n content: chunkContent,\n metadata,\n };\n}\n\nfunction classifyFunction(\n name: string,\n node:\n | TSESTree.FunctionDeclaration\n | TSESTree.ArrowFunctionExpression\n | TSESTree.FunctionExpression\n): ChunkKind {\n // Check for hook (useXxx pattern)\n if (/^use[A-Z]/.test(name)) {\n return \"hook\";\n }\n\n // Check for component (PascalCase + returns JSX)\n if (/^[A-Z]/.test(name) && containsJSX(node)) {\n return \"component\";\n }\n\n // Check for JSX fragment (returns JSX but not PascalCase)\n if (containsJSX(node)) {\n return \"jsx-fragment\";\n }\n\n return \"function\";\n}\n\nfunction containsJSX(node: TSESTree.Node): boolean {\n let found = false;\n\n function search(n: TSESTree.Node) {\n if (found) return;\n if (n.type === AST_NODE_TYPES.JSXElement || n.type === AST_NODE_TYPES.JSXFragment) {\n found = true;\n return;\n }\n for (const key of Object.keys(n)) {\n if (key === \"parent\" || key === \"loc\" || key === \"range\") continue;\n\n const child = (n as unknown as Record<string, unknown>)[key];\n if (child && typeof child === \"object\") {\n if (Array.isArray(child)) {\n child.forEach((c) => {\n if (c && typeof c === \"object\" && \"type\" in c) {\n search(c as TSESTree.Node);\n }\n });\n } else if (\"type\" in child) {\n search(child as TSESTree.Node);\n }\n }\n }\n }\n\n search(node);\n return found;\n}\n\nfunction extractMetadata(\n node:\n | TSESTree.FunctionDeclaration\n | TSESTree.ArrowFunctionExpression\n | TSESTree.FunctionExpression,\n name: string,\n exportedNames: Set<string>,\n defaultExportName: string | null\n): ChunkMetadata {\n const metadata: ChunkMetadata = {\n isExported: exportedNames.has(name) || defaultExportName === name,\n isDefaultExport: defaultExportName === name,\n };\n\n // Extract props from parameters\n const params = node.params;\n if (params.length > 0) {\n const firstParam = params[0];\n const props = extractPropsFromParam(firstParam);\n if (props.length > 0) {\n metadata.props = props;\n }\n }\n\n // Extract hooks and JSX elements\n const hooks: string[] = [];\n const jsxElements: string[] = [];\n\n function searchForHooksAndJSX(n: TSESTree.Node) {\n // Find hook calls\n if (\n n.type === AST_NODE_TYPES.CallExpression &&\n n.callee.type === AST_NODE_TYPES.Identifier &&\n /^use[A-Z]/.test(n.callee.name)\n ) {\n hooks.push(n.callee.name);\n }\n\n // Find JSX elements\n if (n.type === AST_NODE_TYPES.JSXOpeningElement) {\n if (n.name.type === AST_NODE_TYPES.JSXIdentifier) {\n jsxElements.push(n.name.name);\n } else if (n.name.type === AST_NODE_TYPES.JSXMemberExpression) {\n // Handle React.Fragment, etc.\n const parts: string[] = [];\n let current: TSESTree.JSXMemberExpression | TSESTree.JSXIdentifier = n.name;\n while (current.type === AST_NODE_TYPES.JSXMemberExpression) {\n if (current.property.type === AST_NODE_TYPES.JSXIdentifier) {\n parts.unshift(current.property.name);\n }\n current = current.object as TSESTree.JSXMemberExpression | TSESTree.JSXIdentifier;\n }\n if (current.type === AST_NODE_TYPES.JSXIdentifier) {\n parts.unshift(current.name);\n }\n jsxElements.push(parts.join(\".\"));\n }\n }\n\n // Recurse\n for (const key of Object.keys(n)) {\n if (key === \"parent\" || key === \"loc\" || key === \"range\") continue;\n\n const child = (n as unknown as Record<string, unknown>)[key];\n if (child && typeof child === \"object\") {\n if (Array.isArray(child)) {\n child.forEach((c) => {\n if (c && typeof c === \"object\" && \"type\" in c) {\n searchForHooksAndJSX(c as TSESTree.Node);\n }\n });\n } else if (\"type\" in child) {\n searchForHooksAndJSX(child as TSESTree.Node);\n }\n }\n }\n }\n\n searchForHooksAndJSX(node);\n\n if (hooks.length > 0) {\n metadata.hooks = [...new Set(hooks)]; // Deduplicate\n }\n if (jsxElements.length > 0) {\n metadata.jsxElements = [...new Set(jsxElements)]; // Deduplicate\n }\n\n return metadata;\n}\n\nfunction extractPropsFromParam(param: TSESTree.Parameter): string[] {\n const props: string[] = [];\n\n if (param.type === AST_NODE_TYPES.ObjectPattern) {\n for (const prop of param.properties) {\n if (prop.type === AST_NODE_TYPES.Property && prop.key.type === AST_NODE_TYPES.Identifier) {\n props.push(prop.key.name);\n } else if (\n prop.type === AST_NODE_TYPES.RestElement &&\n prop.argument.type === AST_NODE_TYPES.Identifier\n ) {\n props.push(`...${prop.argument.name}`);\n }\n }\n } else if (param.type === AST_NODE_TYPES.Identifier) {\n props.push(param.name);\n }\n\n return props;\n}\n\nfunction getDeclarationNames(\n decl:\n | TSESTree.FunctionDeclaration\n | TSESTree.VariableDeclaration\n | TSESTree.ClassDeclaration\n | TSESTree.TSInterfaceDeclaration\n | TSESTree.TSTypeAliasDeclaration\n | TSESTree.TSEnumDeclaration\n | TSESTree.TSModuleDeclaration\n | TSESTree.TSDeclareFunction\n | TSESTree.TSImportEqualsDeclaration\n): string[] {\n const names: string[] = [];\n\n if (decl.type === AST_NODE_TYPES.FunctionDeclaration && decl.id) {\n names.push(decl.id.name);\n } else if (decl.type === AST_NODE_TYPES.VariableDeclaration) {\n for (const d of decl.declarations) {\n if (d.id.type === AST_NODE_TYPES.Identifier) {\n names.push(d.id.name);\n }\n }\n } else if (decl.type === AST_NODE_TYPES.ClassDeclaration && decl.id) {\n names.push(decl.id.name);\n }\n\n return names;\n}\n\nfunction shouldIncludeChunk(\n chunk: CodeChunk,\n minLines: number,\n includeAnonymous: boolean,\n kinds?: ChunkKind[]\n): boolean {\n const lineCount = chunk.endLine - chunk.startLine + 1;\n if (lineCount < minLines) {\n return false;\n }\n if (!includeAnonymous && chunk.name === null) {\n return false;\n }\n if (kinds && !kinds.includes(chunk.kind)) {\n return false;\n }\n return true;\n}\n\n/** Maximum characters for embedding input (safe limit for nomic-embed-text with 2048 token context) */\nconst DEFAULT_MAX_EMBEDDING_CHARS = 6000;\n\nexport interface EmbeddingInputOptions {\n /** Maximum characters for the embedding input (default: 6000) */\n maxChars?: number;\n}\n\n/**\n * Prepare chunk content for embedding by enriching with context\n */\nexport function prepareEmbeddingInput(\n chunk: CodeChunk,\n options: EmbeddingInputOptions = {}\n): string {\n const { maxChars = DEFAULT_MAX_EMBEDDING_CHARS } = options;\n const parts: string[] = [];\n\n // Add structural context based on kind\n if (chunk.kind === \"component\") {\n parts.push(`React component: ${chunk.name || \"anonymous\"}`);\n if (chunk.metadata.props?.length) {\n parts.push(`Props: ${chunk.metadata.props.join(\", \")}`);\n }\n } else if (chunk.kind === \"component-summary\") {\n parts.push(`React component summary: ${chunk.name || \"anonymous\"}`);\n if (chunk.metadata.props?.length) {\n parts.push(`Props: ${chunk.metadata.props.join(\", \")}`);\n }\n parts.push(\"(Large component - see sections for JSX details)\");\n } else if (chunk.kind === \"jsx-section\") {\n const parentName = chunk.name || \"anonymous\";\n const label = chunk.sectionLabel || `section-${chunk.sectionIndex}`;\n parts.push(`JSX section from ${parentName}: ${label}`);\n } else if (chunk.kind === \"hook\") {\n parts.push(`React hook: ${chunk.name || \"anonymous\"}`);\n } else if (chunk.kind === \"function\") {\n parts.push(`Function: ${chunk.name || \"anonymous\"}`);\n } else if (chunk.kind === \"function-summary\") {\n parts.push(`Function summary: ${chunk.name || \"anonymous\"}`);\n parts.push(\"(Large function - split into sections)\");\n } else if (chunk.kind === \"function-section\") {\n const parentName = chunk.name || \"anonymous\";\n const label = chunk.sectionLabel || `section-${chunk.sectionIndex}`;\n parts.push(`Function section from ${parentName}: ${label}`);\n } else if (chunk.kind === \"jsx-fragment\") {\n parts.push(`JSX fragment: ${chunk.name || \"anonymous\"}`);\n }\n\n // Add the code\n parts.push(chunk.content);\n\n // Add JSX structure for components\n if (chunk.metadata.jsxElements?.length) {\n parts.push(`JSX elements: ${chunk.metadata.jsxElements.join(\", \")}`);\n }\n\n // Add hooks used\n if (chunk.metadata.hooks?.length) {\n parts.push(`Hooks used: ${chunk.metadata.hooks.join(\", \")}`);\n }\n\n let result = parts.join(\"\\n\\n\");\n\n // Truncate if exceeds max chars (safety net for edge cases)\n if (result.length > maxChars) {\n result = result.slice(0, maxChars - 50) + \"\\n\\n[... content truncated for embedding ...]\";\n }\n\n return result;\n}\n\n// ============================================================================\n// Large Component Splitting\n// ============================================================================\n\n/**\n * Split a large chunk into smaller chunks\n * For components, tries JSX-based splitting first, then falls back to line-based\n * For functions/hooks, uses line-based splitting\n */\nfunction splitLargeChunk(\n node: TSESTree.FunctionDeclaration | TSESTree.ArrowFunctionExpression | TSESTree.FunctionExpression,\n originalChunk: CodeChunk,\n content: string,\n lines: string[],\n maxLines: number,\n strategy: \"jsx-children\" | \"line-based\"\n): CodeChunk[] {\n // Only try JSX splitting for components\n if (strategy === \"jsx-children\" && originalChunk.kind === \"component\") {\n const jsxChunks = splitByJSXChildren(node, originalChunk, content, lines);\n if (jsxChunks.length > 0) {\n return jsxChunks;\n }\n // Fall back to line-based if no JSX children found\n }\n\n return splitByLines(originalChunk, lines, maxLines);\n}\n\n/**\n * Split a component by its top-level JSX children\n */\nfunction splitByJSXChildren(\n node: TSESTree.FunctionDeclaration | TSESTree.ArrowFunctionExpression | TSESTree.FunctionExpression,\n originalChunk: CodeChunk,\n content: string,\n lines: string[]\n): CodeChunk[] {\n // Find the return statement with JSX\n const returnStatement = findJSXReturnStatement(node);\n if (!returnStatement || !returnStatement.argument) {\n return [];\n }\n\n // Get the root JSX element\n const jsxRoot = getJSXRoot(returnStatement.argument);\n if (!jsxRoot) {\n return [];\n }\n\n // Get significant JSX children\n const children = getSignificantJSXChildren(jsxRoot);\n if (children.length < 2) {\n // Not worth splitting if there's only one child\n return [];\n }\n\n const chunks: CodeChunk[] = [];\n\n // Create a summary chunk (signature + hooks + state, without the full JSX)\n const summaryChunk = createSummaryChunk(node, originalChunk, returnStatement, lines);\n chunks.push(summaryChunk);\n\n // Create section chunks for each significant JSX child\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n const sectionChunk = createJSXSectionChunk(\n originalChunk,\n child,\n lines,\n i,\n summaryChunk.id\n );\n if (sectionChunk) {\n chunks.push(sectionChunk);\n }\n }\n\n return chunks;\n}\n\n/**\n * Find the return statement containing JSX\n */\nfunction findJSXReturnStatement(\n node: TSESTree.FunctionDeclaration | TSESTree.ArrowFunctionExpression | TSESTree.FunctionExpression\n): TSESTree.ReturnStatement | null {\n // For arrow functions with expression body, create a synthetic return\n if (node.type === AST_NODE_TYPES.ArrowFunctionExpression && node.expression) {\n if (isJSXNode(node.body)) {\n return {\n type: AST_NODE_TYPES.ReturnStatement,\n argument: node.body as TSESTree.Expression,\n loc: node.body.loc,\n range: node.body.range,\n parent: node as unknown as TSESTree.Node,\n } as TSESTree.ReturnStatement;\n }\n return null;\n }\n\n // For function bodies, find the return statement\n const body = node.body;\n if (body.type !== AST_NODE_TYPES.BlockStatement) {\n return null;\n }\n\n // Look for return statements in the body (not nested in other blocks)\n for (const stmt of body.body) {\n if (stmt.type === AST_NODE_TYPES.ReturnStatement && stmt.argument && isJSXNode(stmt.argument)) {\n return stmt;\n }\n }\n\n return null;\n}\n\n/**\n * Check if a node is a JSX element or fragment\n */\nfunction isJSXNode(node: TSESTree.Node): boolean {\n return (\n node.type === AST_NODE_TYPES.JSXElement ||\n node.type === AST_NODE_TYPES.JSXFragment\n );\n}\n\n/**\n * Get the root JSX element, unwrapping parentheses and fragments if needed\n */\nfunction getJSXRoot(\n node: TSESTree.Expression\n): TSESTree.JSXElement | TSESTree.JSXFragment | null {\n // Handle parenthesized expressions\n if (node.type === AST_NODE_TYPES.JSXElement) {\n return node;\n }\n if (node.type === AST_NODE_TYPES.JSXFragment) {\n return node;\n }\n return null;\n}\n\n/**\n * Get significant JSX children (skip whitespace-only text nodes)\n */\nfunction getSignificantJSXChildren(\n jsxRoot: TSESTree.JSXElement | TSESTree.JSXFragment\n): TSESTree.JSXChild[] {\n const children: TSESTree.JSXChild[] = [];\n\n for (const child of jsxRoot.children) {\n // Skip JSXText that's just whitespace\n if (child.type === AST_NODE_TYPES.JSXText) {\n if (child.value.trim() === \"\") {\n continue;\n }\n }\n\n // Include JSX elements, expressions, and non-empty text\n if (\n child.type === AST_NODE_TYPES.JSXElement ||\n child.type === AST_NODE_TYPES.JSXFragment ||\n child.type === AST_NODE_TYPES.JSXExpressionContainer\n ) {\n children.push(child);\n }\n }\n\n return children;\n}\n\n/**\n * Create a summary chunk containing function signature, hooks, and state\n */\nfunction createSummaryChunk(\n node: TSESTree.FunctionDeclaration | TSESTree.ArrowFunctionExpression | TSESTree.FunctionExpression,\n originalChunk: CodeChunk,\n returnStatement: TSESTree.ReturnStatement,\n lines: string[]\n): CodeChunk {\n // Get lines from function start to just before the return statement\n const startLine = originalChunk.startLine;\n const returnLine = returnStatement.loc?.start.line || originalChunk.endLine;\n\n // Include the first line of the return (e.g., \"return (\") but not the JSX body\n const summaryEndLine = Math.min(returnLine, originalChunk.endLine);\n\n // Extract the summary content\n const summaryLines = lines.slice(startLine - 1, summaryEndLine);\n\n // Add closing brace to make it syntactically valid-ish\n const summaryContent = summaryLines.join(\"\\n\") + \"\\n // ... JSX content (see sections)\\n );\";\n\n return {\n id: hashChunk(summaryContent, originalChunk.filePath, startLine),\n filePath: originalChunk.filePath,\n startLine: startLine,\n endLine: summaryEndLine,\n startColumn: originalChunk.startColumn,\n endColumn: originalChunk.endColumn,\n kind: \"component-summary\",\n name: originalChunk.name,\n content: summaryContent,\n metadata: {\n ...originalChunk.metadata,\n // Keep hooks but clear JSX elements (they're in the sections)\n jsxElements: undefined,\n },\n };\n}\n\n/**\n * Create a JSX section chunk from a JSX child element\n */\nfunction createJSXSectionChunk(\n originalChunk: CodeChunk,\n jsxChild: TSESTree.JSXChild,\n lines: string[],\n index: number,\n parentId: string\n): CodeChunk | null {\n const loc = jsxChild.loc;\n if (!loc) {\n return null;\n }\n\n const startLine = loc.start.line;\n const endLine = loc.end.line;\n const lineCount = endLine - startLine + 1;\n\n // Skip very small sections\n if (lineCount < MIN_SECTION_LINES) {\n return null;\n }\n\n // Extract the content\n const sectionContent = lines.slice(startLine - 1, endLine).join(\"\\n\");\n\n // Infer a label from the JSX element\n const label = inferSectionLabel(jsxChild, index);\n\n // Extract JSX elements in this section\n const jsxElements = extractJSXElementsFromNode(jsxChild);\n\n return {\n id: hashChunk(sectionContent, originalChunk.filePath, startLine),\n filePath: originalChunk.filePath,\n startLine,\n endLine,\n startColumn: loc.start.column,\n endColumn: loc.end.column,\n kind: \"jsx-section\",\n name: originalChunk.name,\n content: sectionContent,\n metadata: {\n jsxElements: jsxElements.length > 0 ? jsxElements : undefined,\n isExported: originalChunk.metadata.isExported,\n isDefaultExport: originalChunk.metadata.isDefaultExport,\n },\n parentId,\n sectionIndex: index,\n sectionLabel: label,\n };\n}\n\n/**\n * Infer a human-readable label for a JSX section\n */\nfunction inferSectionLabel(jsxChild: TSESTree.JSXChild, index: number): string {\n if (jsxChild.type === AST_NODE_TYPES.JSXElement) {\n const opening = jsxChild.openingElement;\n\n // Try to get a meaningful name from attributes\n for (const attr of opening.attributes) {\n if (attr.type === AST_NODE_TYPES.JSXAttribute && attr.name.type === AST_NODE_TYPES.JSXIdentifier) {\n const attrName = attr.name.name;\n\n // Look for common identifying attributes\n if (attrName === \"aria-label\" || attrName === \"aria-labelledby\") {\n if (attr.value?.type === AST_NODE_TYPES.Literal && typeof attr.value.value === \"string\") {\n return attr.value.value.toLowerCase().replace(/\\s+/g, \"-\").slice(0, 30);\n }\n }\n\n // Check className for semantic hints\n if (attrName === \"className\" || attrName === \"class\") {\n if (attr.value?.type === AST_NODE_TYPES.Literal && typeof attr.value.value === \"string\") {\n const className = attr.value.value;\n // Extract first meaningful class\n const classes = className.split(/\\s+/);\n for (const cls of classes) {\n // Skip utility classes (Tailwind patterns)\n if (!cls.match(/^(bg-|text-|p-|m-|w-|h-|flex|grid|border|rounded|shadow|hover:|focus:)/)) {\n return cls.slice(0, 30);\n }\n }\n }\n }\n }\n }\n\n // Fall back to element name\n if (opening.name.type === AST_NODE_TYPES.JSXIdentifier) {\n return `${opening.name.name}-${index}`;\n }\n }\n\n return `section-${index}`;\n}\n\n/**\n * Extract JSX element names from a node\n */\nfunction extractJSXElementsFromNode(node: TSESTree.Node): string[] {\n const elements: string[] = [];\n\n function search(n: TSESTree.Node) {\n if (n.type === AST_NODE_TYPES.JSXOpeningElement) {\n if (n.name.type === AST_NODE_TYPES.JSXIdentifier) {\n elements.push(n.name.name);\n } else if (n.name.type === AST_NODE_TYPES.JSXMemberExpression) {\n const parts: string[] = [];\n let current: TSESTree.JSXMemberExpression | TSESTree.JSXIdentifier = n.name;\n while (current.type === AST_NODE_TYPES.JSXMemberExpression) {\n if (current.property.type === AST_NODE_TYPES.JSXIdentifier) {\n parts.unshift(current.property.name);\n }\n current = current.object as TSESTree.JSXMemberExpression | TSESTree.JSXIdentifier;\n }\n if (current.type === AST_NODE_TYPES.JSXIdentifier) {\n parts.unshift(current.name);\n }\n elements.push(parts.join(\".\"));\n }\n }\n\n // Recurse\n for (const key of Object.keys(n)) {\n if (key === \"parent\" || key === \"loc\" || key === \"range\") continue;\n\n const child = (n as unknown as Record<string, unknown>)[key];\n if (child && typeof child === \"object\") {\n if (Array.isArray(child)) {\n child.forEach((c) => {\n if (c && typeof c === \"object\" && \"type\" in c) {\n search(c as TSESTree.Node);\n }\n });\n } else if (\"type\" in child) {\n search(child as TSESTree.Node);\n }\n }\n }\n }\n\n search(node);\n return [...new Set(elements)];\n}\n\n/**\n * Split a chunk by line count (fallback strategy)\n */\nfunction splitByLines(\n originalChunk: CodeChunk,\n lines: string[],\n maxLines: number\n): CodeChunk[] {\n const totalLines = originalChunk.endLine - originalChunk.startLine + 1;\n\n // If it fits, return as-is\n if (totalLines <= maxLines) {\n return [originalChunk];\n }\n\n // Determine the appropriate kinds based on original chunk type\n const isComponent = originalChunk.kind === \"component\" || originalChunk.kind === \"jsx-fragment\";\n const summaryKind: ChunkKind = isComponent ? \"component-summary\" : \"function-summary\";\n const sectionKind: ChunkKind = isComponent ? \"jsx-section\" : \"function-section\";\n\n const chunks: CodeChunk[] = [];\n const overlap = Math.min(10, Math.floor(maxLines / 5)); // 10 lines overlap, or 20% of maxLines\n\n let currentStart = originalChunk.startLine;\n let sectionIndex = 0;\n\n while (currentStart <= originalChunk.endLine) {\n const currentEnd = Math.min(currentStart + maxLines - 1, originalChunk.endLine);\n const sectionContent = lines.slice(currentStart - 1, currentEnd).join(\"\\n\");\n\n const isFirstSection = sectionIndex === 0;\n\n chunks.push({\n id: hashChunk(sectionContent, originalChunk.filePath, currentStart),\n filePath: originalChunk.filePath,\n startLine: currentStart,\n endLine: currentEnd,\n startColumn: isFirstSection ? originalChunk.startColumn : 0,\n endColumn: currentEnd === originalChunk.endLine ? originalChunk.endColumn : lines[currentEnd - 1]?.length || 0,\n kind: isFirstSection ? summaryKind : sectionKind,\n name: originalChunk.name,\n content: sectionContent,\n metadata: isFirstSection ? originalChunk.metadata : {\n isExported: originalChunk.metadata.isExported,\n isDefaultExport: originalChunk.metadata.isDefaultExport,\n },\n parentId: isFirstSection ? undefined : chunks[0]?.id,\n sectionIndex: isFirstSection ? undefined : sectionIndex,\n sectionLabel: isFirstSection ? undefined : `lines-${currentStart}-${currentEnd}`,\n });\n\n // Move to next section with overlap\n currentStart = currentEnd - overlap + 1;\n sectionIndex++;\n\n // Prevent infinite loop\n if (currentStart <= originalChunk.startLine + sectionIndex * (maxLines - overlap)) {\n currentStart = originalChunk.startLine + sectionIndex * (maxLines - overlap);\n }\n }\n\n return chunks;\n}\n","/**\n * Ollama Embedding Client\n *\n * Uses Ollama's /api/embed endpoint to generate text embeddings.\n * Follows the patterns from uilint-core's OllamaClient.\n */\n\nconst DEFAULT_BASE_URL = \"http://localhost:11434\";\nconst DEFAULT_MODEL = \"nomic-embed-text\";\nconst DEFAULT_TIMEOUT = 60000;\nconst DEFAULT_BATCH_SIZE = 10;\n\nexport interface EmbeddingOptions {\n /** Ollama embedding model (default: nomic-embed-text) */\n model?: string;\n /** Ollama server URL (default: http://localhost:11434) */\n baseUrl?: string;\n /** Request timeout in ms (default: 60000) */\n timeout?: number;\n /** Batch size for embedding multiple texts (default: 10) */\n batchSize?: number;\n}\n\nexport interface EmbeddingResult {\n /** The embedding vector */\n embedding: number[];\n /** The model used */\n model: string;\n /** Number of tokens in the input (if available) */\n promptTokens?: number;\n}\n\nexport class OllamaEmbeddingClient {\n private baseUrl: string;\n private model: string;\n private timeout: number;\n private batchSize: number;\n\n constructor(options: EmbeddingOptions = {}) {\n this.baseUrl = options.baseUrl || DEFAULT_BASE_URL;\n this.model = options.model || DEFAULT_MODEL;\n this.timeout = options.timeout || DEFAULT_TIMEOUT;\n this.batchSize = options.batchSize || DEFAULT_BATCH_SIZE;\n }\n\n /**\n * Generate embedding for a single text\n */\n async embed(text: string): Promise<EmbeddingResult> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n const response = await fetch(`${this.baseUrl}/api/embed`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n model: this.model,\n input: text,\n }),\n signal: controller.signal,\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Ollama API error (${response.status}): ${errorText}`);\n }\n\n const data = await response.json();\n\n // Ollama returns embeddings in an array even for single input\n const embedding = data.embeddings?.[0] || data.embedding;\n\n if (!embedding || !Array.isArray(embedding)) {\n throw new Error(\"Invalid embedding response from Ollama\");\n }\n\n return {\n embedding,\n model: this.model,\n promptTokens: data.prompt_eval_count,\n };\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n /**\n * Generate embeddings for multiple texts\n * Automatically batches large inputs\n */\n async embedBatch(texts: string[]): Promise<EmbeddingResult[]> {\n if (texts.length === 0) {\n return [];\n }\n\n // If small enough, embed all at once\n if (texts.length <= this.batchSize) {\n return this.embedBatchDirect(texts);\n }\n\n // Otherwise, process in batches\n const results: EmbeddingResult[] = [];\n for (let i = 0; i < texts.length; i += this.batchSize) {\n const batch = texts.slice(i, i + this.batchSize);\n const batchResults = await this.embedBatchDirect(batch);\n results.push(...batchResults);\n }\n return results;\n }\n\n /**\n * Embed a batch directly (no chunking)\n */\n private async embedBatchDirect(texts: string[]): Promise<EmbeddingResult[]> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n const response = await fetch(`${this.baseUrl}/api/embed`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n model: this.model,\n input: texts,\n }),\n signal: controller.signal,\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Ollama API error (${response.status}): ${errorText}`);\n }\n\n const data = await response.json();\n const embeddings: number[][] = data.embeddings;\n\n if (!embeddings || !Array.isArray(embeddings)) {\n throw new Error(\"Invalid batch embedding response from Ollama\");\n }\n\n return embeddings.map((embedding) => ({\n embedding,\n model: this.model,\n }));\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n /**\n * Check if Ollama is available\n */\n async isAvailable(): Promise<boolean> {\n try {\n const response = await fetch(`${this.baseUrl}/api/tags`, {\n method: \"GET\",\n signal: AbortSignal.timeout(5000),\n });\n return response.ok;\n } catch {\n return false;\n }\n }\n\n /**\n * Check if the embedding model is available\n */\n async isModelAvailable(): Promise<boolean> {\n try {\n const response = await fetch(`${this.baseUrl}/api/tags`, {\n method: \"GET\",\n signal: AbortSignal.timeout(5000),\n });\n\n if (!response.ok) return false;\n\n const data = await response.json();\n const models = data.models || [];\n\n return models.some(\n (m: { name: string }) =>\n m.name === this.model || m.name.startsWith(`${this.model}:`)\n );\n } catch {\n return false;\n }\n }\n\n /**\n * Pull the embedding model if not available\n */\n async ensureModel(): Promise<void> {\n const available = await this.isModelAvailable();\n if (available) return;\n\n console.log(`Pulling embedding model ${this.model}...`);\n\n const response = await fetch(`${this.baseUrl}/api/pull`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n model: this.model,\n stream: false,\n }),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Failed to pull model ${this.model}: ${errorText}`);\n }\n }\n\n /**\n * Get the embedding dimension for the current model\n * (Requires generating a test embedding)\n */\n async getEmbeddingDimension(): Promise<number> {\n const result = await this.embed(\"test\");\n return result.embedding.length;\n }\n\n /**\n * Get the current model name\n */\n getModel(): string {\n return this.model;\n }\n\n /**\n * Set the model name\n */\n setModel(model: string): void {\n this.model = model;\n }\n}\n\n// Default singleton instance\nlet defaultClient: OllamaEmbeddingClient | null = null;\n\nexport function getOllamaEmbeddingClient(\n options?: EmbeddingOptions\n): OllamaEmbeddingClient {\n if (!defaultClient || options) {\n defaultClient = new OllamaEmbeddingClient(options);\n }\n return defaultClient;\n}\n","/**\n * Query API for semantic duplicate detection\n *\n * High-level API for indexing, finding duplicates, and semantic search.\n */\n\nimport { resolve } from \"path\";\nimport type { ChunkKind } from \"../embeddings/types.js\";\nimport {\n IncrementalIndexer,\n createIndexer,\n type IndexerOptions,\n type IndexUpdateResult,\n} from \"../cache/incremental-indexer.js\";\nimport {\n findDuplicateGroups,\n findSimilarToLocation,\n findSimilarToQuery,\n} from \"../detection/duplicate-finder.js\";\nimport { OllamaEmbeddingClient } from \"../embeddings/ollama-embeddings.js\";\n\nexport interface IndexOptions {\n /** Embedding model to use */\n model?: string;\n /** Ollama server URL */\n baseUrl?: string;\n /** Glob patterns to exclude */\n exclude?: string[];\n /** Force reindex from scratch */\n force?: boolean;\n /** Progress callback */\n onProgress?: (message: string, current?: number, total?: number) => void;\n}\n\nexport interface FindDuplicatesOptions {\n /** Path to search (defaults to current directory) */\n path?: string;\n /** Minimum similarity threshold (0-1). Default: 0.75 */\n threshold?: number;\n /** Minimum group size. Default: 2 */\n minGroupSize?: number;\n /** Filter by kind: component, hook, function */\n kind?: ChunkKind;\n /** Minimum confidence level: \"high\", \"medium\", \"low\". Default: \"low\" */\n confidenceLevel?: \"high\" | \"medium\" | \"low\";\n /** Use structural similarity boost. Default: true */\n useStructuralBoost?: boolean;\n /** Include duplicates within the same file. Default: true */\n includeSameFile?: boolean;\n}\n\nexport interface SearchOptions {\n /** Path to search (defaults to current directory) */\n path?: string;\n /** Number of results to return. Default: 10 */\n top?: number;\n /** Minimum similarity threshold. Default: 0.5 */\n threshold?: number;\n /** Embedding model to use */\n model?: string;\n /** Ollama server URL */\n baseUrl?: string;\n}\n\nexport interface SimilarLocationOptions extends SearchOptions {\n /** File path containing the code */\n filePath: string;\n /** Line number in the file */\n line: number;\n}\n\nexport interface DuplicateGroupMember {\n /** File path */\n filePath: string;\n /** Start line */\n startLine: number;\n /** End line */\n endLine: number;\n /** Chunk name (component/function/hook name) */\n name: string | null;\n /** Kind of code */\n kind: ChunkKind;\n /** Similarity score (1.0 for the reference member) */\n score: number;\n}\n\nexport interface DuplicateGroup {\n /** Members of the duplicate group */\n members: DuplicateGroupMember[];\n /** Average similarity between all group members */\n avgSimilarity: number;\n /** The kind of code in this group */\n kind: ChunkKind;\n /** Confidence level for this group */\n confidence: \"high\" | \"medium\" | \"low\";\n}\n\nexport interface SearchResult {\n /** File path */\n filePath: string;\n /** Start line */\n startLine: number;\n /** End line */\n endLine: number;\n /** Chunk name */\n name: string | null;\n /** Kind of code */\n kind: ChunkKind;\n /** Similarity score */\n score: number;\n}\n\n// Cache for loaded indexers to avoid reloading on every query\nconst indexerCache = new Map<string, IncrementalIndexer>();\n\n/**\n * Get or create an indexer for a project path.\n */\nfunction getIndexer(path: string, options?: IndexerOptions): IncrementalIndexer {\n const projectRoot = resolve(path);\n const cacheKey = projectRoot;\n\n let indexer = indexerCache.get(cacheKey);\n if (!indexer) {\n indexer = createIndexer(projectRoot, options);\n indexerCache.set(cacheKey, indexer);\n }\n\n return indexer;\n}\n\n/**\n * Clear the indexer cache for a path.\n */\nexport function clearIndexerCache(path?: string): void {\n if (path) {\n const projectRoot = resolve(path);\n indexerCache.delete(projectRoot);\n } else {\n indexerCache.clear();\n }\n}\n\n/**\n * Index a directory for semantic duplicate detection.\n * Creates or updates the index at .uilint/.duplicates-index/\n */\nexport async function indexDirectory(\n path: string,\n options: IndexOptions = {}\n): Promise<IndexUpdateResult> {\n const projectRoot = resolve(path);\n\n // Clear cache to ensure fresh indexer\n clearIndexerCache(projectRoot);\n\n const indexer = createIndexer(projectRoot, {\n model: options.model,\n baseUrl: options.baseUrl,\n exclude: options.exclude,\n onProgress: options.onProgress,\n });\n\n // Update cache\n indexerCache.set(projectRoot, indexer);\n\n if (options.force) {\n return await indexer.indexAll(true);\n }\n\n // Try incremental update first, fall back to full index\n if (indexer.hasIndex()) {\n return await indexer.update();\n }\n\n return await indexer.indexAll(false);\n}\n\n/**\n * Find semantic duplicate groups in the indexed codebase.\n */\nexport async function findDuplicates(\n options: FindDuplicatesOptions = {}\n): Promise<DuplicateGroup[]> {\n const projectRoot = resolve(options.path || process.cwd());\n const indexer = getIndexer(projectRoot);\n\n // Load the index\n await indexer.load();\n\n if (!indexer.hasIndex()) {\n throw new Error(\n `No index found at ${projectRoot}. Run 'uilint duplicates index' first.`\n );\n }\n\n const vectorStore = indexer.getVectorStore();\n const metadataStore = indexer.getMetadataStore();\n\n const groups = findDuplicateGroups(vectorStore, metadataStore, {\n threshold: options.threshold ?? 0.75,\n minGroupSize: options.minGroupSize,\n kind: options.kind,\n confidenceFilter: options.confidenceLevel,\n useStructuralBoost: options.useStructuralBoost ?? true,\n includeSameFile: options.includeSameFile ?? true,\n });\n\n // Transform to public API format\n return groups.map((group) => ({\n members: group.members.map((m) => ({\n filePath: m.metadata.filePath,\n startLine: m.metadata.startLine,\n endLine: m.metadata.endLine,\n name: m.metadata.name,\n kind: m.metadata.kind,\n score: m.score,\n })),\n avgSimilarity: group.avgSimilarity,\n kind: group.kind,\n confidence: group.confidence,\n }));\n}\n\n/**\n * Search for code semantically similar to a text query.\n */\nexport async function searchSimilar(\n query: string,\n options: SearchOptions = {}\n): Promise<SearchResult[]> {\n const projectRoot = resolve(options.path || process.cwd());\n const indexer = getIndexer(projectRoot);\n\n // Load the index\n await indexer.load();\n\n if (!indexer.hasIndex()) {\n throw new Error(\n `No index found at ${projectRoot}. Run 'uilint duplicates index' first.`\n );\n }\n\n // Create embedding client\n const embeddingClient = new OllamaEmbeddingClient({\n model: options.model,\n baseUrl: options.baseUrl,\n });\n\n // Embed the query\n const queryResult = await embeddingClient.embed(query);\n\n const vectorStore = indexer.getVectorStore();\n const metadataStore = indexer.getMetadataStore();\n\n const results = findSimilarToQuery(vectorStore, queryResult.embedding, {\n top: options.top,\n threshold: options.threshold,\n });\n\n // Transform to public API format\n return results\n .map((r) => {\n const metadata = metadataStore.get(r.id);\n if (!metadata) return null;\n return {\n filePath: metadata.filePath,\n startLine: metadata.startLine,\n endLine: metadata.endLine,\n name: metadata.name,\n kind: metadata.kind,\n score: r.score,\n };\n })\n .filter((r): r is SearchResult => r !== null);\n}\n\n/**\n * Find code similar to a specific location (file:line).\n */\nexport async function findSimilarAtLocation(\n options: SimilarLocationOptions\n): Promise<SearchResult[]> {\n const projectRoot = resolve(options.path || process.cwd());\n const indexer = getIndexer(projectRoot);\n\n // Load the index\n await indexer.load();\n\n if (!indexer.hasIndex()) {\n throw new Error(\n `No index found at ${projectRoot}. Run 'uilint duplicates index' first.`\n );\n }\n\n const vectorStore = indexer.getVectorStore();\n const metadataStore = indexer.getMetadataStore();\n\n const results = findSimilarToLocation(\n vectorStore,\n metadataStore,\n options.filePath,\n options.line,\n {\n top: options.top,\n threshold: options.threshold,\n }\n );\n\n // Transform to public API format\n return results\n .map((r) => {\n const metadata = metadataStore.get(r.id);\n if (!metadata) return null;\n return {\n filePath: metadata.filePath,\n startLine: metadata.startLine,\n endLine: metadata.endLine,\n name: metadata.name,\n kind: metadata.kind,\n score: r.score,\n };\n })\n .filter((r): r is SearchResult => r !== null);\n}\n\n/**\n * Check if an index exists for the given path.\n */\nexport function hasIndex(path: string = process.cwd()): boolean {\n const projectRoot = resolve(path);\n const indexer = getIndexer(projectRoot);\n return indexer.hasIndex();\n}\n\n/**\n * Get index statistics.\n */\nexport async function getIndexStats(path: string = process.cwd()): Promise<{\n totalFiles: number;\n totalChunks: number;\n indexSizeBytes: number;\n embeddingModel: string | null;\n lastUpdated: string | null;\n}> {\n const projectRoot = resolve(path);\n const indexer = getIndexer(projectRoot);\n\n await indexer.load();\n\n const stats = indexer.getStats();\n return {\n totalFiles: stats.totalFiles,\n totalChunks: stats.totalChunks,\n indexSizeBytes: stats.indexSizeBytes,\n embeddingModel: stats.manifest?.embeddingModel || null,\n lastUpdated: stats.manifest?.updatedAt || null,\n };\n}\n","/**\n * Incremental Indexer\n *\n * Combines chunker, embedding client, and storage to build and update\n * the semantic index incrementally.\n */\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"fs\";\nimport { join, relative } from \"path\";\nimport { glob } from \"glob\";\nimport { chunkFile, prepareEmbeddingInput } from \"../embeddings/chunker.js\";\nimport { OllamaEmbeddingClient } from \"../embeddings/ollama-embeddings.js\";\nimport { VectorStore } from \"../index/vector-store.js\";\nimport { MetadataStore } from \"../index/metadata-store.js\";\nimport {\n FileTracker,\n hashContentSync,\n type FileChange,\n} from \"./file-tracker.js\";\nimport type { ChunkingOptions } from \"../embeddings/types.js\";\nimport type { IndexManifest, StoredChunkMetadata } from \"../index/types.js\";\n\nconst INDEX_DIR = \".uilint/.duplicates-index\";\nconst MANIFEST_FILE = \"manifest.json\";\nconst MANIFEST_VERSION = 1;\n\nexport interface IndexerOptions {\n /** Embedding model to use */\n model?: string;\n /** Ollama server URL */\n baseUrl?: string;\n /** Glob patterns to include (default: **\\/*.{ts,tsx,js,jsx}) */\n include?: string[];\n /** Glob patterns to exclude */\n exclude?: string[];\n /** Chunking options */\n chunking?: ChunkingOptions;\n /** Progress callback */\n onProgress?: (message: string, current?: number, total?: number) => void;\n}\n\nexport interface IndexUpdateResult {\n /** Number of files added */\n added: number;\n /** Number of files modified */\n modified: number;\n /** Number of files deleted */\n deleted: number;\n /** Total chunks in index */\n totalChunks: number;\n /** Duration in milliseconds */\n duration: number;\n}\n\nexport class IncrementalIndexer {\n private vectorStore: VectorStore;\n private metadataStore: MetadataStore;\n private fileTracker: FileTracker;\n private embeddingClient: OllamaEmbeddingClient;\n private projectRoot: string;\n private indexDir: string;\n private options: IndexerOptions;\n private manifest: IndexManifest | null = null;\n\n constructor(projectRoot: string, options: IndexerOptions = {}) {\n this.projectRoot = projectRoot;\n this.indexDir = join(projectRoot, INDEX_DIR);\n this.options = options;\n\n this.vectorStore = new VectorStore();\n this.metadataStore = new MetadataStore();\n this.fileTracker = new FileTracker();\n this.embeddingClient = new OllamaEmbeddingClient({\n model: options.model,\n baseUrl: options.baseUrl,\n });\n }\n\n /**\n * Get the include patterns\n */\n private getIncludePatterns(): string[] {\n return this.options.include || [\"**/*.{ts,tsx,js,jsx}\"];\n }\n\n /**\n * Get the exclude patterns\n */\n private getExcludePatterns(): string[] {\n return [\n \"**/node_modules/**\",\n \"**/dist/**\",\n \"**/build/**\",\n \"**/.git/**\",\n \"**/*.test.{ts,tsx,js,jsx}\",\n \"**/*.spec.{ts,tsx,js,jsx}\",\n \"**/__tests__/**\",\n ...(this.options.exclude || []),\n ];\n }\n\n /**\n * Find all files to index\n */\n private async findFiles(): Promise<string[]> {\n const files: string[] = [];\n\n for (const pattern of this.getIncludePatterns()) {\n const matches = await glob(pattern, {\n cwd: this.projectRoot,\n ignore: this.getExcludePatterns(),\n absolute: true,\n nodir: true,\n });\n files.push(...matches);\n }\n\n return [...new Set(files)]; // Dedupe\n }\n\n /**\n * Load existing index from disk\n */\n async load(): Promise<void> {\n if (!existsSync(this.indexDir)) {\n return;\n }\n\n try {\n // Load manifest\n const manifestPath = join(this.indexDir, MANIFEST_FILE);\n if (existsSync(manifestPath)) {\n const content = readFileSync(manifestPath, \"utf-8\");\n this.manifest = JSON.parse(content);\n }\n\n // Load stores\n await this.vectorStore.load(this.indexDir);\n await this.metadataStore.load(this.indexDir);\n await this.fileTracker.load(this.indexDir);\n } catch {\n // If loading fails, start fresh\n this.vectorStore = new VectorStore();\n this.metadataStore = new MetadataStore();\n this.fileTracker = new FileTracker();\n this.manifest = null;\n }\n }\n\n /**\n * Save index to disk\n */\n async save(): Promise<void> {\n if (!existsSync(this.indexDir)) {\n mkdirSync(this.indexDir, { recursive: true });\n }\n\n // Update and save manifest\n const now = new Date().toISOString();\n const dimension = this.vectorStore.getDimension();\n\n this.manifest = {\n version: MANIFEST_VERSION,\n createdAt: this.manifest?.createdAt || now,\n updatedAt: now,\n embeddingModel: this.embeddingClient.getModel(),\n dimension: dimension || 0,\n fileCount: this.fileTracker.getTrackedFiles().length,\n chunkCount: this.metadataStore.size(),\n };\n\n const manifestPath = join(this.indexDir, MANIFEST_FILE);\n writeFileSync(\n manifestPath,\n JSON.stringify(this.manifest, null, 2),\n \"utf-8\"\n );\n\n // Save stores\n await this.vectorStore.save(this.indexDir);\n await this.metadataStore.save(this.indexDir);\n await this.fileTracker.save(this.indexDir);\n }\n\n /**\n * Index all files from scratch\n */\n async indexAll(force: boolean = false): Promise<IndexUpdateResult> {\n const startTime = Date.now();\n const log = this.options.onProgress || (() => {});\n\n // Check if Ollama is available\n const available = await this.embeddingClient.isAvailable();\n if (!available) {\n throw new Error(\n \"Ollama is not available. Make sure it's running at \" +\n (this.options.baseUrl || \"http://localhost:11434\")\n );\n }\n\n // Clear existing index if force\n if (force) {\n this.vectorStore.clear();\n this.metadataStore.clear();\n this.fileTracker.clear();\n } else {\n await this.load();\n }\n\n // Find files\n log(\"Finding files...\");\n const files = await this.findFiles();\n log(`Found ${files.length} files`);\n\n // Detect changes\n const changes = force\n ? files.map((path) => ({ path, type: \"added\" as const, newHash: \"\" }))\n : await this.fileTracker.detectChanges(files);\n\n // Process changes\n const result = await this.processChanges(changes, log);\n\n // Save index\n log(\"Saving index...\");\n await this.save();\n\n return {\n ...result,\n duration: Date.now() - startTime,\n };\n }\n\n /**\n * Update index incrementally\n */\n async update(): Promise<IndexUpdateResult> {\n const startTime = Date.now();\n const log = this.options.onProgress || (() => {});\n\n // Load existing index\n await this.load();\n\n // Check if Ollama is available\n const available = await this.embeddingClient.isAvailable();\n if (!available) {\n throw new Error(\"Ollama is not available\");\n }\n\n // Find files and detect changes\n log(\"Detecting changes...\");\n const files = await this.findFiles();\n const changes = await this.fileTracker.detectChanges(files);\n\n if (changes.length === 0) {\n log(\"No changes detected\");\n return {\n added: 0,\n modified: 0,\n deleted: 0,\n totalChunks: this.metadataStore.size(),\n duration: Date.now() - startTime,\n };\n }\n\n log(`Found ${changes.length} changed files`);\n\n // Process changes\n const result = await this.processChanges(changes, log);\n\n // Save index\n log(\"Saving index...\");\n await this.save();\n\n return {\n ...result,\n duration: Date.now() - startTime,\n };\n }\n\n /**\n * Process file changes\n */\n private async processChanges(\n changes: FileChange[],\n log: (msg: string, current?: number, total?: number) => void\n ): Promise<Omit<IndexUpdateResult, \"duration\">> {\n let added = 0;\n let modified = 0;\n let deleted = 0;\n\n // Handle deletions first\n const deletedFiles = changes.filter((c) => c.type === \"deleted\");\n for (const change of deletedFiles) {\n const removedIds = this.metadataStore.removeByFilePath(change.path);\n for (const id of removedIds) {\n this.vectorStore.remove(id);\n }\n this.fileTracker.removeEntry(change.path);\n deleted++;\n }\n\n // Handle additions and modifications\n const filesToProcess = changes.filter((c) => c.type !== \"deleted\");\n\n for (let i = 0; i < filesToProcess.length; i++) {\n const change = filesToProcess[i];\n log(\n `Processing ${relative(this.projectRoot, change.path)}`,\n i + 1,\n filesToProcess.length\n );\n\n try {\n // Read file content\n const content = readFileSync(change.path, \"utf-8\");\n\n // Remove old chunks if modified\n if (change.type === \"modified\") {\n const removedIds = this.metadataStore.removeByFilePath(change.path);\n for (const id of removedIds) {\n this.vectorStore.remove(id);\n }\n modified++;\n } else {\n added++;\n }\n\n // Chunk the file\n const chunks = chunkFile(change.path, content, this.options.chunking);\n\n if (chunks.length === 0) {\n // No chunks to embed, but still track the file\n await this.fileTracker.updateFile(change.path, content, []);\n continue;\n }\n\n // Prepare embedding inputs\n const embeddingInputs = chunks.map((c) => prepareEmbeddingInput(c));\n\n // Generate embeddings\n const embeddings =\n await this.embeddingClient.embedBatch(embeddingInputs);\n\n // Store chunks and embeddings\n const chunkIds: string[] = [];\n for (let j = 0; j < chunks.length; j++) {\n const chunk = chunks[j];\n const embedding = embeddings[j].embedding;\n\n // Store vector\n this.vectorStore.add(chunk.id, embedding);\n\n // Store metadata with relative path for portability across environments\n const relativeFilePath = relative(this.projectRoot, chunk.filePath);\n const metadata: StoredChunkMetadata = {\n filePath: relativeFilePath,\n startLine: chunk.startLine,\n endLine: chunk.endLine,\n startColumn: chunk.startColumn,\n endColumn: chunk.endColumn,\n kind: chunk.kind,\n name: chunk.name,\n contentHash: hashContentSync(chunk.content),\n metadata: {\n props: chunk.metadata.props,\n hooks: chunk.metadata.hooks,\n jsxElements: chunk.metadata.jsxElements,\n isExported: chunk.metadata.isExported,\n isDefaultExport: chunk.metadata.isDefaultExport,\n },\n };\n this.metadataStore.set(chunk.id, metadata);\n\n chunkIds.push(chunk.id);\n }\n\n // Update file tracker\n await this.fileTracker.updateFile(change.path, content, chunkIds);\n } catch (error) {\n console.warn(`Error processing ${change.path}:`, error);\n }\n }\n\n return {\n added,\n modified,\n deleted,\n totalChunks: this.metadataStore.size(),\n };\n }\n\n /**\n * Get index statistics\n */\n getStats(): {\n totalFiles: number;\n totalChunks: number;\n indexSizeBytes: number;\n manifest: IndexManifest | null;\n } {\n return {\n totalFiles: this.fileTracker.getTrackedFiles().length,\n totalChunks: this.metadataStore.size(),\n indexSizeBytes: this.vectorStore.getStats().memoryBytes,\n manifest: this.manifest,\n };\n }\n\n /**\n * Get the vector store (for queries)\n */\n getVectorStore(): VectorStore {\n return this.vectorStore;\n }\n\n /**\n * Get the metadata store (for queries)\n */\n getMetadataStore(): MetadataStore {\n return this.metadataStore;\n }\n\n /**\n * Check if index exists\n */\n hasIndex(): boolean {\n return existsSync(join(this.indexDir, MANIFEST_FILE));\n }\n}\n\n/**\n * Create an indexer for a project\n */\nexport function createIndexer(\n projectRoot: string,\n options?: IndexerOptions\n): IncrementalIndexer {\n return new IncrementalIndexer(projectRoot, options);\n}\n","/**\n * Vector Store\n *\n * File-based vector storage with cosine similarity search.\n * Uses binary Float32 format for efficient storage.\n */\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"fs\";\nimport { join } from \"path\";\n\nexport interface SimilarityResult {\n /** Chunk ID */\n id: string;\n /** Cosine similarity score (0-1) */\n score: number;\n /** Distance (1 - score) */\n distance: number;\n}\n\nexport interface VectorStoreOptions {\n /** Expected dimension of vectors (validated on add) */\n dimension?: number;\n}\n\n/**\n * Compute cosine similarity between two vectors\n */\nfunction cosineSimilarity(a: number[], b: number[]): number {\n if (a.length !== b.length) {\n throw new Error(`Vector dimension mismatch: ${a.length} vs ${b.length}`);\n }\n\n let dotProduct = 0;\n let normA = 0;\n let normB = 0;\n\n for (let i = 0; i < a.length; i++) {\n dotProduct += a[i] * b[i];\n normA += a[i] * a[i];\n normB += b[i] * b[i];\n }\n\n normA = Math.sqrt(normA);\n normB = Math.sqrt(normB);\n\n if (normA === 0 || normB === 0) {\n return 0;\n }\n\n return dotProduct / (normA * normB);\n}\n\nexport class VectorStore {\n private vectors: Map<string, number[]> = new Map();\n private dimension: number | null = null;\n private idIndex: string[] = []; // Ordered list of IDs for binary storage\n\n constructor(options: VectorStoreOptions = {}) {\n if (options.dimension) {\n this.dimension = options.dimension;\n }\n }\n\n /**\n * Add a vector to the store\n */\n add(id: string, vector: number[]): void {\n // Validate dimension\n if (this.dimension === null) {\n this.dimension = vector.length;\n } else if (vector.length !== this.dimension) {\n throw new Error(\n `Vector dimension mismatch: expected ${this.dimension}, got ${vector.length}`\n );\n }\n\n // Add to store\n if (!this.vectors.has(id)) {\n this.idIndex.push(id);\n }\n this.vectors.set(id, vector);\n }\n\n /**\n * Add multiple vectors at once\n */\n addBatch(items: Array<{ id: string; vector: number[] }>): void {\n for (const { id, vector } of items) {\n this.add(id, vector);\n }\n }\n\n /**\n * Remove a vector from the store\n */\n remove(id: string): boolean {\n if (!this.vectors.has(id)) {\n return false;\n }\n this.vectors.delete(id);\n this.idIndex = this.idIndex.filter((i) => i !== id);\n return true;\n }\n\n /**\n * Get a vector by ID\n */\n get(id: string): number[] | null {\n return this.vectors.get(id) || null;\n }\n\n /**\n * Check if a vector exists\n */\n has(id: string): boolean {\n return this.vectors.has(id);\n }\n\n /**\n * Find the most similar vectors to a query vector\n */\n findSimilar(\n query: number[],\n k: number = 10,\n threshold: number = 0\n ): SimilarityResult[] {\n if (this.dimension !== null && query.length !== this.dimension) {\n throw new Error(\n `Query vector dimension mismatch: expected ${this.dimension}, got ${query.length}`\n );\n }\n\n const results: SimilarityResult[] = [];\n\n for (const [id, vector] of this.vectors) {\n const score = cosineSimilarity(query, vector);\n if (score >= threshold) {\n results.push({\n id,\n score,\n distance: 1 - score,\n });\n }\n }\n\n // Sort by score descending\n results.sort((a, b) => b.score - a.score);\n\n // Return top k\n return results.slice(0, k);\n }\n\n /**\n * Get the number of vectors in the store\n */\n size(): number {\n return this.vectors.size;\n }\n\n /**\n * Get the dimension of vectors\n */\n getDimension(): number | null {\n return this.dimension;\n }\n\n /**\n * Get all IDs\n */\n getIds(): string[] {\n return [...this.idIndex];\n }\n\n /**\n * Clear all vectors\n */\n clear(): void {\n this.vectors.clear();\n this.idIndex = [];\n this.dimension = null;\n }\n\n /**\n * Save the vector store to disk\n *\n * Format:\n * - embeddings.bin: Binary Float32 vectors\n * - ids.json: Ordered array of IDs matching vector positions\n */\n async save(dirPath: string): Promise<void> {\n // Ensure directory exists\n if (!existsSync(dirPath)) {\n mkdirSync(dirPath, { recursive: true });\n }\n\n // Save IDs\n const idsPath = join(dirPath, \"ids.json\");\n writeFileSync(idsPath, JSON.stringify(this.idIndex), \"utf-8\");\n\n // Save vectors as binary\n const embeddingsPath = join(dirPath, \"embeddings.bin\");\n\n if (this.vectors.size === 0) {\n // Write empty file with header only\n const header = new Uint32Array([0, 0]); // dimension=0, count=0\n writeFileSync(embeddingsPath, Buffer.from(header.buffer));\n return;\n }\n\n const dimension = this.dimension!;\n const count = this.vectors.size;\n\n // Create buffer: 8 bytes header (2 uint32) + vectors\n const headerSize = 8;\n const vectorsSize = count * dimension * 4; // Float32 = 4 bytes\n const buffer = Buffer.alloc(headerSize + vectorsSize);\n\n // Write header\n buffer.writeUInt32LE(dimension, 0);\n buffer.writeUInt32LE(count, 4);\n\n // Write vectors in ID order\n let offset = headerSize;\n for (const id of this.idIndex) {\n const vector = this.vectors.get(id)!;\n for (const value of vector) {\n buffer.writeFloatLE(value, offset);\n offset += 4;\n }\n }\n\n writeFileSync(embeddingsPath, buffer);\n }\n\n /**\n * Load the vector store from disk\n */\n async load(dirPath: string): Promise<void> {\n const idsPath = join(dirPath, \"ids.json\");\n const embeddingsPath = join(dirPath, \"embeddings.bin\");\n\n if (!existsSync(idsPath) || !existsSync(embeddingsPath)) {\n throw new Error(`Vector store files not found in ${dirPath}`);\n }\n\n // Clear current state\n this.clear();\n\n // Load IDs\n const idsContent = readFileSync(idsPath, \"utf-8\");\n this.idIndex = JSON.parse(idsContent);\n\n // Load vectors\n const buffer = readFileSync(embeddingsPath);\n\n // Read header\n const dimension = buffer.readUInt32LE(0);\n const count = buffer.readUInt32LE(4);\n\n if (count === 0) {\n // Empty store\n return;\n }\n\n this.dimension = dimension;\n\n // Read vectors\n let offset = 8;\n for (let i = 0; i < count; i++) {\n const vector: number[] = [];\n for (let j = 0; j < dimension; j++) {\n vector.push(buffer.readFloatLE(offset));\n offset += 4;\n }\n this.vectors.set(this.idIndex[i], vector);\n }\n }\n\n /**\n * Iterate over all vectors\n */\n *entries(): IterableIterator<[string, number[]]> {\n for (const id of this.idIndex) {\n yield [id, this.vectors.get(id)!];\n }\n }\n\n /**\n * Get stats about the store\n */\n getStats(): { size: number; dimension: number | null; memoryBytes: number } {\n const memoryBytes = this.dimension\n ? this.vectors.size * this.dimension * 4 + this.idIndex.length * 50 // Rough estimate\n : 0;\n\n return {\n size: this.vectors.size,\n dimension: this.dimension,\n memoryBytes,\n };\n }\n}\n","/**\n * Metadata Store\n *\n * JSON-based storage for chunk metadata (file paths, line numbers, etc.)\n */\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"fs\";\nimport { join } from \"path\";\nimport type { StoredChunkMetadata } from \"./types.js\";\n\nexport class MetadataStore {\n private chunks: Map<string, StoredChunkMetadata> = new Map();\n\n /**\n * Add or update chunk metadata\n */\n set(id: string, metadata: StoredChunkMetadata): void {\n this.chunks.set(id, metadata);\n }\n\n /**\n * Add multiple chunks at once\n */\n setBatch(items: Array<{ id: string; metadata: StoredChunkMetadata }>): void {\n for (const { id, metadata } of items) {\n this.set(id, metadata);\n }\n }\n\n /**\n * Get chunk metadata by ID\n */\n get(id: string): StoredChunkMetadata | null {\n return this.chunks.get(id) || null;\n }\n\n /**\n * Check if a chunk exists\n */\n has(id: string): boolean {\n return this.chunks.has(id);\n }\n\n /**\n * Remove chunk metadata\n */\n remove(id: string): boolean {\n return this.chunks.delete(id);\n }\n\n /**\n * Remove all chunks for a given file path\n */\n removeByFilePath(filePath: string): string[] {\n const removedIds: string[] = [];\n for (const [id, metadata] of this.chunks) {\n if (metadata.filePath === filePath) {\n this.chunks.delete(id);\n removedIds.push(id);\n }\n }\n return removedIds;\n }\n\n /**\n * Get all chunks for a given file path\n */\n getByFilePath(\n filePath: string\n ): Array<{ id: string; metadata: StoredChunkMetadata }> {\n const results: Array<{ id: string; metadata: StoredChunkMetadata }> = [];\n for (const [id, metadata] of this.chunks) {\n if (metadata.filePath === filePath) {\n results.push({ id, metadata });\n }\n }\n return results;\n }\n\n /**\n * Get chunk by content hash\n */\n getByContentHash(\n contentHash: string\n ): { id: string; metadata: StoredChunkMetadata } | null {\n for (const [id, metadata] of this.chunks) {\n if (metadata.contentHash === contentHash) {\n return { id, metadata };\n }\n }\n return null;\n }\n\n /**\n * Get chunk at a specific location\n */\n getAtLocation(\n filePath: string,\n line: number\n ): { id: string; metadata: StoredChunkMetadata } | null {\n for (const [id, metadata] of this.chunks) {\n if (\n metadata.filePath === filePath &&\n metadata.startLine <= line &&\n metadata.endLine >= line\n ) {\n return { id, metadata };\n }\n }\n return null;\n }\n\n /**\n * Get all unique file paths\n */\n getFilePaths(): string[] {\n const paths = new Set<string>();\n for (const metadata of this.chunks.values()) {\n paths.add(metadata.filePath);\n }\n return [...paths];\n }\n\n /**\n * Get number of chunks\n */\n size(): number {\n return this.chunks.size;\n }\n\n /**\n * Clear all metadata\n */\n clear(): void {\n this.chunks.clear();\n }\n\n /**\n * Iterate over all chunks\n */\n *entries(): IterableIterator<[string, StoredChunkMetadata]> {\n yield* this.chunks.entries();\n }\n\n /**\n * Get all IDs\n */\n getIds(): string[] {\n return [...this.chunks.keys()];\n }\n\n /**\n * Save to disk\n */\n async save(dirPath: string): Promise<void> {\n if (!existsSync(dirPath)) {\n mkdirSync(dirPath, { recursive: true });\n }\n\n const metadataPath = join(dirPath, \"metadata.json\");\n const data = Object.fromEntries(this.chunks);\n writeFileSync(metadataPath, JSON.stringify(data, null, 2), \"utf-8\");\n }\n\n /**\n * Load from disk\n */\n async load(dirPath: string): Promise<void> {\n const metadataPath = join(dirPath, \"metadata.json\");\n\n if (!existsSync(metadataPath)) {\n throw new Error(`Metadata file not found: ${metadataPath}`);\n }\n\n this.clear();\n const content = readFileSync(metadataPath, \"utf-8\");\n const data = JSON.parse(content) as Record<string, StoredChunkMetadata>;\n\n for (const [id, metadata] of Object.entries(data)) {\n this.chunks.set(id, metadata);\n }\n }\n\n /**\n * Filter chunks by kind\n */\n filterByKind(\n kind: string\n ): Array<{ id: string; metadata: StoredChunkMetadata }> {\n const results: Array<{ id: string; metadata: StoredChunkMetadata }> = [];\n for (const [id, metadata] of this.chunks) {\n if (metadata.kind === kind) {\n results.push({ id, metadata });\n }\n }\n return results;\n }\n\n /**\n * Search by name (case-insensitive partial match)\n */\n searchByName(\n query: string\n ): Array<{ id: string; metadata: StoredChunkMetadata }> {\n const lowerQuery = query.toLowerCase();\n const results: Array<{ id: string; metadata: StoredChunkMetadata }> = [];\n for (const [id, metadata] of this.chunks) {\n if (metadata.name && metadata.name.toLowerCase().includes(lowerQuery)) {\n results.push({ id, metadata });\n }\n }\n return results;\n }\n}\n","/**\n * File Tracker\n *\n * Tracks file content hashes for incremental updates.\n * Uses xxhash for fast hashing (following uilint-eslint patterns).\n */\n\nimport {\n existsSync,\n mkdirSync,\n readFileSync,\n writeFileSync,\n statSync,\n} from \"fs\";\nimport { join } from \"path\";\n\n// Lazy-loaded xxhash\nlet xxhashInstance: Awaited<\n ReturnType<typeof import(\"xxhash-wasm\")[\"default\"]>\n> | null = null;\n\nasync function getXxhash() {\n if (!xxhashInstance) {\n const xxhash = await import(\"xxhash-wasm\");\n xxhashInstance = await xxhash.default();\n }\n return xxhashInstance;\n}\n\n/**\n * Synchronous hash using djb2 algorithm (fallback)\n */\nfunction djb2Hash(str: string): string {\n let hash = 5381;\n for (let i = 0; i < str.length; i++) {\n hash = (hash * 33) ^ str.charCodeAt(i);\n }\n return (hash >>> 0).toString(16);\n}\n\n/**\n * Hash content using xxhash (async) or djb2 (sync fallback)\n */\nexport async function hashContent(content: string): Promise<string> {\n try {\n const xxhash = await getXxhash();\n return xxhash.h64ToString(content);\n } catch {\n return djb2Hash(content);\n }\n}\n\n/**\n * Synchronous hash for when async is not possible\n */\nexport function hashContentSync(content: string): string {\n return djb2Hash(content);\n}\n\nexport interface FileHashEntry {\n /** xxhash of file content */\n contentHash: string;\n /** Last modification time in ms */\n mtimeMs: number;\n /** IDs of chunks from this file */\n chunkIds: string[];\n}\n\nexport interface HashStore {\n version: number;\n files: Record<string, FileHashEntry>;\n}\n\nexport interface FileChange {\n path: string;\n type: \"added\" | \"modified\" | \"deleted\";\n oldHash?: string;\n newHash?: string;\n}\n\nconst HASH_STORE_VERSION = 1;\n\nexport class FileTracker {\n private store: HashStore = {\n version: HASH_STORE_VERSION,\n files: {},\n };\n\n /**\n * Get the hash entry for a file\n */\n getEntry(filePath: string): FileHashEntry | null {\n return this.store.files[filePath] || null;\n }\n\n /**\n * Set the hash entry for a file\n */\n setEntry(filePath: string, entry: FileHashEntry): void {\n this.store.files[filePath] = entry;\n }\n\n /**\n * Remove the hash entry for a file\n */\n removeEntry(filePath: string): boolean {\n if (this.store.files[filePath]) {\n delete this.store.files[filePath];\n return true;\n }\n return false;\n }\n\n /**\n * Get all tracked file paths\n */\n getTrackedFiles(): string[] {\n return Object.keys(this.store.files);\n }\n\n /**\n * Clear all entries\n */\n clear(): void {\n this.store = {\n version: HASH_STORE_VERSION,\n files: {},\n };\n }\n\n /**\n * Detect changes between current files and stored hashes\n */\n async detectChanges(files: string[]): Promise<FileChange[]> {\n const changes: FileChange[] = [];\n const currentFiles = new Set(files);\n\n // Check for deleted files\n for (const storedPath of Object.keys(this.store.files)) {\n if (!currentFiles.has(storedPath)) {\n changes.push({\n path: storedPath,\n type: \"deleted\",\n oldHash: this.store.files[storedPath].contentHash,\n });\n }\n }\n\n // Check for added or modified files\n for (const filePath of files) {\n try {\n const content = readFileSync(filePath, \"utf-8\");\n const newHash = await hashContent(content);\n const entry = this.store.files[filePath];\n\n if (!entry) {\n // New file\n changes.push({\n path: filePath,\n type: \"added\",\n newHash,\n });\n } else if (entry.contentHash !== newHash) {\n // Modified file\n changes.push({\n path: filePath,\n type: \"modified\",\n oldHash: entry.contentHash,\n newHash,\n });\n }\n // If hash matches and mtime is similar, no change\n } catch {\n // File might be deleted or unreadable\n if (this.store.files[filePath]) {\n changes.push({\n path: filePath,\n type: \"deleted\",\n oldHash: this.store.files[filePath].contentHash,\n });\n }\n }\n }\n\n return changes;\n }\n\n /**\n * Update stored hash for a file\n */\n async updateFile(\n filePath: string,\n content: string,\n chunkIds: string[]\n ): Promise<void> {\n const hash = await hashContent(content);\n const stat = statSync(filePath);\n\n this.store.files[filePath] = {\n contentHash: hash,\n mtimeMs: stat.mtimeMs,\n chunkIds,\n };\n }\n\n /**\n * Save to disk\n */\n async save(dirPath: string): Promise<void> {\n if (!existsSync(dirPath)) {\n mkdirSync(dirPath, { recursive: true });\n }\n\n const hashesPath = join(dirPath, \"hashes.json\");\n writeFileSync(hashesPath, JSON.stringify(this.store, null, 2), \"utf-8\");\n }\n\n /**\n * Load from disk\n */\n async load(dirPath: string): Promise<void> {\n const hashesPath = join(dirPath, \"hashes.json\");\n\n if (!existsSync(hashesPath)) {\n // No existing hash store - start fresh\n this.clear();\n return;\n }\n\n const content = readFileSync(hashesPath, \"utf-8\");\n const data = JSON.parse(content) as HashStore;\n\n // Version check\n if (data.version !== HASH_STORE_VERSION) {\n // Incompatible version - start fresh\n this.clear();\n return;\n }\n\n this.store = data;\n }\n\n /**\n * Get stats\n */\n getStats(): { trackedFiles: number } {\n return {\n trackedFiles: Object.keys(this.store.files).length,\n };\n }\n}\n","/**\n * Duplicate Scorer\n *\n * Provides scoring functions for ranking duplicate code groups.\n */\n\nimport type { StoredChunkMetadata } from \"../index/types.js\";\n\nexport interface DuplicateScore {\n /** Embedding cosine similarity (0-1) */\n similarity: number;\n /** Ratio of code size similarity (0-1) */\n sizeRatio: number;\n /** Weighted combined score */\n combinedScore: number;\n}\n\n/**\n * Calculate the size ratio between two code chunks.\n * Returns a value between 0 and 1 where 1 means identical size.\n */\nexport function calculateSizeRatio(\n chunk1: StoredChunkMetadata,\n chunk2: StoredChunkMetadata\n): number {\n const lines1 = chunk1.endLine - chunk1.startLine + 1;\n const lines2 = chunk2.endLine - chunk2.startLine + 1;\n\n const minLines = Math.min(lines1, lines2);\n const maxLines = Math.max(lines1, lines2);\n\n return maxLines > 0 ? minLines / maxLines : 1;\n}\n\n/**\n * Calculate a combined duplicate score.\n */\nexport function calculateDuplicateScore(\n similarity: number,\n chunk1: StoredChunkMetadata,\n chunk2: StoredChunkMetadata\n): DuplicateScore {\n const sizeRatio = calculateSizeRatio(chunk1, chunk2);\n\n // Weighted score: 85% similarity, 15% size ratio\n const combinedScore = similarity * 0.85 + sizeRatio * 0.15;\n\n return {\n similarity,\n sizeRatio,\n combinedScore,\n };\n}\n\n/**\n * Calculate the average similarity of a duplicate group.\n */\nexport function calculateGroupAverageSimilarity(\n similarities: number[]\n): number {\n if (similarities.length === 0) return 0;\n return similarities.reduce((sum, s) => sum + s, 0) / similarities.length;\n}\n\n/**\n * Sort duplicate groups by relevance.\n * Groups are sorted by: member count (desc), then average similarity (desc).\n */\nexport function sortDuplicateGroups<T extends { avgSimilarity: number; members: unknown[] }>(\n groups: T[]\n): T[] {\n return [...groups].sort((a, b) => {\n // First by member count (more members = more important)\n const countDiff = b.members.length - a.members.length;\n if (countDiff !== 0) return countDiff;\n\n // Then by average similarity\n return b.avgSimilarity - a.avgSimilarity;\n });\n}\n","/**\n * Structural Similarity Scorer\n *\n * Calculates similarity based on code structure (props, hooks, JSX elements)\n * independent of semantic embeddings. This complements embedding-based\n * similarity by catching cases where code structure is similar but\n * variable/prop names differ.\n */\n\nimport type { StoredChunkMetadata } from \"../index/types.js\";\n\nexport interface StructuralScore {\n /** Jaccard similarity of prop names (0-1) */\n propsOverlap: number;\n /** Jaccard similarity of JSX elements (0-1) */\n jsxOverlap: number;\n /** Jaccard similarity of hooks used (0-1) */\n hooksOverlap: number;\n /** Line count ratio (0-1, 1 = same size) */\n sizeRatio: number;\n /** Combined weighted score (0-1) */\n combined: number;\n}\n\nexport interface StructuralScorerWeights {\n /** Weight for props overlap (default: 0.25) */\n props: number;\n /** Weight for JSX elements overlap (default: 0.35) */\n jsx: number;\n /** Weight for hooks overlap (default: 0.25) */\n hooks: number;\n /** Weight for size similarity (default: 0.15) */\n size: number;\n}\n\nexport const DEFAULT_STRUCTURAL_WEIGHTS: StructuralScorerWeights = {\n props: 0.25,\n jsx: 0.35,\n hooks: 0.25,\n size: 0.15,\n};\n\n/**\n * Calculate Jaccard similarity between two sets of strings.\n * Returns 1 if both sets are empty (vacuously similar).\n */\nexport function jaccard(a: string[], b: string[]): number {\n if (a.length === 0 && b.length === 0) return 1;\n if (a.length === 0 || b.length === 0) return 0;\n\n // Normalize to lowercase for comparison\n const setA = new Set(a.map((s) => s.toLowerCase()));\n const setB = new Set(b.map((s) => s.toLowerCase()));\n\n const intersection = new Set([...setA].filter((x) => setB.has(x)));\n const union = new Set([...setA, ...setB]);\n\n return intersection.size / union.size;\n}\n\n/**\n * Calculate size ratio between two code chunks.\n * Returns a value between 0 and 1, where 1 means identical size.\n */\nexport function calculateSizeRatio(linesA: number, linesB: number): number {\n if (linesA === 0 && linesB === 0) return 1;\n if (linesA === 0 || linesB === 0) return 0;\n\n const min = Math.min(linesA, linesB);\n const max = Math.max(linesA, linesB);\n\n return min / max;\n}\n\n/**\n * Extract structural features from chunk metadata.\n * Handles cases where metadata fields may be missing.\n * Note: StoredChunkMetadata has a nested `metadata` field containing props, hooks, etc.\n */\nfunction extractFeatures(storedMeta: StoredChunkMetadata): {\n props: string[];\n jsxElements: string[];\n hooks: string[];\n lines: number;\n} {\n const meta = storedMeta.metadata ?? {};\n return {\n props: meta.props ?? [],\n jsxElements: meta.jsxElements ?? [],\n hooks: meta.hooks ?? [],\n lines: (storedMeta.endLine ?? 0) - (storedMeta.startLine ?? 0) + 1,\n };\n}\n\n/**\n * Calculate structural similarity between two chunks.\n *\n * This function compares the structural features of two code chunks:\n * - Props/parameters they accept\n * - JSX elements they render\n * - Hooks they use\n * - Relative size\n *\n * @param a First chunk metadata\n * @param b Second chunk metadata\n * @param weights Optional custom weights for each feature\n * @returns Structural similarity score with component breakdowns\n */\nexport function calculateStructuralSimilarity(\n a: StoredChunkMetadata,\n b: StoredChunkMetadata,\n weights: StructuralScorerWeights = DEFAULT_STRUCTURAL_WEIGHTS\n): StructuralScore {\n const featuresA = extractFeatures(a);\n const featuresB = extractFeatures(b);\n\n const propsOverlap = jaccard(featuresA.props, featuresB.props);\n const jsxOverlap = jaccard(featuresA.jsxElements, featuresB.jsxElements);\n const hooksOverlap = jaccard(featuresA.hooks, featuresB.hooks);\n const sizeRatio = calculateSizeRatio(featuresA.lines, featuresB.lines);\n\n // Calculate weighted combined score\n const combined =\n propsOverlap * weights.props +\n jsxOverlap * weights.jsx +\n hooksOverlap * weights.hooks +\n sizeRatio * weights.size;\n\n return {\n propsOverlap,\n jsxOverlap,\n hooksOverlap,\n sizeRatio,\n combined,\n };\n}\n\n/**\n * Quick check if two chunks have high structural similarity.\n * Useful for fast pre-filtering before expensive embedding comparison.\n *\n * @param a First chunk metadata\n * @param b Second chunk metadata\n * @param threshold Minimum combined score to consider similar (default: 0.5)\n */\nexport function hasHighStructuralSimilarity(\n a: StoredChunkMetadata,\n b: StoredChunkMetadata,\n threshold: number = 0.5\n): boolean {\n const score = calculateStructuralSimilarity(a, b);\n return score.combined >= threshold;\n}\n\n/**\n * Find structurally similar chunks from a list.\n * Returns chunks sorted by structural similarity (highest first).\n *\n * @param target The chunk to compare against\n * @param candidates List of candidate chunks to compare\n * @param threshold Minimum similarity threshold\n * @param limit Maximum number of results to return\n */\nexport function findStructurallySimilar(\n target: StoredChunkMetadata,\n candidates: StoredChunkMetadata[],\n threshold: number = 0.5,\n limit: number = 10\n): Array<{ metadata: StoredChunkMetadata; score: StructuralScore }> {\n const results: Array<{ metadata: StoredChunkMetadata; score: StructuralScore }> = [];\n\n for (const candidate of candidates) {\n // Skip self-comparison\n if (candidate.filePath === target.filePath && candidate.startLine === target.startLine) {\n continue;\n }\n\n const score = calculateStructuralSimilarity(target, candidate);\n if (score.combined >= threshold) {\n results.push({ metadata: candidate, score });\n }\n }\n\n // Sort by combined score descending\n results.sort((a, b) => b.score.combined - a.score.combined);\n\n return results.slice(0, limit);\n}\n","/**\n * Confidence Level System\n *\n * Provides confidence levels for duplicate detection results\n * to help users prioritize which duplicates to address.\n *\n * Confidence levels:\n * - HIGH: Likely copy-paste or near-identical implementation. Should consolidate.\n * - MEDIUM: Semantically similar code. Worth reviewing for potential abstraction.\n * - LOW: Possibly related patterns. Optional to review.\n */\n\nexport type ConfidenceLevel = \"high\" | \"medium\" | \"low\";\n\nexport interface ConfidenceConfig {\n /** Threshold for high confidence (default: 0.90) */\n highThreshold: number;\n /** Threshold for medium confidence (default: 0.75) */\n mediumThreshold: number;\n /** Threshold for low confidence / minimum reporting (default: 0.60) */\n lowThreshold: number;\n}\n\nexport const DEFAULT_CONFIDENCE_CONFIG: ConfidenceConfig = {\n highThreshold: 0.9,\n mediumThreshold: 0.75,\n lowThreshold: 0.6,\n};\n\nexport interface ConfidenceResult {\n /** The confidence level */\n level: ConfidenceLevel;\n /** The raw similarity score (0-1) */\n score: number;\n /** Human-readable description of what this confidence level means */\n description: string;\n /** Recommended action for the user */\n action: string;\n /** Color for CLI/UI display */\n color: \"red\" | \"yellow\" | \"green\";\n}\n\n/**\n * Determine confidence level from a similarity score.\n *\n * @param score Similarity score between 0 and 1\n * @param config Optional custom threshold configuration\n * @returns The confidence level\n */\nexport function getConfidenceLevel(\n score: number,\n config: ConfidenceConfig = DEFAULT_CONFIDENCE_CONFIG\n): ConfidenceLevel {\n if (score >= config.highThreshold) return \"high\";\n if (score >= config.mediumThreshold) return \"medium\";\n return \"low\";\n}\n\n/**\n * Check if a score meets the minimum threshold for reporting.\n *\n * @param score Similarity score\n * @param config Optional custom threshold configuration\n * @returns True if the score should be reported\n */\nexport function meetsMinimumThreshold(\n score: number,\n config: ConfidenceConfig = DEFAULT_CONFIDENCE_CONFIG\n): boolean {\n return score >= config.lowThreshold;\n}\n\n/**\n * Get detailed confidence result with actionable guidance.\n *\n * @param score Similarity score between 0 and 1\n * @param config Optional custom threshold configuration\n * @returns Full confidence result with guidance\n */\nexport function getConfidenceResult(\n score: number,\n config: ConfidenceConfig = DEFAULT_CONFIDENCE_CONFIG\n): ConfidenceResult {\n const level = getConfidenceLevel(score, config);\n\n switch (level) {\n case \"high\":\n return {\n level,\n score,\n description:\n \"High confidence duplicate - likely copy-paste or near-identical implementation\",\n action: \"Strongly recommend consolidating into a single reusable component/function\",\n color: \"red\",\n };\n case \"medium\":\n return {\n level,\n score,\n description:\n \"Medium confidence - semantically similar code with different implementation details\",\n action: \"Review for potential consolidation or shared abstraction\",\n color: \"yellow\",\n };\n case \"low\":\n return {\n level,\n score,\n description: \"Low confidence - possibly related patterns or partial structural overlap\",\n action: \"Optional review - differences may be intentional\",\n color: \"green\",\n };\n }\n}\n\n/**\n * Get emoji indicator for confidence level (for CLI output).\n */\nexport function getConfidenceEmoji(level: ConfidenceLevel): string {\n switch (level) {\n case \"high\":\n return \"🔴\";\n case \"medium\":\n return \"🟡\";\n case \"low\":\n return \"🟢\";\n }\n}\n\n/**\n * Get ANSI color code for confidence level (for CLI output).\n */\nexport function getConfidenceAnsiColor(level: ConfidenceLevel): string {\n switch (level) {\n case \"high\":\n return \"\\x1b[31m\"; // Red\n case \"medium\":\n return \"\\x1b[33m\"; // Yellow\n case \"low\":\n return \"\\x1b[32m\"; // Green\n }\n}\n\n/**\n * Format confidence for display in CLI.\n *\n * @param result Confidence result to format\n * @param useEmoji Whether to include emoji (default: true)\n * @param useColor Whether to include ANSI colors (default: false)\n * @returns Formatted string\n */\nexport function formatConfidence(\n result: ConfidenceResult,\n useEmoji: boolean = true,\n useColor: boolean = false\n): string {\n const percent = Math.round(result.score * 100);\n const emoji = useEmoji ? getConfidenceEmoji(result.level) + \" \" : \"\";\n const colorStart = useColor ? getConfidenceAnsiColor(result.level) : \"\";\n const colorEnd = useColor ? \"\\x1b[0m\" : \"\";\n\n return `${emoji}${colorStart}${percent}% similarity (${result.level} confidence)${colorEnd}`;\n}\n\n/**\n * Format confidence with full details for verbose output.\n */\nexport function formatConfidenceVerbose(result: ConfidenceResult): string {\n const lines = [\n formatConfidence(result),\n ` ${result.description}`,\n ` → ${result.action}`,\n ];\n return lines.join(\"\\n\");\n}\n\n/**\n * Compare two confidence levels.\n * Returns: -1 if a < b, 0 if equal, 1 if a > b\n */\nexport function compareConfidenceLevels(a: ConfidenceLevel, b: ConfidenceLevel): number {\n const order: Record<ConfidenceLevel, number> = { high: 3, medium: 2, low: 1 };\n return order[a] - order[b];\n}\n\n/**\n * Filter results by minimum confidence level.\n */\nexport function filterByConfidence<T extends { score: number }>(\n results: T[],\n minLevel: ConfidenceLevel,\n config: ConfidenceConfig = DEFAULT_CONFIDENCE_CONFIG\n): T[] {\n const minThreshold =\n minLevel === \"high\"\n ? config.highThreshold\n : minLevel === \"medium\"\n ? config.mediumThreshold\n : config.lowThreshold;\n\n return results.filter((r) => r.score >= minThreshold);\n}\n","/**\n * Duplicate Finder\n *\n * Finds groups of semantically similar code chunks using the vector index.\n * Enhanced with structural similarity scoring and confidence levels.\n */\n\nimport type { VectorStore, SimilarityResult } from \"../index/vector-store.js\";\nimport type { MetadataStore } from \"../index/metadata-store.js\";\nimport type { StoredChunkMetadata } from \"../index/types.js\";\nimport type { ChunkKind } from \"../embeddings/types.js\";\nimport {\n calculateGroupAverageSimilarity,\n sortDuplicateGroups,\n} from \"./scorer.js\";\nimport { calculateStructuralSimilarity } from \"./structural-scorer.js\";\nimport {\n getConfidenceLevel,\n type ConfidenceLevel,\n} from \"./confidence.js\";\n\nexport interface DuplicateMember {\n /** Chunk ID */\n id: string;\n /** Chunk metadata */\n metadata: StoredChunkMetadata;\n /** Similarity score to the group centroid/first member (semantic only) */\n score: number;\n /** Combined score (semantic + structural) */\n combinedScore?: number;\n /** Structural similarity score */\n structuralScore?: number;\n /** Confidence level for this match */\n confidence?: ConfidenceLevel;\n}\n\nexport interface DuplicateGroup {\n /** Members of the duplicate group */\n members: DuplicateMember[];\n /** Average similarity between all group members */\n avgSimilarity: number;\n /** The kind of code in this group (component, hook, function) */\n kind: ChunkKind;\n /** Overall confidence level for the group */\n confidence: ConfidenceLevel;\n}\n\nexport interface FindDuplicatesOptions {\n /** Minimum cosine similarity threshold (0-1). Default: 0.75 (lowered from 0.85) */\n threshold?: number;\n /** Minimum group size. Default: 2 */\n minGroupSize?: number;\n /** Filter by chunk kind */\n kind?: ChunkKind;\n /** Exclude specific file paths */\n excludePaths?: string[];\n /** Include duplicates within the same file. Default: true */\n includeSameFile?: boolean;\n /** Use structural similarity to boost scores. Default: true */\n useStructuralBoost?: boolean;\n /** Filter results by minimum confidence level */\n confidenceFilter?: ConfidenceLevel;\n}\n\n/**\n * Calculate combined score from semantic and structural similarity.\n * Weights: 60% semantic, 40% structural.\n */\nfunction calculateCombinedSimilarity(\n semanticScore: number,\n metadataA: StoredChunkMetadata,\n metadataB: StoredChunkMetadata\n): { combined: number; structural: number } {\n const structuralResult = calculateStructuralSimilarity(metadataA, metadataB);\n const structural = structuralResult.combined;\n\n // Weighted combination: 60% semantic, 40% structural\n const combined = semanticScore * 0.6 + structural * 0.4;\n\n return { combined, structural };\n}\n\n/**\n * Get minimum threshold for confidence level filter.\n */\nfunction getConfidenceThreshold(level: ConfidenceLevel): number {\n switch (level) {\n case \"high\":\n return 0.9;\n case \"medium\":\n return 0.75;\n case \"low\":\n return 0.6;\n }\n}\n\n/**\n * Find groups of semantically similar code.\n *\n * Algorithm:\n * 1. Iterate through all chunks\n * 2. For each unprocessed chunk, find similar chunks above threshold\n * 3. Calculate combined score (semantic + structural)\n * 4. Group similar chunks together\n * 5. Assign confidence levels\n * 6. Sort groups by size and similarity\n */\nexport function findDuplicateGroups(\n vectorStore: VectorStore,\n metadataStore: MetadataStore,\n options: FindDuplicatesOptions = {}\n): DuplicateGroup[] {\n const {\n threshold = 0.75, // Lowered from 0.85\n minGroupSize = 2,\n kind,\n excludePaths = [],\n includeSameFile = true,\n useStructuralBoost = true,\n confidenceFilter,\n } = options;\n\n const groups: DuplicateGroup[] = [];\n const processed = new Set<string>();\n\n // Get all entries and filter by kind if specified\n let entries = [...metadataStore.entries()];\n\n if (kind) {\n entries = entries.filter(([, meta]) => meta.kind === kind);\n }\n\n // Exclude specified paths\n if (excludePaths.length > 0) {\n entries = entries.filter(\n ([, meta]) => !excludePaths.some((p) => meta.filePath.includes(p))\n );\n }\n\n for (const [id, metadata] of entries) {\n if (processed.has(id)) continue;\n\n const vector = vectorStore.get(id);\n if (!vector) continue;\n\n // Find similar chunks - use lower threshold for initial search\n // to catch candidates that might be boosted by structural similarity\n const searchThreshold = useStructuralBoost ? threshold * 0.8 : threshold;\n const similar = vectorStore.findSimilar(vector, 50, searchThreshold);\n\n // Filter out self, already-processed, and potentially filter by kind\n let candidates = similar.filter((s) => {\n if (s.id === id) return false;\n if (processed.has(s.id)) return false;\n\n const candidateMeta = metadataStore.get(s.id);\n if (!candidateMeta) return false;\n\n // If kind filter is set, only include same kind\n if (kind && candidateMeta.kind !== kind) return false;\n\n // Exclude paths\n if (excludePaths.some((p) => candidateMeta.filePath.includes(p)))\n return false;\n\n // Optionally exclude same-file matches\n if (!includeSameFile && candidateMeta.filePath === metadata.filePath)\n return false;\n\n return true;\n });\n\n // Calculate combined scores if structural boost is enabled\n if (useStructuralBoost) {\n candidates = candidates\n .map((c) => {\n const candidateMeta = metadataStore.get(c.id);\n if (!candidateMeta) return { ...c, combinedScore: c.score };\n\n const { combined, structural } = calculateCombinedSimilarity(\n c.score,\n metadata,\n candidateMeta\n );\n return { ...c, combinedScore: combined, structuralScore: structural };\n })\n .filter((c) => (c.combinedScore ?? c.score) >= threshold)\n .sort((a, b) => (b.combinedScore ?? b.score) - (a.combinedScore ?? a.score));\n }\n\n // If not filtering by kind, prefer same-kind groupings\n if (!kind && candidates.length > 0) {\n const sameKindCandidates = candidates.filter((c) => {\n const meta = metadataStore.get(c.id);\n return meta?.kind === metadata.kind;\n });\n if (sameKindCandidates.length > 0) {\n candidates = sameKindCandidates;\n }\n }\n\n // Check if we have enough candidates for a group\n if (candidates.length >= minGroupSize - 1) {\n const members: DuplicateMember[] = [\n {\n id,\n metadata,\n score: 1.0,\n combinedScore: 1.0,\n confidence: \"high\",\n },\n ];\n\n const similarities: number[] = [];\n\n for (const candidate of candidates) {\n const candidateMeta = metadataStore.get(candidate.id);\n if (candidateMeta) {\n const combinedScore =\n (candidate as { combinedScore?: number }).combinedScore ?? candidate.score;\n const structuralScore =\n (candidate as { structuralScore?: number }).structuralScore;\n const confidence = getConfidenceLevel(combinedScore);\n\n members.push({\n id: candidate.id,\n metadata: candidateMeta,\n score: candidate.score,\n combinedScore,\n structuralScore,\n confidence,\n });\n similarities.push(combinedScore);\n processed.add(candidate.id);\n }\n }\n\n // Mark the original chunk as processed\n processed.add(id);\n\n const avgSimilarity = calculateGroupAverageSimilarity(similarities);\n const groupConfidence = getConfidenceLevel(avgSimilarity);\n\n groups.push({\n members,\n avgSimilarity,\n kind: metadata.kind,\n confidence: groupConfidence,\n });\n }\n }\n\n // Filter by confidence level if specified\n let result = groups;\n if (confidenceFilter) {\n const minThreshold = getConfidenceThreshold(confidenceFilter);\n result = groups.filter((g) => g.avgSimilarity >= minThreshold);\n }\n\n // Sort groups by relevance\n return sortDuplicateGroups(result);\n}\n\n/**\n * Find similar code to a given location (file:line).\n */\nexport function findSimilarToLocation(\n vectorStore: VectorStore,\n metadataStore: MetadataStore,\n filePath: string,\n line: number,\n options: { top?: number; threshold?: number } = {}\n): SimilarityResult[] {\n const { top = 10, threshold = 0.5 } = options;\n\n // Find the chunk at this location\n const chunk = metadataStore.getAtLocation(filePath, line);\n if (!chunk) {\n return [];\n }\n\n // Get the vector for this chunk\n const vector = vectorStore.get(chunk.id);\n if (!vector) {\n return [];\n }\n\n // Find similar chunks (excluding self)\n const similar = vectorStore.findSimilar(vector, top + 1, threshold);\n\n return similar.filter((s) => s.id !== chunk.id).slice(0, top);\n}\n\n/**\n * Search for code similar to a text query.\n * Requires embedding the query first.\n */\nexport function findSimilarToQuery(\n vectorStore: VectorStore,\n queryEmbedding: number[],\n options: { top?: number; threshold?: number } = {}\n): SimilarityResult[] {\n const { top = 10, threshold = 0.5 } = options;\n\n return vectorStore.findSimilar(queryEmbedding, top, threshold);\n}\n","/**\n * Code Normalizer\n *\n * Normalizes code before comparison to improve duplicate detection:\n * 1. Replaces identifiers with canonical placeholders (for near-identical detection)\n * 2. Normalizes semantic equivalents (size/dimension, onClick/onPress)\n * 3. Strips comments and normalizes whitespace\n *\n * This is particularly useful for detecting utility functions that are\n * copy-pasted with only variable name changes.\n */\n\nexport interface NormalizationOptions {\n /** Replace all local identifiers with placeholders (aggressive) */\n normalizeIdentifiers?: boolean;\n /** Normalize semantic equivalents like size/dimension */\n normalizeSemantics?: boolean;\n /** Strip comments from code */\n stripComments?: boolean;\n /** Normalize whitespace to single spaces */\n normalizeWhitespace?: boolean;\n}\n\nexport const DEFAULT_NORMALIZATION_OPTIONS: NormalizationOptions = {\n normalizeIdentifiers: false,\n normalizeSemantics: true,\n stripComments: true,\n normalizeWhitespace: true,\n};\n\n/**\n * Semantic equivalent patterns.\n * Maps common naming variations to canonical forms.\n */\nconst SEMANTIC_EQUIVALENTS: Array<[RegExp, string]> = [\n // Size-related props\n [/\\b(size|dimension|scale|magnitude)\\b/gi, \"__SIZE__\"],\n // Variant-related props\n [/\\b(variant|type|kind|style|mode)\\b/gi, \"__VARIANT__\"],\n // Click/press handlers\n [/\\b(onClick|onPress|onTap|handleClick|handlePress|onSelect)\\b/g, \"__CLICK_HANDLER__\"],\n // Change handlers\n [/\\b(onChange|onInput|handleChange|handleInput)\\b/g, \"__CHANGE_HANDLER__\"],\n // Submit handlers\n [/\\b(onSubmit|handleSubmit)\\b/g, \"__SUBMIT_HANDLER__\"],\n // Loading states\n [/\\b(loading|isLoading|pending|isFetching|isBusy)\\b/gi, \"__LOADING__\"],\n // Error states\n [/\\b(error|err|errorMsg|errorMessage|failure)\\b/gi, \"__ERROR__\"],\n // Success states\n [/\\b(success|isSuccess|succeeded|done)\\b/gi, \"__SUCCESS__\"],\n // Data/items collections\n [/\\b(data|items|list|results|entries|records)\\b/gi, \"__DATA__\"],\n // Children/content slots\n [/\\b(children|content|body|slot|inner)\\b/gi, \"__CHILDREN__\"],\n // Label/title text\n [/\\b(label|title|heading|name|text)\\b/gi, \"__LABEL__\"],\n // Description/message\n [/\\b(description|message|subtitle|detail|info)\\b/gi, \"__DESCRIPTION__\"],\n // Value/amount\n [/\\b(value|amount|total|count|number)\\b/gi, \"__VALUE__\"],\n // Disabled state\n [/\\b(disabled|isDisabled|readonly|readOnly)\\b/gi, \"__DISABLED__\"],\n // Visible/shown state\n [/\\b(visible|isVisible|shown|isShown|open|isOpen)\\b/gi, \"__VISIBLE__\"],\n // Class names\n [/\\b(className|classes|style|styles)\\b/gi, \"__CLASSNAME__\"],\n];\n\n/**\n * Strip comments from code.\n */\nfunction stripComments(code: string): string {\n // Remove single-line comments\n let result = code.replace(/\\/\\/.*$/gm, \"\");\n // Remove multi-line comments\n result = result.replace(/\\/\\*[\\s\\S]*?\\*\\//g, \"\");\n return result;\n}\n\n/**\n * Normalize whitespace to single spaces.\n */\nfunction normalizeWhitespace(code: string): string {\n return code\n .replace(/\\s+/g, \" \")\n .replace(/\\s*([{}[\\]();,:<>])\\s*/g, \"$1\")\n .trim();\n}\n\n/**\n * Apply semantic normalization patterns.\n */\nfunction applySemanticNormalization(code: string): string {\n let result = code;\n for (const [pattern, replacement] of SEMANTIC_EQUIVALENTS) {\n result = result.replace(pattern, replacement);\n }\n return result;\n}\n\n/**\n * Normalize identifiers by replacing them with sequential placeholders.\n * This is an aggressive normalization that makes structurally identical\n * code with different variable names appear identical.\n */\nfunction normalizeIdentifiersSimple(code: string): string {\n const identifierMap = new Map<string, string>();\n let counter = 0;\n\n // Match potential identifiers (simplified approach without full AST parsing)\n // This matches word characters that look like identifiers\n const identifierPattern = /\\b([a-z_$][a-z0-9_$]*)\\b/gi;\n\n // Built-in keywords and common globals to preserve\n const preserveList = new Set([\n // JavaScript keywords\n \"const\",\n \"let\",\n \"var\",\n \"function\",\n \"return\",\n \"if\",\n \"else\",\n \"for\",\n \"while\",\n \"do\",\n \"switch\",\n \"case\",\n \"break\",\n \"continue\",\n \"default\",\n \"try\",\n \"catch\",\n \"finally\",\n \"throw\",\n \"new\",\n \"this\",\n \"class\",\n \"extends\",\n \"super\",\n \"import\",\n \"export\",\n \"from\",\n \"as\",\n \"async\",\n \"await\",\n \"yield\",\n \"typeof\",\n \"instanceof\",\n \"in\",\n \"of\",\n \"void\",\n \"delete\",\n \"true\",\n \"false\",\n \"null\",\n \"undefined\",\n // TypeScript keywords\n \"interface\",\n \"type\",\n \"enum\",\n \"implements\",\n \"private\",\n \"public\",\n \"protected\",\n \"readonly\",\n \"abstract\",\n \"declare\",\n \"namespace\",\n \"module\",\n // React hooks\n \"useState\",\n \"useEffect\",\n \"useCallback\",\n \"useMemo\",\n \"useRef\",\n \"useContext\",\n \"useReducer\",\n \"useLayoutEffect\",\n \"useImperativeHandle\",\n \"useDebugValue\",\n \"useDeferredValue\",\n \"useTransition\",\n \"useId\",\n \"useSyncExternalStore\",\n \"useInsertionEffect\",\n // React\n \"React\",\n \"Component\",\n \"Fragment\",\n \"Suspense\",\n \"memo\",\n \"forwardRef\",\n \"createContext\",\n \"createElement\",\n // Common globals\n \"console\",\n \"window\",\n \"document\",\n \"Math\",\n \"Date\",\n \"JSON\",\n \"Object\",\n \"Array\",\n \"String\",\n \"Number\",\n \"Boolean\",\n \"Promise\",\n \"Set\",\n \"Map\",\n \"WeakSet\",\n \"WeakMap\",\n \"Symbol\",\n \"Error\",\n \"RegExp\",\n \"Intl\",\n \"setTimeout\",\n \"setInterval\",\n \"clearTimeout\",\n \"clearInterval\",\n \"fetch\",\n \"require\",\n // Common type names\n \"string\",\n \"number\",\n \"boolean\",\n \"object\",\n \"any\",\n \"unknown\",\n \"never\",\n \"void\",\n // Normalized placeholders (preserve these)\n \"__SIZE__\",\n \"__VARIANT__\",\n \"__CLICK_HANDLER__\",\n \"__CHANGE_HANDLER__\",\n \"__SUBMIT_HANDLER__\",\n \"__LOADING__\",\n \"__ERROR__\",\n \"__SUCCESS__\",\n \"__DATA__\",\n \"__CHILDREN__\",\n \"__LABEL__\",\n \"__DESCRIPTION__\",\n \"__VALUE__\",\n \"__DISABLED__\",\n \"__VISIBLE__\",\n \"__CLASSNAME__\",\n ]);\n\n return code.replace(identifierPattern, (match) => {\n // Preserve keywords and built-ins\n if (preserveList.has(match) || preserveList.has(match.toLowerCase())) {\n return match;\n }\n\n // Get or create placeholder for this identifier\n const key = match.toLowerCase();\n if (!identifierMap.has(key)) {\n identifierMap.set(key, `_ID${counter++}_`);\n }\n return identifierMap.get(key)!;\n });\n}\n\n/**\n * Normalize code for comparison.\n *\n * @param code The source code to normalize\n * @param options Normalization options\n * @returns Normalized code string\n */\nexport function normalizeCode(\n code: string,\n options: NormalizationOptions = DEFAULT_NORMALIZATION_OPTIONS\n): string {\n let result = code;\n\n // Strip comments first\n if (options.stripComments) {\n result = stripComments(result);\n }\n\n // Apply semantic normalization\n if (options.normalizeSemantics) {\n result = applySemanticNormalization(result);\n }\n\n // Normalize identifiers (most aggressive, do last before whitespace)\n if (options.normalizeIdentifiers) {\n result = normalizeIdentifiersSimple(result);\n }\n\n // Normalize whitespace last\n if (options.normalizeWhitespace) {\n result = normalizeWhitespace(result);\n }\n\n return result;\n}\n\n/**\n * Calculate Levenshtein distance between two strings.\n * Used for fuzzy matching of normalized code.\n */\nexport function levenshteinDistance(a: string, b: string): number {\n // Early termination for identical strings\n if (a === b) return 0;\n\n // Early termination for empty strings\n if (a.length === 0) return b.length;\n if (b.length === 0) return a.length;\n\n // Use two-row optimization for memory efficiency\n let previousRow = new Array(b.length + 1);\n let currentRow = new Array(b.length + 1);\n\n // Initialize first row\n for (let j = 0; j <= b.length; j++) {\n previousRow[j] = j;\n }\n\n // Fill in the rest of the matrix\n for (let i = 1; i <= a.length; i++) {\n currentRow[0] = i;\n\n for (let j = 1; j <= b.length; j++) {\n const cost = a[i - 1] === b[j - 1] ? 0 : 1;\n currentRow[j] = Math.min(\n previousRow[j] + 1, // Deletion\n currentRow[j - 1] + 1, // Insertion\n previousRow[j - 1] + cost // Substitution\n );\n }\n\n // Swap rows\n [previousRow, currentRow] = [currentRow, previousRow];\n }\n\n return previousRow[b.length];\n}\n\n/**\n * Calculate normalized similarity between two code snippets.\n * Returns 1.0 for identical normalized code, lower for differences.\n *\n * @param codeA First code snippet\n * @param codeB Second code snippet\n * @param options Normalization options\n * @returns Similarity score between 0 and 1\n */\nexport function calculateNormalizedSimilarity(\n codeA: string,\n codeB: string,\n options: NormalizationOptions = { normalizeIdentifiers: true, normalizeSemantics: true }\n): number {\n const normalizedA = normalizeCode(codeA, options);\n const normalizedB = normalizeCode(codeB, options);\n\n // Exact match after normalization\n if (normalizedA === normalizedB) {\n return 1.0;\n }\n\n // Calculate Levenshtein-based similarity\n const distance = levenshteinDistance(normalizedA, normalizedB);\n const maxLen = Math.max(normalizedA.length, normalizedB.length);\n\n if (maxLen === 0) return 1.0;\n\n return 1 - distance / maxLen;\n}\n\n/**\n * Quick check if two code snippets are near-identical after normalization.\n *\n * @param codeA First code snippet\n * @param codeB Second code snippet\n * @param threshold Minimum similarity to consider near-identical (default: 0.95)\n * @returns True if the code is near-identical\n */\nexport function isNearIdentical(\n codeA: string,\n codeB: string,\n threshold: number = 0.95\n): boolean {\n return calculateNormalizedSimilarity(codeA, codeB) >= threshold;\n}\n\n/**\n * Prepare code for embedding by applying light normalization.\n * This is less aggressive than full normalization and is meant\n * to improve embedding quality without losing semantic meaning.\n *\n * @param code The source code\n * @returns Lightly normalized code for embedding\n */\nexport function prepareForEmbedding(code: string): string {\n return normalizeCode(code, {\n normalizeIdentifiers: false,\n normalizeSemantics: true,\n stripComments: true,\n normalizeWhitespace: false, // Preserve structure for embedding\n });\n}\n","/**\n * Combined Scorer\n *\n * Combines multiple similarity signals into a final score:\n * - Semantic similarity (from embeddings)\n * - Structural similarity (from metadata: props, JSX, hooks)\n * - Normalized similarity (from AST normalization - optional, expensive)\n *\n * The combined approach catches more duplicates than embedding alone:\n * - Structural catches same-structure/different-names cases\n * - Normalization catches copy-paste with renamed variables\n * - Semantic catches conceptually similar but differently structured code\n */\n\nimport type { StoredChunkMetadata } from \"../index/types.js\";\nimport {\n calculateStructuralSimilarity,\n type StructuralScore,\n} from \"./structural-scorer.js\";\nimport { calculateNormalizedSimilarity } from \"./normalizer.js\";\nimport {\n getConfidenceLevel,\n getConfidenceResult,\n type ConfidenceLevel,\n type ConfidenceResult,\n} from \"./confidence.js\";\n\nexport interface CombinedScore {\n /** Final combined score (0-1) */\n final: number;\n /** Semantic embedding similarity (0-1) */\n semantic: number;\n /** Structural metadata similarity (0-1) */\n structural: number;\n /** Detailed structural breakdown */\n structuralDetails: StructuralScore;\n /** Normalized code similarity (0-1, only if computed) */\n normalized?: number;\n /** Confidence level based on final score */\n confidence: ConfidenceLevel;\n /** Detailed confidence result */\n confidenceDetails: ConfidenceResult;\n}\n\nexport interface CombinedScorerOptions {\n /** Weight for semantic similarity (default: 0.5) */\n semanticWeight?: number;\n /** Weight for structural similarity (default: 0.3) */\n structuralWeight?: number;\n /** Weight for normalized similarity (default: 0.2) */\n normalizedWeight?: number;\n /** Whether to compute normalized similarity (expensive) */\n includeNormalized?: boolean;\n}\n\nexport const DEFAULT_COMBINED_SCORER_OPTIONS: Required<CombinedScorerOptions> = {\n semanticWeight: 0.5,\n structuralWeight: 0.3,\n normalizedWeight: 0.2,\n includeNormalized: false,\n};\n\n/**\n * Calculate combined similarity score using multiple signals.\n *\n * @param semanticScore Embedding-based similarity score (0-1)\n * @param metadataA Metadata for first chunk\n * @param metadataB Metadata for second chunk\n * @param codeA Source code of first chunk (optional, needed for normalization)\n * @param codeB Source code of second chunk (optional, needed for normalization)\n * @param options Scoring options\n * @returns Combined score with all components\n */\nexport function calculateCombinedScore(\n semanticScore: number,\n metadataA: StoredChunkMetadata,\n metadataB: StoredChunkMetadata,\n codeA?: string,\n codeB?: string,\n options: CombinedScorerOptions = {}\n): CombinedScore {\n const opts = { ...DEFAULT_COMBINED_SCORER_OPTIONS, ...options };\n\n // Calculate structural similarity\n const structuralDetails = calculateStructuralSimilarity(metadataA, metadataB);\n const structural = structuralDetails.combined;\n\n // Calculate normalized similarity if requested and code is available\n let normalized: number | undefined;\n if (opts.includeNormalized && codeA && codeB) {\n normalized = calculateNormalizedSimilarity(codeA, codeB);\n }\n\n // Calculate final score based on available signals\n let final: number;\n\n if (normalized !== undefined) {\n // All three signals available\n final =\n semanticScore * opts.semanticWeight +\n structural * opts.structuralWeight +\n normalized * opts.normalizedWeight;\n } else {\n // Only semantic and structural available\n // Redistribute normalized weight proportionally\n const totalWeight = opts.semanticWeight + opts.structuralWeight;\n const adjustedSemanticWeight = opts.semanticWeight / totalWeight;\n const adjustedStructuralWeight = opts.structuralWeight / totalWeight;\n\n final =\n semanticScore * adjustedSemanticWeight + structural * adjustedStructuralWeight;\n }\n\n // Boost score if any single signal is very high (catch obvious duplicates)\n final = applyBoostForHighSignals(final, semanticScore, structural, normalized);\n\n // Ensure final is clamped to [0, 1]\n final = Math.max(0, Math.min(1, final));\n\n const confidence = getConfidenceLevel(final);\n const confidenceDetails = getConfidenceResult(final);\n\n return {\n final,\n semantic: semanticScore,\n structural,\n structuralDetails,\n normalized,\n confidence,\n confidenceDetails,\n };\n}\n\n/**\n * Apply boost to final score if any individual signal is very high.\n * This ensures that obvious duplicates (e.g., 98% normalized similarity)\n * are not penalized by lower scores in other dimensions.\n */\nfunction applyBoostForHighSignals(\n baseScore: number,\n semantic: number,\n structural: number,\n normalized?: number\n): number {\n const HIGH_SIGNAL_THRESHOLD = 0.95;\n const BOOST_FACTOR = 0.1;\n\n let boost = 0;\n\n // If normalized similarity is very high, this is almost certainly a duplicate\n if (normalized !== undefined && normalized >= HIGH_SIGNAL_THRESHOLD) {\n boost = Math.max(boost, (normalized - HIGH_SIGNAL_THRESHOLD) * 2);\n }\n\n // If semantic similarity is very high\n if (semantic >= HIGH_SIGNAL_THRESHOLD) {\n boost = Math.max(boost, (semantic - HIGH_SIGNAL_THRESHOLD) * 1.5);\n }\n\n // If structural similarity is very high\n if (structural >= HIGH_SIGNAL_THRESHOLD) {\n boost = Math.max(boost, (structural - HIGH_SIGNAL_THRESHOLD) * 1.5);\n }\n\n return baseScore + boost * BOOST_FACTOR;\n}\n\n/**\n * Quick pre-filter check using only structural similarity.\n * Use this to avoid expensive embedding comparisons for obviously dissimilar code.\n *\n * @param metadataA First chunk metadata\n * @param metadataB Second chunk metadata\n * @param threshold Minimum structural similarity to consider (default: 0.3)\n * @returns True if chunks are potentially similar enough to warrant full comparison\n */\nexport function isPotentialDuplicate(\n metadataA: StoredChunkMetadata,\n metadataB: StoredChunkMetadata,\n threshold: number = 0.3\n): boolean {\n const structural = calculateStructuralSimilarity(metadataA, metadataB);\n return structural.combined >= threshold;\n}\n\n/**\n * Calculate quick similarity using only structural features.\n * Useful when embedding scores are not available.\n */\nexport function calculateQuickScore(\n metadataA: StoredChunkMetadata,\n metadataB: StoredChunkMetadata\n): { score: number; confidence: ConfidenceLevel } {\n const structural = calculateStructuralSimilarity(metadataA, metadataB);\n const confidence = getConfidenceLevel(structural.combined);\n return { score: structural.combined, confidence };\n}\n\n/**\n * Determine the best action based on combined score.\n */\nexport function getRecommendedAction(score: CombinedScore): string {\n if (score.normalized !== undefined && score.normalized >= 0.95) {\n return \"These appear to be near-identical. Consolidate into a single implementation.\";\n }\n\n if (score.final >= 0.9) {\n return \"High similarity detected. Strongly consider consolidating into a shared component/function.\";\n }\n\n if (score.final >= 0.75) {\n return \"Moderate similarity. Review for potential abstraction into a shared utility.\";\n }\n\n if (score.structural >= 0.8 && score.semantic < 0.7) {\n return \"Similar structure but different semantics. May be intentionally different implementations.\";\n }\n\n if (score.semantic >= 0.8 && score.structural < 0.5) {\n return \"Similar purpose but different structure. Consider if a common abstraction makes sense.\";\n }\n\n return \"Low similarity. Likely different implementations that happen to share some patterns.\";\n}\n\n/**\n * Format combined score for display.\n */\nexport function formatCombinedScore(score: CombinedScore, verbose: boolean = false): string {\n const percent = Math.round(score.final * 100);\n const lines: string[] = [];\n\n lines.push(`${percent}% similar (${score.confidence} confidence)`);\n\n if (verbose) {\n lines.push(` Semantic: ${Math.round(score.semantic * 100)}%`);\n lines.push(` Structural: ${Math.round(score.structural * 100)}%`);\n if (score.normalized !== undefined) {\n lines.push(` Normalized: ${Math.round(score.normalized * 100)}%`);\n }\n lines.push(` → ${getRecommendedAction(score)}`);\n }\n\n return lines.join(\"\\n\");\n}\n"],"mappings":"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","names":["existsSync","mkdirSync","readFileSync","writeFileSync","join","existsSync","mkdirSync","readFileSync","writeFileSync","join","existsSync","mkdirSync","readFileSync","writeFileSync","join","join","existsSync","readFileSync","mkdirSync","writeFileSync","calculateSizeRatio"]}