UNPKG

@opichi/smartcode

Version:

Universal code intelligence MCP server - analyze any codebase with TypeScript excellence and multi-language support

226 lines 7.94 kB
import { QdrantClient } from '@qdrant/js-client-rest'; export class CodeVectorStore { client; collectionName = 'code_nodes'; constructor(url = 'http://localhost:6333') { this.client = new QdrantClient({ url }); } async initialize() { try { // Check if collection exists const collections = await this.client.getCollections(); const exists = collections.collections.some(c => c.name === this.collectionName); if (!exists) { // Create collection with appropriate vector size (384 for sentence transformers) await this.client.createCollection(this.collectionName, { vectors: { size: 384, distance: 'Cosine' } }); console.log(`Created Qdrant collection: ${this.collectionName}`); } } catch (error) { console.error('Failed to initialize Qdrant:', error); throw error; } } async indexNode(node) { if (!node.embedding) { throw new Error('Node must have embedding before indexing'); } try { await this.client.upsert(this.collectionName, { wait: true, points: [ { id: this.hashId(node.id), vector: node.embedding, payload: { id: node.id, type: node.type, name: node.name, filePath: node.filePath, startLine: node.startLine, endLine: node.endLine, content: node.content, metadata: node.metadata } } ] }); } catch (error) { console.error(`Failed to index node ${node.id}:`, error); throw error; } } async indexNodes(nodes) { const nodesWithEmbeddings = nodes.filter(node => node.embedding); if (nodesWithEmbeddings.length === 0) { return; } try { const points = nodesWithEmbeddings.map(node => ({ id: this.hashId(node.id), vector: node.embedding, payload: { id: node.id, type: node.type, name: node.name, filePath: node.filePath, startLine: node.startLine, endLine: node.endLine, content: node.content, metadata: node.metadata } })); await this.client.upsert(this.collectionName, { wait: true, points }); console.log(`Indexed ${points.length} code nodes`); } catch (error) { console.error('Failed to index nodes:', error); throw error; } } async searchSimilar(queryEmbedding, limit = 10, filter) { try { const searchResult = await this.client.search(this.collectionName, { vector: queryEmbedding, limit, filter, with_payload: true, score_threshold: 0.3 // Only return results with decent similarity }); return searchResult.map(result => ({ node: { id: result.payload.id, type: result.payload.type, name: result.payload.name, filePath: result.payload.filePath, startLine: result.payload.startLine, endLine: result.payload.endLine, content: result.payload.content, metadata: result.payload.metadata }, score: result.score, context: this.generateContext(result.payload.content), relationships: [] // Will be populated by knowledge graph })); } catch (error) { console.error('Failed to search:', error); throw error; } } async searchByType(nodeType, limit = 50) { try { const searchResult = await this.client.scroll(this.collectionName, { filter: { must: [ { key: 'type', match: { value: nodeType } } ] }, limit, with_payload: true }); return searchResult.points.map(point => ({ id: point.payload.id, type: point.payload.type, name: point.payload.name, filePath: point.payload.filePath, startLine: point.payload.startLine, endLine: point.payload.endLine, content: point.payload.content, metadata: point.payload.metadata })); } catch (error) { console.error('Failed to search by type:', error); throw error; } } async searchByFile(filePath) { try { const searchResult = await this.client.scroll(this.collectionName, { filter: { must: [ { key: 'filePath', match: { value: filePath } } ] }, limit: 1000, with_payload: true }); return searchResult.points.map(point => ({ id: point.payload.id, type: point.payload.type, name: point.payload.name, filePath: point.payload.filePath, startLine: point.payload.startLine, endLine: point.payload.endLine, content: point.payload.content, metadata: point.payload.metadata })); } catch (error) { console.error('Failed to search by file:', error); throw error; } } async deleteByFile(filePath) { try { await this.client.delete(this.collectionName, { filter: { must: [ { key: 'filePath', match: { value: filePath } } ] } }); } catch (error) { console.error(`Failed to delete nodes for file ${filePath}:`, error); throw error; } } async clear() { try { await this.client.deleteCollection(this.collectionName); await this.initialize(); } catch (error) { console.error('Failed to clear collection:', error); throw error; } } hashId(id) { // Simple hash function to convert string ID to number let hash = 0; for (let i = 0; i < id.length; i++) { const char = id.charCodeAt(i); hash = ((hash << 5) - hash) + char; hash = hash & hash; // Convert to 32-bit integer } return Math.abs(hash); } generateContext(content) { // Generate a brief context snippet const lines = content.split('\n'); const firstLine = lines[0]?.trim() || ''; const preview = firstLine.length > 100 ? firstLine.substring(0, 100) + '...' : firstLine; return preview; } } //# sourceMappingURL=qdrant.js.map