@gettymade/roux 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../node_modules/string-similarity/src/index.js","../src/types/node.ts","../src/types/provider.ts","../src/types/config.ts","../src/providers/docstore/index.ts","../src/providers/docstore/cache.ts","../src/providers/vector/sqlite.ts","../src/providers/docstore/parser.ts","../src/graph/builder.ts","../src/graph/operations.ts","../src/providers/embedding/transformers.ts","../src/core/graphcore.ts","../src/index.ts"],"sourcesContent":["module.exports = {\n\tcompareTwoStrings:compareTwoStrings,\n\tfindBestMatch:findBestMatch\n};\n\nfunction compareTwoStrings(first, second) {\n\tfirst = first.replace(/\\s+/g, '')\n\tsecond = second.replace(/\\s+/g, '')\n\n\tif (first === second) return 1; // identical or empty\n\tif (first.length < 2 || second.length < 2) return 0; // if either is a 0-letter or 1-letter string\n\n\tlet firstBigrams = new Map();\n\tfor (let i = 0; i < first.length - 1; i++) {\n\t\tconst bigram = first.substring(i, i + 2);\n\t\tconst count = firstBigrams.has(bigram)\n\t\t\t? firstBigrams.get(bigram) + 1\n\t\t\t: 1;\n\n\t\tfirstBigrams.set(bigram, count);\n\t};\n\n\tlet intersectionSize = 0;\n\tfor (let i = 0; i < second.length - 1; i++) {\n\t\tconst bigram = second.substring(i, i + 2);\n\t\tconst count = firstBigrams.has(bigram)\n\t\t\t? firstBigrams.get(bigram)\n\t\t\t: 0;\n\n\t\tif (count > 0) {\n\t\t\tfirstBigrams.set(bigram, count - 1);\n\t\t\tintersectionSize++;\n\t\t}\n\t}\n\n\treturn (2.0 * intersectionSize) / (first.length + second.length - 2);\n}\n\nfunction findBestMatch(mainString, targetStrings) {\n\tif (!areArgsValid(mainString, targetStrings)) throw new Error('Bad arguments: First argument should be a string, second should be an array of strings');\n\t\n\tconst ratings = [];\n\tlet bestMatchIndex = 0;\n\n\tfor (let i = 0; i < targetStrings.length; i++) {\n\t\tconst currentTargetString = targetStrings[i];\n\t\tconst currentRating = compareTwoStrings(mainString, currentTargetString)\n\t\tratings.push({target: currentTargetString, rating: currentRating})\n\t\tif (currentRating > ratings[bestMatchIndex].rating) {\n\t\t\tbestMatchIndex = i\n\t\t}\n\t}\n\t\n\t\n\tconst bestMatch = ratings[bestMatchIndex]\n\t\n\treturn { ratings: ratings, bestMatch: bestMatch, bestMatchIndex: bestMatchIndex };\n}\n\nfunction areArgsValid(mainString, targetStrings) {\n\tif (typeof mainString !== 'string') return false;\n\tif (!Array.isArray(targetStrings)) return false;\n\tif (!targetStrings.length) return false;\n\tif (targetStrings.find( function (s) { return typeof s !== 'string'})) return false;\n\treturn true;\n}\n","export interface SourceRef {\n type: 'file' | 'api' | 'manual';\n path?: string;\n lastModified?: Date;\n}\n\n/** The canonical data model. All modules speak Node. */\nexport interface Node {\n /** Store-specific format */\n id: string;\n title: string;\n content: string;\n tags: string[];\n /** By id */\n outgoingLinks: string[];\n properties: Record<string, unknown>;\n sourceRef?: SourceRef;\n}\n\nexport interface NodeWithContext extends Node {\n /** Populated when depth > 0 */\n neighbors?: Node[];\n incomingCount?: number;\n outgoingCount?: number;\n}\n\nexport function isNode(value: unknown): value is Node {\n if (typeof value !== 'object' || value === null) {\n return false;\n }\n const obj = value as Record<string, unknown>;\n return (\n typeof obj['id'] === 'string' &&\n typeof obj['title'] === 'string' &&\n typeof obj['content'] === 'string' &&\n Array.isArray(obj['tags']) &&\n obj['tags'].every((t) => typeof t === 'string') &&\n Array.isArray(obj['outgoingLinks']) &&\n obj['outgoingLinks'].every((l) => typeof l === 'string') &&\n typeof obj['properties'] === 'object' &&\n obj['properties'] !== null\n );\n}\n\nexport function isSourceRef(value: unknown): value is SourceRef {\n if (typeof value !== 'object' || value === null) {\n return false;\n }\n const obj = value as Record<string, unknown>;\n const validTypes = ['file', 'api', 'manual'];\n return (\n typeof obj['type'] === 'string' &&\n validTypes.includes(obj['type']) &&\n (obj['path'] === undefined || typeof obj['path'] === 'string') &&\n (obj['lastModified'] === undefined || obj['lastModified'] instanceof Date)\n );\n}\n","import type { Node } from './node.js';\nimport type { Direction, NeighborOptions } from './edge.js';\n\nexport type Metric = 'pagerank' | 'in_degree' | 'out_degree';\n\n// Batch operation types\nexport interface ListFilter {\n /** Filter by tag (case-insensitive) */\n tag?: string;\n /** Filter by path prefix (startsWith) */\n path?: string;\n}\n\nexport interface ListOptions {\n /** Default 100, max 1000 */\n limit?: number;\n /** Default 0 */\n offset?: number;\n}\n\nexport interface NodeSummary {\n id: string;\n title: string;\n}\n\nexport interface ListNodesResult {\n nodes: NodeSummary[];\n /** Total matching nodes (before limit/offset applied) */\n total: number;\n}\n\nexport type ResolveStrategy = 'exact' | 'fuzzy' | 'semantic';\n\nexport interface ResolveOptions {\n /** Filter candidates by tag */\n tag?: string;\n /** Filter candidates by path prefix */\n path?: string;\n /** 0-1, default 0.7, ignored for 'exact' */\n threshold?: number;\n /** Default 'fuzzy' */\n strategy?: ResolveStrategy;\n}\n\nexport interface ResolveResult {\n /** Original input */\n query: string;\n /** Matched node ID or null */\n match: string | null;\n /** 0-1, 0 if no match */\n score: number;\n}\n\nexport interface CentralityMetrics {\n inDegree: number;\n outDegree: number;\n}\n\nexport type TagMode = 'any' | 'all';\n\nexport interface VectorSearchResult {\n id: string;\n distance: number;\n}\n\n/** Link with resolved title for MCP responses. */\nexport interface LinkInfo {\n id: string;\n title: string;\n}\n\n/** Data persistence and graph operations. Required provider. */\nexport interface StoreProvider {\n // CRUD\n createNode(node: Node): Promise<void>;\n updateNode(id: string, updates: Partial<Node>): Promise<void>;\n deleteNode(id: string): Promise<void>;\n getNode(id: string): Promise<Node | null>;\n getNodes(ids: string[]): Promise<Node[]>;\n\n // Graph operations\n getNeighbors(id: string, options: NeighborOptions): Promise<Node[]>;\n findPath(source: string, target: string): Promise<string[] | null>;\n getHubs(metric: Metric, limit: number): Promise<Array<[string, number]>>;\n\n // Vector storage\n storeEmbedding(id: string, vector: number[], model: string): Promise<void>;\n searchByVector(\n vector: number[],\n limit: number\n ): Promise<VectorSearchResult[]>;\n\n // Search\n searchByTags(tags: string[], mode: TagMode): Promise<Node[]>;\n\n // Discovery\n getRandomNode(tags?: string[]): Promise<Node | null>;\n\n // Link resolution (for MCP response formatting)\n resolveTitles(ids: string[]): Promise<Map<string, string>>;\n\n // Batch operations\n listNodes(filter: ListFilter, options?: ListOptions): Promise<ListNodesResult>;\n resolveNodes(names: string[], options?: ResolveOptions): Promise<ResolveResult[]>;\n nodesExist(ids: string[]): Promise<Map<string, boolean>>;\n}\n\n/** Stateless vector generation. Storage handled by StoreProvider. */\nexport interface EmbeddingProvider {\n embed(text: string): Promise<number[]>;\n embedBatch(texts: string[]): Promise<number[][]>;\n /** For storage allocation */\n dimensions(): number;\n modelId(): string;\n}\n\n/** Pluggable vector storage and similarity search. */\nexport interface VectorProvider {\n store(id: string, vector: number[], model: string): Promise<void>;\n search(vector: number[], limit: number): Promise<VectorSearchResult[]>;\n delete(id: string): Promise<void>;\n getModel(id: string): Promise<string | null>;\n hasEmbedding(id: string): boolean;\n}\n\nexport function isVectorProvider(value: unknown): value is VectorProvider {\n if (value === null || typeof value !== 'object') {\n return false;\n }\n const obj = value as Record<string, unknown>;\n return (\n typeof obj.store === 'function' &&\n typeof obj.search === 'function' &&\n typeof obj.delete === 'function' &&\n typeof obj.getModel === 'function' &&\n typeof obj.hasEmbedding === 'function'\n );\n}\n\n// Re-export for convenience\nexport type { Direction, NeighborOptions };\n","export interface SourceConfig {\n /** Relative to config file */\n path: string;\n include: string[];\n /** .roux/ always excluded (hardcoded) */\n exclude: string[];\n}\n\nexport interface CacheConfig {\n /** SQLite directory */\n path: string;\n}\n\nexport type ModelChangeBehavior = 'lazy' | 'eager';\n\nexport interface SystemConfig {\n /** Embedding regeneration strategy */\n onModelChange: ModelChangeBehavior;\n}\n\nexport interface DocStoreConfig {\n type: 'docstore';\n}\n\nexport interface LocalEmbeddingConfig {\n type: 'local';\n /** Default: Xenova/all-MiniLM-L6-v2 */\n model?: string;\n}\n\nexport interface OllamaEmbeddingConfig {\n type: 'ollama';\n model: string;\n endpoint?: string;\n timeout?: number;\n}\n\nexport interface OpenAIEmbeddingConfig {\n type: 'openai';\n model: string;\n timeout?: number;\n}\n\nexport type EmbeddingConfig =\n | LocalEmbeddingConfig\n | OllamaEmbeddingConfig\n | OpenAIEmbeddingConfig;\n\nexport interface OllamaLLMConfig {\n type: 'ollama';\n model: string;\n endpoint?: string;\n timeout?: number;\n}\n\nexport interface OpenAILLMConfig {\n type: 'openai';\n model: string;\n timeout?: number;\n}\n\nexport type LLMConfig = OllamaLLMConfig | OpenAILLMConfig;\n\nexport type StoreConfig = DocStoreConfig;\n\nexport interface ProvidersConfig {\n store: StoreConfig;\n /** Defaults to local */\n embedding?: EmbeddingConfig;\n llm?: LLMConfig;\n}\n\nexport interface RouxConfig {\n source?: SourceConfig;\n cache?: CacheConfig;\n system?: SystemConfig;\n providers: ProvidersConfig;\n}\n\nexport const DEFAULT_CONFIG: Required<\n Pick<RouxConfig, 'source' | 'cache' | 'system'>\n> & { providers: { store: DocStoreConfig } } = {\n source: {\n path: '.',\n include: ['*.md'],\n exclude: [],\n },\n cache: {\n path: '.roux/',\n },\n system: {\n onModelChange: 'lazy',\n },\n providers: {\n store: {\n type: 'docstore',\n },\n },\n};\n","import { readFile, writeFile, stat, readdir, mkdir, rm } from 'node:fs/promises';\nimport { join, relative, dirname, resolve } from 'node:path';\nimport { watch, type FSWatcher } from 'chokidar';\nimport type { DirectedGraph } from 'graphology';\nimport type { Node } from '../../types/node.js';\nimport type {\n StoreProvider,\n NeighborOptions,\n Metric,\n TagMode,\n VectorSearchResult,\n VectorProvider,\n ListFilter,\n ListOptions,\n ListNodesResult,\n ResolveOptions,\n ResolveResult,\n} from '../../types/provider.js';\nimport { Cache } from './cache.js';\nimport { SqliteVectorProvider } from '../vector/sqlite.js';\nimport {\n parseMarkdown,\n extractWikiLinks,\n normalizeId,\n titleFromPath,\n serializeToMarkdown,\n} from './parser.js';\nimport { buildGraph } from '../../graph/builder.js';\nimport {\n getNeighborIds,\n findPath as graphFindPath,\n getHubs as graphGetHubs,\n computeCentrality,\n} from '../../graph/operations.js';\n\nexport class DocStore implements StoreProvider {\n private cache: Cache;\n private sourceRoot: string;\n private graph: DirectedGraph | null = null;\n private vectorProvider: VectorProvider;\n private ownsVectorProvider: boolean;\n\n private watcher: FSWatcher | null = null;\n private debounceTimer: ReturnType<typeof setTimeout> | null = null;\n private pendingChanges: Map<string, 'add' | 'change' | 'unlink'> = new Map();\n private onChangeCallback: ((changedIds: string[]) => void) | undefined;\n\n constructor(\n sourceRoot: string,\n cacheDir: string,\n vectorProvider?: VectorProvider\n ) {\n this.sourceRoot = sourceRoot;\n this.cache = new Cache(cacheDir);\n this.ownsVectorProvider = !vectorProvider;\n this.vectorProvider = vectorProvider ?? new SqliteVectorProvider(cacheDir);\n }\n\n async sync(): Promise<void> {\n const currentPaths = await this.collectMarkdownFiles(this.sourceRoot);\n const trackedPaths = this.cache.getAllTrackedPaths();\n\n // Process new/modified files\n for (const filePath of currentPaths) {\n try {\n const mtime = await this.getFileMtime(filePath);\n const cachedMtime = this.cache.getModifiedTime(filePath);\n\n if (cachedMtime === null || mtime > cachedMtime) {\n const node = await this.fileToNode(filePath);\n this.cache.upsertNode(node, 'file', filePath, mtime);\n }\n } catch (err) {\n // File may have been deleted between readdir and stat — skip it\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n continue;\n }\n throw err;\n }\n }\n\n // Remove deleted files\n const currentSet = new Set(currentPaths);\n for (const tracked of trackedPaths) {\n if (!currentSet.has(tracked)) {\n const node = this.cache.getNodeByPath(tracked);\n if (node) {\n this.cache.deleteNode(node.id);\n }\n }\n }\n\n // Resolve wiki-links after all nodes are cached\n const filenameIndex = this.buildFilenameIndex();\n this.resolveOutgoingLinks(filenameIndex);\n\n // Rebuild graph from all nodes\n this.rebuildGraph();\n }\n\n async createNode(node: Node): Promise<void> {\n const normalizedId = normalizeId(node.id);\n this.validatePathWithinSource(normalizedId);\n\n const existing = this.cache.getNode(normalizedId);\n if (existing) {\n throw new Error(`Node already exists: ${normalizedId}`);\n }\n\n const filePath = join(this.sourceRoot, normalizedId);\n const dir = dirname(filePath);\n await mkdir(dir, { recursive: true });\n\n const parsed = {\n title: node.title,\n tags: node.tags,\n properties: node.properties,\n content: node.content,\n };\n const markdown = serializeToMarkdown(parsed);\n await writeFile(filePath, markdown, 'utf-8');\n\n const mtime = await this.getFileMtime(filePath);\n const normalizedNode = { ...node, id: normalizedId };\n this.cache.upsertNode(normalizedNode, 'file', filePath, mtime);\n\n // Rebuild graph to include new node\n this.rebuildGraph();\n }\n\n async updateNode(id: string, updates: Partial<Node>): Promise<void> {\n const normalizedId = normalizeId(id);\n const existing = this.cache.getNode(normalizedId);\n if (!existing) {\n throw new Error(`Node not found: ${id}`);\n }\n\n // If content is updated, reparse wiki-links\n let outgoingLinks = updates.outgoingLinks;\n if (updates.content !== undefined && outgoingLinks === undefined) {\n const rawLinks = extractWikiLinks(updates.content);\n outgoingLinks = rawLinks.map((link) => this.normalizeWikiLink(link));\n }\n\n const updated: Node = {\n ...existing,\n ...updates,\n outgoingLinks: outgoingLinks ?? existing.outgoingLinks,\n id: existing.id, // ID cannot be changed\n };\n\n const filePath = join(this.sourceRoot, existing.id);\n const parsed = {\n title: updated.title,\n tags: updated.tags,\n properties: updated.properties,\n content: updated.content,\n };\n const markdown = serializeToMarkdown(parsed);\n await writeFile(filePath, markdown, 'utf-8');\n\n const mtime = await this.getFileMtime(filePath);\n this.cache.upsertNode(updated, 'file', filePath, mtime);\n\n // Rebuild graph if links changed\n if (outgoingLinks !== undefined || updates.outgoingLinks !== undefined) {\n this.rebuildGraph();\n }\n }\n\n async deleteNode(id: string): Promise<void> {\n const normalizedId = normalizeId(id);\n const existing = this.cache.getNode(normalizedId);\n if (!existing) {\n throw new Error(`Node not found: ${id}`);\n }\n\n const filePath = join(this.sourceRoot, existing.id);\n await rm(filePath);\n this.cache.deleteNode(existing.id);\n await this.vectorProvider.delete(existing.id);\n\n // Rebuild graph without deleted node\n this.rebuildGraph();\n }\n\n async getNode(id: string): Promise<Node | null> {\n // Normalize ID for case-insensitive lookup\n const normalizedId = normalizeId(id);\n return this.cache.getNode(normalizedId);\n }\n\n async getNodes(ids: string[]): Promise<Node[]> {\n const normalizedIds = ids.map(normalizeId);\n return this.cache.getNodes(normalizedIds);\n }\n\n async getAllNodeIds(): Promise<string[]> {\n const nodes = this.cache.getAllNodes();\n return nodes.map((n) => n.id);\n }\n\n async searchByTags(tags: string[], mode: TagMode): Promise<Node[]> {\n return this.cache.searchByTags(tags, mode);\n }\n\n async getRandomNode(tags?: string[]): Promise<Node | null> {\n let candidates: Node[];\n\n if (tags && tags.length > 0) {\n candidates = await this.searchByTags(tags, 'any');\n } else {\n candidates = this.cache.getAllNodes();\n }\n\n if (candidates.length === 0) {\n return null;\n }\n\n const randomIndex = Math.floor(Math.random() * candidates.length);\n // Safe: randomIndex is always 0 to length-1 when length > 0\n return candidates[randomIndex]!;\n }\n\n async resolveTitles(ids: string[]): Promise<Map<string, string>> {\n return this.cache.resolveTitles(ids);\n }\n\n async listNodes(\n filter: ListFilter,\n options?: ListOptions\n ): Promise<ListNodesResult> {\n return this.cache.listNodes(filter, options);\n }\n\n async resolveNodes(\n names: string[],\n options?: ResolveOptions\n ): Promise<ResolveResult[]> {\n // For exact and fuzzy, delegate to cache\n const strategy = options?.strategy ?? 'fuzzy';\n if (strategy === 'exact' || strategy === 'fuzzy') {\n return this.cache.resolveNodes(names, options);\n }\n\n // Semantic strategy: use vector search\n // This requires embedding provider which DocStore doesn't have direct access to\n // Return unmatched for now - GraphCore will handle semantic with embedding provider\n return names.map((query) => ({ query, match: null, score: 0 }));\n }\n\n async nodesExist(ids: string[]): Promise<Map<string, boolean>> {\n const normalizedIds = ids.map(normalizeId);\n return this.cache.nodesExist(normalizedIds);\n }\n\n async getNeighbors(id: string, options: NeighborOptions): Promise<Node[]> {\n this.ensureGraph();\n const neighborIds = getNeighborIds(this.graph!, id, options);\n return this.cache.getNodes(neighborIds);\n }\n\n async findPath(source: string, target: string): Promise<string[] | null> {\n this.ensureGraph();\n return graphFindPath(this.graph!, source, target);\n }\n\n async getHubs(metric: Metric, limit: number): Promise<Array<[string, number]>> {\n this.ensureGraph();\n return graphGetHubs(this.graph!, metric, limit);\n }\n\n async storeEmbedding(\n id: string,\n vector: number[],\n model: string\n ): Promise<void> {\n return this.vectorProvider.store(id, vector, model);\n }\n\n async searchByVector(\n vector: number[],\n limit: number\n ): Promise<VectorSearchResult[]> {\n return this.vectorProvider.search(vector, limit);\n }\n\n hasEmbedding(id: string): boolean {\n return this.vectorProvider.hasEmbedding(id);\n }\n\n close(): void {\n this.stopWatching();\n this.cache.close();\n if (this.ownsVectorProvider && 'close' in this.vectorProvider) {\n (this.vectorProvider as { close: () => void }).close();\n }\n }\n\n startWatching(onChange?: (changedIds: string[]) => void): Promise<void> {\n if (this.watcher) {\n throw new Error('Already watching. Call stopWatching() first.');\n }\n\n this.onChangeCallback = onChange;\n\n return new Promise((resolve, reject) => {\n this.watcher = watch(this.sourceRoot, {\n ignoreInitial: true,\n ignored: [...DocStore.EXCLUDED_DIRS].map((dir) => `**/${dir}/**`),\n awaitWriteFinish: {\n stabilityThreshold: 100,\n },\n followSymlinks: false,\n });\n\n this.watcher\n .on('ready', () => resolve())\n .on('add', (path) => this.queueChange(path, 'add'))\n .on('change', (path) => this.queueChange(path, 'change'))\n .on('unlink', (path) => this.queueChange(path, 'unlink'))\n .on('error', (err) => {\n if ((err as NodeJS.ErrnoException).code === 'EMFILE') {\n console.error(\n 'File watcher hit file descriptor limit. ' +\n 'Try: ulimit -n 65536 or reduce watched files.'\n );\n }\n reject(err);\n });\n });\n }\n\n stopWatching(): void {\n if (this.debounceTimer) {\n clearTimeout(this.debounceTimer);\n this.debounceTimer = null;\n }\n this.pendingChanges.clear();\n\n if (this.watcher) {\n this.watcher.close();\n this.watcher = null;\n }\n }\n\n isWatching(): boolean {\n return this.watcher !== null;\n }\n\n private queueChange(filePath: string, event: 'add' | 'change' | 'unlink'): void {\n const relativePath = relative(this.sourceRoot, filePath);\n const id = normalizeId(relativePath);\n\n // Check exclusions\n if (!filePath.endsWith('.md')) {\n return;\n }\n\n // Check if path contains any excluded directory\n const pathParts = relativePath.split('/');\n for (const part of pathParts) {\n if (DocStore.EXCLUDED_DIRS.has(part)) {\n return;\n }\n }\n\n // Apply coalescing rules\n const existing = this.pendingChanges.get(id);\n\n if (existing) {\n if (existing === 'add' && event === 'change') {\n // add + change = add (keep as add)\n return;\n } else if (existing === 'add' && event === 'unlink') {\n // add + unlink = remove from queue\n this.pendingChanges.delete(id);\n } else if (existing === 'change' && event === 'unlink') {\n // change + unlink = unlink\n this.pendingChanges.set(id, 'unlink');\n }\n // change + change = change (already set, no action needed)\n } else {\n this.pendingChanges.set(id, event);\n }\n\n // Reset debounce timer\n if (this.debounceTimer) {\n clearTimeout(this.debounceTimer);\n }\n\n this.debounceTimer = setTimeout(() => {\n this.processQueue();\n }, 1000);\n }\n\n private async processQueue(): Promise<void> {\n const changes = new Map(this.pendingChanges);\n this.pendingChanges.clear();\n this.debounceTimer = null;\n\n const processedIds: string[] = [];\n\n for (const [id, event] of changes) {\n try {\n if (event === 'unlink') {\n const existing = this.cache.getNode(id);\n if (existing) {\n this.cache.deleteNode(id);\n await this.vectorProvider.delete(id);\n processedIds.push(id);\n }\n } else {\n // add or change\n const filePath = join(this.sourceRoot, id);\n const node = await this.fileToNode(filePath);\n const mtime = await this.getFileMtime(filePath);\n this.cache.upsertNode(node, 'file', filePath, mtime);\n processedIds.push(id);\n }\n } catch (err) {\n console.warn(`Failed to process file change for ${id}:`, err);\n }\n }\n\n // Resolve wiki-links and rebuild graph after processing all changes\n if (processedIds.length > 0) {\n const filenameIndex = this.buildFilenameIndex();\n this.resolveOutgoingLinks(filenameIndex);\n this.rebuildGraph();\n }\n\n // Call callback if provided\n if (this.onChangeCallback && processedIds.length > 0) {\n this.onChangeCallback(processedIds);\n }\n }\n\n private buildFilenameIndex(): Map<string, string[]> {\n const index = new Map<string, string[]>();\n for (const node of this.cache.getAllNodes()) {\n const basename = node.id.split('/').pop()!;\n const existing = index.get(basename) ?? [];\n existing.push(node.id);\n index.set(basename, existing);\n }\n // Sort each array alphabetically for deterministic first-match\n for (const paths of index.values()) {\n paths.sort();\n }\n return index;\n }\n\n private resolveOutgoingLinks(filenameIndex: Map<string, string[]>): void {\n // Build set of valid node IDs for quick lookup\n const validNodeIds = new Set<string>();\n for (const paths of filenameIndex.values()) {\n for (const path of paths) {\n validNodeIds.add(path);\n }\n }\n\n for (const node of this.cache.getAllNodes()) {\n const resolved = node.outgoingLinks.map((link) => {\n // If link already exists as a valid node ID, keep it\n if (validNodeIds.has(link)) {\n return link;\n }\n // Only resolve bare filenames (no path separators)\n // Partial paths like \"folder/target.md\" stay literal\n if (link.includes('/')) {\n return link;\n }\n // Try basename lookup for bare filenames\n const matches = filenameIndex.get(link);\n if (matches && matches.length > 0) {\n return matches[0]!;\n }\n return link;\n });\n\n // Only update if something changed\n if (resolved.some((r, i) => r !== node.outgoingLinks[i])) {\n this.cache.updateOutgoingLinks(node.id, resolved);\n }\n }\n }\n\n private ensureGraph(): void {\n if (!this.graph) {\n this.rebuildGraph();\n }\n }\n\n private rebuildGraph(): void {\n const nodes = this.cache.getAllNodes();\n this.graph = buildGraph(nodes);\n\n // Cache centrality metrics\n const centrality = computeCentrality(this.graph);\n const now = Date.now();\n for (const [id, metrics] of centrality) {\n this.cache.storeCentrality(id, 0, metrics.inDegree, metrics.outDegree, now);\n }\n }\n\n private static readonly EXCLUDED_DIRS = new Set(['.roux', 'node_modules', '.git', '.obsidian']);\n\n private async collectMarkdownFiles(dir: string): Promise<string[]> {\n const results: string[] = [];\n\n let entries;\n try {\n entries = await readdir(dir, { withFileTypes: true });\n } catch {\n // Directory doesn't exist yet\n return results;\n }\n\n for (const entry of entries) {\n const fullPath = join(dir, entry.name);\n\n if (entry.isDirectory()) {\n // Skip excluded directories\n if (DocStore.EXCLUDED_DIRS.has(entry.name)) {\n continue;\n }\n const nested = await this.collectMarkdownFiles(fullPath);\n results.push(...nested);\n } else if (entry.isFile() && entry.name.endsWith('.md')) {\n results.push(fullPath);\n }\n }\n\n return results;\n }\n\n private async getFileMtime(filePath: string): Promise<number> {\n const stats = await stat(filePath);\n return stats.mtimeMs;\n }\n\n private async fileToNode(filePath: string): Promise<Node> {\n const raw = await readFile(filePath, 'utf-8');\n const parsed = parseMarkdown(raw);\n\n const relativePath = relative(this.sourceRoot, filePath);\n const id = normalizeId(relativePath);\n\n // Derive title from path if not in frontmatter\n const title = parsed.title ?? titleFromPath(id);\n\n // Extract and normalize wiki links\n const rawLinks = extractWikiLinks(parsed.content);\n const outgoingLinks = rawLinks.map((link) => this.normalizeWikiLink(link));\n\n return {\n id,\n title,\n content: parsed.content,\n tags: parsed.tags,\n outgoingLinks,\n properties: parsed.properties,\n sourceRef: {\n type: 'file',\n path: filePath,\n lastModified: new Date(await this.getFileMtime(filePath)),\n },\n };\n }\n\n /**\n * Normalize a wiki-link target to an ID.\n * - If it has a file extension, normalize as-is\n * - If no extension, add .md\n * - Lowercase, forward slashes\n */\n private normalizeWikiLink(target: string): string {\n let normalized = target.toLowerCase().replace(/\\\\/g, '/');\n\n // Add .md if no file extension present\n // File extension = dot followed by 1-4 alphanumeric chars at end\n if (!this.hasFileExtension(normalized)) {\n normalized += '.md';\n }\n\n return normalized;\n }\n\n private hasFileExtension(path: string): boolean {\n // Match common file extensions: .md, .txt, .png, .json, etc.\n // Extension must contain at least one letter (to exclude .2024, .123, etc.)\n const match = path.match(/\\.([a-z0-9]{1,4})$/i);\n if (!match?.[1]) return false;\n // Require at least one letter in the extension\n return /[a-z]/i.test(match[1]);\n }\n\n private validatePathWithinSource(id: string): void {\n const resolvedPath = resolve(this.sourceRoot, id);\n const resolvedRoot = resolve(this.sourceRoot);\n\n if (!resolvedPath.startsWith(resolvedRoot + '/')) {\n throw new Error(`Path traversal detected: ${id} resolves outside source root`);\n }\n }\n}\n\nexport { Cache } from './cache.js';\nexport {\n parseMarkdown,\n extractWikiLinks,\n normalizeId,\n titleFromPath,\n serializeToMarkdown,\n} from './parser.js';\n","import Database from 'better-sqlite3';\nimport { join } from 'node:path';\nimport { mkdirSync } from 'node:fs';\nimport stringSimilarity from 'string-similarity';\nimport type { Node, SourceRef } from '../../types/node.js';\nimport type {\n TagMode,\n ListFilter,\n ListOptions,\n ListNodesResult,\n ResolveOptions,\n ResolveResult,\n} from '../../types/provider.js';\n\nexport interface EmbeddingRecord {\n model: string;\n vector: number[];\n}\n\nexport interface CentralityRecord {\n pagerank: number;\n inDegree: number;\n outDegree: number;\n computedAt: number;\n}\n\ninterface NodeRow {\n id: string;\n title: string;\n content: string;\n tags: string;\n outgoing_links: string;\n properties: string;\n source_type: string;\n source_path: string;\n source_modified: number;\n}\n\ninterface EmbeddingRow {\n node_id: string;\n model: string;\n vector: Buffer;\n}\n\ninterface CentralityRow {\n node_id: string;\n pagerank: number;\n in_degree: number;\n out_degree: number;\n computed_at: number;\n}\n\nexport class Cache {\n private db: Database.Database;\n\n constructor(cacheDir: string) {\n mkdirSync(cacheDir, { recursive: true });\n const dbPath = join(cacheDir, 'cache.db');\n this.db = new Database(dbPath);\n this.db.pragma('journal_mode = WAL');\n this.initSchema();\n }\n\n private initSchema(): void {\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS nodes (\n id TEXT PRIMARY KEY,\n title TEXT,\n content TEXT,\n tags TEXT,\n outgoing_links TEXT,\n properties TEXT,\n source_type TEXT,\n source_path TEXT,\n source_modified INTEGER\n );\n\n CREATE TABLE IF NOT EXISTS embeddings (\n node_id TEXT PRIMARY KEY,\n model TEXT,\n vector BLOB,\n FOREIGN KEY (node_id) REFERENCES nodes(id) ON DELETE CASCADE\n );\n\n CREATE TABLE IF NOT EXISTS centrality (\n node_id TEXT PRIMARY KEY,\n pagerank REAL,\n in_degree INTEGER,\n out_degree INTEGER,\n computed_at INTEGER,\n FOREIGN KEY (node_id) REFERENCES nodes(id) ON DELETE CASCADE\n );\n\n CREATE INDEX IF NOT EXISTS idx_nodes_source_path ON nodes(source_path);\n `);\n // Enable foreign key enforcement for cascade deletes\n this.db.pragma('foreign_keys = ON');\n }\n\n getTableNames(): string[] {\n const rows = this.db\n .prepare(\"SELECT name FROM sqlite_master WHERE type='table'\")\n .all() as Array<{ name: string }>;\n return rows.map((r) => r.name);\n }\n\n upsertNode(\n node: Node,\n sourceType: string,\n sourcePath: string,\n sourceModified: number\n ): void {\n const stmt = this.db.prepare(`\n INSERT INTO nodes (id, title, content, tags, outgoing_links, properties, source_type, source_path, source_modified)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT(id) DO UPDATE SET\n title = excluded.title,\n content = excluded.content,\n tags = excluded.tags,\n outgoing_links = excluded.outgoing_links,\n properties = excluded.properties,\n source_type = excluded.source_type,\n source_path = excluded.source_path,\n source_modified = excluded.source_modified\n `);\n\n stmt.run(\n node.id,\n node.title,\n node.content,\n JSON.stringify(node.tags),\n JSON.stringify(node.outgoingLinks),\n JSON.stringify(node.properties),\n sourceType,\n sourcePath,\n sourceModified\n );\n }\n\n getNode(id: string): Node | null {\n const row = this.db\n .prepare('SELECT * FROM nodes WHERE id = ?')\n .get(id) as NodeRow | undefined;\n\n if (!row) return null;\n return this.rowToNode(row);\n }\n\n getNodes(ids: string[]): Node[] {\n if (ids.length === 0) return [];\n\n // Fetch all nodes then order by input ids\n const placeholders = ids.map(() => '?').join(',');\n const rows = this.db\n .prepare(`SELECT * FROM nodes WHERE id IN (${placeholders})`)\n .all(...ids) as NodeRow[];\n\n const nodeMap = new Map<string, Node>();\n for (const row of rows) {\n nodeMap.set(row.id, this.rowToNode(row));\n }\n\n // Return in requested order\n const result: Node[] = [];\n for (const id of ids) {\n const node = nodeMap.get(id);\n if (node) result.push(node);\n }\n return result;\n }\n\n deleteNode(id: string): void {\n this.db.prepare('DELETE FROM nodes WHERE id = ?').run(id);\n }\n\n getAllNodes(): Node[] {\n const rows = this.db.prepare('SELECT * FROM nodes').all() as NodeRow[];\n return rows.map((row) => this.rowToNode(row));\n }\n\n searchByTags(tags: string[], mode: TagMode): Node[] {\n if (tags.length === 0) return [];\n\n const allNodes = this.getAllNodes();\n const lowerTags = tags.map((t) => t.toLowerCase());\n\n return allNodes.filter((node) => {\n const nodeTags = node.tags.map((t) => t.toLowerCase());\n if (mode === 'any') {\n return lowerTags.some((t) => nodeTags.includes(t));\n } else {\n return lowerTags.every((t) => nodeTags.includes(t));\n }\n });\n }\n\n getModifiedTime(sourcePath: string): number | null {\n const row = this.db\n .prepare('SELECT source_modified FROM nodes WHERE source_path = ?')\n .get(sourcePath) as { source_modified: number } | undefined;\n\n return row?.source_modified ?? null;\n }\n\n getNodeByPath(sourcePath: string): Node | null {\n const row = this.db\n .prepare('SELECT * FROM nodes WHERE source_path = ?')\n .get(sourcePath) as NodeRow | undefined;\n\n if (!row) return null;\n return this.rowToNode(row);\n }\n\n getAllTrackedPaths(): Set<string> {\n const rows = this.db\n .prepare('SELECT source_path FROM nodes')\n .all() as Array<{ source_path: string }>;\n\n return new Set(rows.map((r) => r.source_path));\n }\n\n resolveTitles(ids: string[]): Map<string, string> {\n if (ids.length === 0) return new Map();\n\n const placeholders = ids.map(() => '?').join(',');\n const rows = this.db\n .prepare(`SELECT id, title FROM nodes WHERE id IN (${placeholders})`)\n .all(...ids) as Array<{ id: string; title: string }>;\n\n const result = new Map<string, string>();\n for (const row of rows) {\n result.set(row.id, row.title);\n }\n return result;\n }\n\n nodesExist(ids: string[]): Map<string, boolean> {\n if (ids.length === 0) return new Map();\n\n const placeholders = ids.map(() => '?').join(',');\n const rows = this.db\n .prepare(`SELECT id FROM nodes WHERE id IN (${placeholders})`)\n .all(...ids) as Array<{ id: string }>;\n\n const existingIds = new Set(rows.map((r) => r.id));\n const result = new Map<string, boolean>();\n for (const id of ids) {\n result.set(id, existingIds.has(id));\n }\n return result;\n }\n\n listNodes(filter: ListFilter, options?: ListOptions): ListNodesResult {\n const limit = Math.min(options?.limit ?? 100, 1000);\n const offset = options?.offset ?? 0;\n\n // Build query dynamically based on filters\n const conditions: string[] = [];\n const params: unknown[] = [];\n\n if (filter.tag) {\n // Case-insensitive tag match - tags stored as JSON array\n conditions.push(\"EXISTS (SELECT 1 FROM json_each(tags) WHERE LOWER(json_each.value) = LOWER(?))\");\n params.push(filter.tag);\n }\n\n if (filter.path) {\n conditions.push(\"id LIKE ? || '%'\");\n params.push(filter.path);\n }\n\n const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';\n\n // Get total count of matching nodes (without limit/offset)\n const countQuery = `SELECT COUNT(*) as count FROM nodes ${whereClause}`;\n const countRow = this.db.prepare(countQuery).get(...params) as { count: number };\n const total = countRow.count;\n\n // Get paginated results\n const query = `SELECT id, title FROM nodes ${whereClause} LIMIT ? OFFSET ?`;\n const rows = this.db.prepare(query).all(...params, limit, offset) as Array<{ id: string; title: string }>;\n\n const nodes = rows.map((row) => ({ id: row.id, title: row.title }));\n return { nodes, total };\n }\n\n resolveNodes(names: string[], options?: ResolveOptions): ResolveResult[] {\n if (names.length === 0) return [];\n\n const strategy = options?.strategy ?? 'fuzzy';\n const threshold = options?.threshold ?? 0.7;\n\n // Build filter without undefined values\n const filter: ListFilter = {};\n if (options?.tag) filter.tag = options.tag;\n if (options?.path) filter.path = options.path;\n\n // Get candidate nodes (applying tag/path filters)\n const { nodes: candidates } = this.listNodes(filter, { limit: 1000 });\n\n if (candidates.length === 0) {\n return names.map((query) => ({ query, match: null, score: 0 }));\n }\n\n const candidateTitles = candidates.map((c) => c.title.toLowerCase());\n const titleToId = new Map<string, string>();\n for (const c of candidates) {\n titleToId.set(c.title.toLowerCase(), c.id);\n }\n\n return names.map((query): ResolveResult => {\n const queryLower = query.toLowerCase();\n\n if (strategy === 'exact') {\n // Exact case-insensitive title match\n const matchedId = titleToId.get(queryLower);\n if (matchedId) {\n return { query, match: matchedId, score: 1 };\n }\n return { query, match: null, score: 0 };\n }\n\n // Fuzzy strategy using string-similarity\n if (strategy === 'fuzzy') {\n const result = stringSimilarity.findBestMatch(queryLower, candidateTitles);\n const bestMatch = result.bestMatch;\n\n if (bestMatch.rating >= threshold) {\n // bestMatch.target is guaranteed to exist in titleToId since both come from candidates\n const matchedId = titleToId.get(bestMatch.target)!;\n return { query, match: matchedId, score: bestMatch.rating };\n }\n return { query, match: null, score: 0 };\n }\n\n // Semantic strategy - not supported at cache level, return no match\n // DocStore will handle semantic by using embedding provider\n return { query, match: null, score: 0 };\n });\n }\n\n updateOutgoingLinks(nodeId: string, links: string[]): void {\n this.db\n .prepare('UPDATE nodes SET outgoing_links = ? WHERE id = ?')\n .run(JSON.stringify(links), nodeId);\n }\n\n storeEmbedding(nodeId: string, vector: number[], model: string): void {\n const buffer = Buffer.from(new Float32Array(vector).buffer);\n this.db\n .prepare(\n `\n INSERT INTO embeddings (node_id, model, vector)\n VALUES (?, ?, ?)\n ON CONFLICT(node_id) DO UPDATE SET\n model = excluded.model,\n vector = excluded.vector\n `\n )\n .run(nodeId, model, buffer);\n }\n\n getEmbedding(nodeId: string): EmbeddingRecord | null {\n const row = this.db\n .prepare('SELECT model, vector FROM embeddings WHERE node_id = ?')\n .get(nodeId) as EmbeddingRow | undefined;\n\n if (!row) return null;\n\n const float32 = new Float32Array(\n row.vector.buffer,\n row.vector.byteOffset,\n row.vector.length / 4\n );\n return {\n model: row.model,\n vector: Array.from(float32),\n };\n }\n\n storeCentrality(\n nodeId: string,\n pagerank: number,\n inDegree: number,\n outDegree: number,\n computedAt: number\n ): void {\n this.db\n .prepare(\n `\n INSERT INTO centrality (node_id, pagerank, in_degree, out_degree, computed_at)\n VALUES (?, ?, ?, ?, ?)\n ON CONFLICT(node_id) DO UPDATE SET\n pagerank = excluded.pagerank,\n in_degree = excluded.in_degree,\n out_degree = excluded.out_degree,\n computed_at = excluded.computed_at\n `\n )\n .run(nodeId, pagerank, inDegree, outDegree, computedAt);\n }\n\n getCentrality(nodeId: string): CentralityRecord | null {\n const row = this.db\n .prepare('SELECT * FROM centrality WHERE node_id = ?')\n .get(nodeId) as CentralityRow | undefined;\n\n if (!row) return null;\n\n return {\n pagerank: row.pagerank,\n inDegree: row.in_degree,\n outDegree: row.out_degree,\n computedAt: row.computed_at,\n };\n }\n\n getStats(): { nodeCount: number; embeddingCount: number; edgeCount: number } {\n const nodeCount = this.db\n .prepare('SELECT COUNT(*) as count FROM nodes')\n .get() as { count: number };\n\n const embeddingCount = this.db\n .prepare('SELECT COUNT(*) as count FROM embeddings')\n .get() as { count: number };\n\n // Sum all in_degree values to get edge count\n const edgeSum = this.db\n .prepare('SELECT SUM(in_degree) as total FROM centrality')\n .get() as { total: number | null };\n\n return {\n nodeCount: nodeCount.count,\n embeddingCount: embeddingCount.count,\n edgeCount: edgeSum.total ?? 0,\n };\n }\n\n clear(): void {\n this.db.exec('DELETE FROM centrality');\n this.db.exec('DELETE FROM embeddings');\n this.db.exec('DELETE FROM nodes');\n }\n\n close(): void {\n this.db.close();\n }\n\n private rowToNode(row: NodeRow): Node {\n const sourceRef: SourceRef = {\n type: row.source_type as SourceRef['type'],\n path: row.source_path,\n lastModified: new Date(row.source_modified),\n };\n\n return {\n id: row.id,\n title: row.title,\n content: row.content,\n tags: JSON.parse(row.tags) as string[],\n outgoingLinks: JSON.parse(row.outgoing_links) as string[],\n properties: JSON.parse(row.properties) as Record<string, unknown>,\n sourceRef,\n };\n }\n}\n","import Database from 'better-sqlite3';\nimport type { Database as DatabaseType } from 'better-sqlite3';\nimport { join } from 'node:path';\nimport type { VectorProvider, VectorSearchResult } from '../../types/provider.js';\n\nexport class SqliteVectorProvider implements VectorProvider {\n private db: DatabaseType;\n private ownsDb: boolean;\n\n constructor(pathOrDb: string | DatabaseType) {\n if (typeof pathOrDb === 'string') {\n this.db = new Database(join(pathOrDb, 'vectors.db'));\n this.ownsDb = true;\n } else {\n this.db = pathOrDb;\n this.ownsDb = false;\n }\n this.init();\n }\n\n private init(): void {\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS vectors (\n id TEXT PRIMARY KEY,\n model TEXT NOT NULL,\n vector BLOB NOT NULL\n )\n `);\n }\n\n async store(id: string, vector: number[], model: string): Promise<void> {\n if (vector.length === 0) {\n throw new Error('Cannot store empty vector');\n }\n for (const v of vector) {\n if (!Number.isFinite(v)) {\n throw new Error(`Invalid vector value: ${v}`);\n }\n }\n\n // Validate dimension consistency (exclude self for overwrites)\n const existing = this.db\n .prepare('SELECT LENGTH(vector) / 4 as dim FROM vectors WHERE id != ? LIMIT 1')\n .get(id) as { dim: number } | undefined;\n\n if (existing && existing.dim !== vector.length) {\n throw new Error(\n `Dimension mismatch: cannot store ${vector.length}-dim vector, existing vectors have ${existing.dim} dimensions`\n );\n }\n\n const blob = Buffer.from(new Float32Array(vector).buffer);\n this.db\n .prepare(\n `INSERT OR REPLACE INTO vectors (id, model, vector) VALUES (?, ?, ?)`\n )\n .run(id, model, blob);\n }\n\n async search(vector: number[], limit: number): Promise<VectorSearchResult[]> {\n if (vector.length === 0) {\n throw new Error('Cannot search with empty vector');\n }\n for (const v of vector) {\n if (!Number.isFinite(v)) {\n throw new Error(`Invalid vector value: ${v}`);\n }\n }\n if (limit <= 0) {\n return [];\n }\n\n const rows = this.db\n .prepare('SELECT id, vector FROM vectors')\n .all() as Array<{ id: string; vector: Buffer }>;\n\n if (rows.length === 0) {\n return [];\n }\n\n // Check dimension mismatch against first stored vector\n const firstStoredDim = rows[0]!.vector.byteLength / 4;\n if (vector.length !== firstStoredDim) {\n throw new Error(\n `Dimension mismatch: query has ${vector.length} dimensions, stored vectors have ${firstStoredDim}`\n );\n }\n\n const queryVec = new Float32Array(vector);\n const results: VectorSearchResult[] = [];\n\n for (const row of rows) {\n const storedVec = new Float32Array(\n row.vector.buffer,\n row.vector.byteOffset,\n row.vector.byteLength / 4\n );\n const distance = cosineDistance(queryVec, storedVec);\n results.push({ id: row.id, distance });\n }\n\n results.sort((a, b) => a.distance - b.distance);\n return results.slice(0, limit);\n }\n\n async delete(id: string): Promise<void> {\n this.db.prepare('DELETE FROM vectors WHERE id = ?').run(id);\n }\n\n async getModel(id: string): Promise<string | null> {\n const row = this.db\n .prepare('SELECT model FROM vectors WHERE id = ?')\n .get(id) as { model: string } | undefined;\n return row?.model ?? null;\n }\n\n hasEmbedding(id: string): boolean {\n const row = this.db\n .prepare('SELECT 1 FROM vectors WHERE id = ?')\n .get(id);\n return row !== undefined;\n }\n\n /** For testing: get table names */\n getTableNames(): string[] {\n const rows = this.db\n .prepare(\"SELECT name FROM sqlite_master WHERE type='table'\")\n .all() as Array<{ name: string }>;\n return rows.map((r) => r.name);\n }\n\n /** For testing: get vector blob size */\n getVectorBlobSize(id: string): number | null {\n const row = this.db\n .prepare('SELECT LENGTH(vector) as size FROM vectors WHERE id = ?')\n .get(id) as { size: number } | undefined;\n return row?.size ?? null;\n }\n\n /** Get total number of stored embeddings */\n getEmbeddingCount(): number {\n const row = this.db\n .prepare('SELECT COUNT(*) as count FROM vectors')\n .get() as { count: number };\n return row.count;\n }\n\n close(): void {\n if (this.ownsDb) {\n this.db.close();\n }\n }\n}\n\nfunction cosineDistance(a: Float32Array, b: Float32Array): number {\n let dotProduct = 0;\n let magnitudeA = 0;\n let magnitudeB = 0;\n\n for (let i = 0; i < a.length; i++) {\n dotProduct += a[i]! * b[i]!;\n magnitudeA += a[i]! * a[i]!;\n magnitudeB += b[i]! * b[i]!;\n }\n\n magnitudeA = Math.sqrt(magnitudeA);\n magnitudeB = Math.sqrt(magnitudeB);\n\n if (magnitudeA === 0 || magnitudeB === 0) {\n return 1; // No similarity for zero vectors\n }\n\n const similarity = dotProduct / (magnitudeA * magnitudeB);\n return 1 - similarity;\n}\n","import matter from 'gray-matter';\n\nexport interface ParsedMarkdown {\n title: string | undefined;\n tags: string[];\n properties: Record<string, unknown>;\n content: string;\n}\n\n/**\n * Parse markdown with YAML frontmatter.\n * Handles missing/malformed frontmatter gracefully.\n */\nexport function parseMarkdown(raw: string): ParsedMarkdown {\n let parsed: matter.GrayMatterFile<string>;\n try {\n parsed = matter(raw);\n } catch {\n // Malformed frontmatter - return content as-is\n return {\n title: undefined,\n tags: [],\n properties: {},\n content: raw,\n };\n }\n\n const data = parsed.data as Record<string, unknown>;\n\n // Extract title\n const title = typeof data['title'] === 'string' ? data['title'] : undefined;\n\n // Extract tags - must be an array of strings\n let tags: string[] = [];\n if (Array.isArray(data['tags'])) {\n tags = data['tags'].filter((t): t is string => typeof t === 'string');\n }\n\n // Extract other properties (excluding title and tags)\n const properties: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(data)) {\n if (key !== 'title' && key !== 'tags') {\n properties[key] = value;\n }\n }\n\n return {\n title,\n tags,\n properties,\n content: parsed.content.trim(),\n };\n}\n\n/**\n * Extract wiki-link targets from markdown content.\n * Ignores links inside code blocks and inline code.\n * Deduplicates results.\n */\nexport function extractWikiLinks(content: string): string[] {\n // Remove code blocks first\n const withoutCodeBlocks = content.replace(/```[\\s\\S]*?```/g, '');\n\n // Remove inline code\n const withoutInlineCode = withoutCodeBlocks.replace(/`[^`]+`/g, '');\n\n // Match wiki links: [[target]] or [[target|display]]\n const linkRegex = /\\[\\[([^\\]|]+)(?:\\|[^\\]]+)?\\]\\]/g;\n const seen = new Set<string>();\n const links: string[] = [];\n\n let match;\n while ((match = linkRegex.exec(withoutInlineCode)) !== null) {\n const target = match[1]?.trim();\n if (target && !seen.has(target)) {\n seen.add(target);\n links.push(target);\n }\n }\n\n return links;\n}\n\n/**\n * Normalize a file path to a consistent ID format.\n * - Lowercased\n * - Forward slashes only\n * - Preserves extension\n */\nexport function normalizeId(path: string): string {\n return path.toLowerCase().replace(/\\\\/g, '/');\n}\n\n/**\n * Derive a human-readable title from a file path.\n * - Removes directory prefix\n * - Removes extension\n * - Replaces hyphens/underscores with spaces\n * - Title-cases words\n */\nexport function titleFromPath(path: string): string {\n // Get filename without directory\n const parts = path.split(/[/\\\\]/);\n // parts is always non-empty (even '' splits to [''])\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const filename = parts.at(-1)!;\n\n // Remove extension\n const withoutExt = filename.replace(/\\.[^.]+$/, '');\n\n // Replace hyphens and underscores with spaces, collapse multiples\n const spaced = withoutExt.replace(/[-_]+/g, ' ').toLowerCase();\n\n // Title-case each word\n return spaced\n .split(' ')\n .filter((w) => w.length > 0)\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(' ');\n}\n\n/**\n * Serialize parsed markdown back to a string with YAML frontmatter.\n * Omits frontmatter if no metadata is present.\n */\nexport function serializeToMarkdown(parsed: ParsedMarkdown): string {\n const hasFrontmatter =\n parsed.title !== undefined ||\n parsed.tags.length > 0 ||\n Object.keys(parsed.properties).length > 0;\n\n if (!hasFrontmatter) {\n return parsed.content;\n }\n\n // Build frontmatter object\n const frontmatter: Record<string, unknown> = {};\n\n if (parsed.title !== undefined) {\n frontmatter['title'] = parsed.title;\n }\n\n if (parsed.tags.length > 0) {\n frontmatter['tags'] = parsed.tags;\n }\n\n // Add other properties\n for (const [key, value] of Object.entries(parsed.properties)) {\n frontmatter[key] = value;\n }\n\n // Use gray-matter to stringify\n return matter.stringify(parsed.content, frontmatter);\n}\n","import { DirectedGraph } from 'graphology';\nimport type { Node } from '../types/node.js';\n\n/**\n * Build a directed graph from an array of nodes.\n * Edges are derived from each node's outgoingLinks.\n * Links to non-existent nodes are ignored.\n */\nexport function buildGraph(nodes: Node[]): DirectedGraph {\n const graph = new DirectedGraph();\n\n // First pass: add all nodes\n const nodeIds = new Set<string>();\n for (const node of nodes) {\n graph.addNode(node.id);\n nodeIds.add(node.id);\n }\n\n // Second pass: add edges (only to existing nodes)\n for (const node of nodes) {\n const seen = new Set<string>();\n for (const target of node.outgoingLinks) {\n // Skip if target doesn't exist or we've already added this edge\n if (!nodeIds.has(target) || seen.has(target)) {\n continue;\n }\n seen.add(target);\n graph.addDirectedEdge(node.id, target);\n }\n }\n\n return graph;\n}\n","import type { DirectedGraph } from 'graphology';\nimport { bidirectional } from 'graphology-shortest-path';\nimport type {\n NeighborOptions,\n Metric,\n CentralityMetrics,\n} from '../types/provider.js';\n\n/**\n * Get neighbor IDs based on direction.\n * Returns empty array if node doesn't exist.\n */\nexport function getNeighborIds(\n graph: DirectedGraph,\n id: string,\n options: NeighborOptions\n): string[] {\n if (!graph.hasNode(id)) {\n return [];\n }\n\n let neighbors: string[];\n\n switch (options.direction) {\n case 'in':\n neighbors = graph.inNeighbors(id);\n break;\n case 'out':\n neighbors = graph.outNeighbors(id);\n break;\n case 'both':\n neighbors = graph.neighbors(id);\n break;\n }\n\n if (options.limit !== undefined) {\n if (options.limit <= 0) {\n return [];\n }\n if (options.limit < neighbors.length) {\n return neighbors.slice(0, options.limit);\n }\n }\n\n return neighbors;\n}\n\n/**\n * Find shortest path between two nodes.\n * Returns array of node IDs or null if no path exists.\n */\nexport function findPath(\n graph: DirectedGraph,\n source: string,\n target: string\n): string[] | null {\n if (!graph.hasNode(source) || !graph.hasNode(target)) {\n return null;\n }\n\n if (source === target) {\n return [source];\n }\n\n const path = bidirectional(graph, source, target);\n return path;\n}\n\n/**\n * Get top nodes by centrality metric.\n * Returns array of [id, score] tuples sorted descending.\n */\nexport function getHubs(\n graph: DirectedGraph,\n metric: Metric,\n limit: number\n): Array<[string, number]> {\n if (limit <= 0) {\n return [];\n }\n\n const scores: Array<[string, number]> = [];\n\n graph.forEachNode((id) => {\n let score: number;\n switch (metric) {\n case 'in_degree':\n score = graph.inDegree(id);\n break;\n case 'out_degree':\n score = graph.outDegree(id);\n break;\n case 'pagerank':\n // PageRank is post-MVP, use in_degree as fallback\n score = graph.inDegree(id);\n break;\n }\n scores.push([id, score]);\n });\n\n scores.sort((a, b) => b[1] - a[1]);\n return scores.slice(0, limit);\n}\n\n/**\n * Compute centrality metrics for all nodes.\n * For MVP, computes in_degree and out_degree only.\n */\nexport function computeCentrality(\n graph: DirectedGraph\n): Map<string, CentralityMetrics> {\n const result = new Map<string, CentralityMetrics>();\n\n graph.forEachNode((id) => {\n result.set(id, {\n inDegree: graph.inDegree(id),\n outDegree: graph.outDegree(id),\n });\n });\n\n return result;\n}\n","import { pipeline, type FeatureExtractionPipeline } from '@xenova/transformers';\nimport type { EmbeddingProvider } from '../../types/provider.js';\n\nconst DEFAULT_MODEL = 'Xenova/all-MiniLM-L6-v2';\nconst DEFAULT_DIMENSIONS = 384;\n\nexport class TransformersEmbeddingProvider implements EmbeddingProvider {\n private model: string;\n private dims: number;\n private pipe: FeatureExtractionPipeline | null = null;\n\n constructor(model = DEFAULT_MODEL, dimensions = DEFAULT_DIMENSIONS) {\n this.model = model;\n this.dims = dimensions;\n }\n\n private async getPipeline(): Promise<FeatureExtractionPipeline> {\n if (!this.pipe) {\n this.pipe = await pipeline('feature-extraction', this.model);\n }\n return this.pipe;\n }\n\n async embed(text: string): Promise<number[]> {\n const pipe = await this.getPipeline();\n const output = await pipe(text, { pooling: 'mean', normalize: true });\n return Array.from(output.data as Float32Array);\n }\n\n async embedBatch(texts: string[]): Promise<number[][]> {\n if (texts.length === 0) {\n return [];\n }\n return Promise.all(texts.map((t) => this.embed(t)));\n }\n\n dimensions(): number {\n return this.dims;\n }\n\n modelId(): string {\n return this.model;\n }\n}\n","import type { Node, NodeWithContext } from '../types/node.js';\nimport type {\n GraphCore,\n SearchOptions,\n} from '../types/graphcore.js';\nimport type {\n StoreProvider,\n EmbeddingProvider,\n Metric,\n TagMode,\n NeighborOptions,\n ListFilter,\n ListOptions,\n ListNodesResult,\n ResolveOptions,\n ResolveResult,\n} from '../types/provider.js';\nimport type { RouxConfig } from '../types/config.js';\nimport { DocStore } from '../providers/docstore/index.js';\nimport { TransformersEmbeddingProvider } from '../providers/embedding/transformers.js';\n\nexport class GraphCoreImpl implements GraphCore {\n private store: StoreProvider | null = null;\n private embedding: EmbeddingProvider | null = null;\n\n registerStore(provider: StoreProvider): void {\n if (!provider) {\n throw new Error('Store provider is required');\n }\n this.store = provider;\n }\n\n registerEmbedding(provider: EmbeddingProvider): void {\n if (!provider) {\n throw new Error('Embedding provider is required');\n }\n this.embedding = provider;\n }\n\n private requireStore(): StoreProvider {\n if (!this.store) {\n throw new Error('StoreProvider not registered');\n }\n return this.store;\n }\n\n private requireEmbedding(): EmbeddingProvider {\n if (!this.embedding) {\n throw new Error('EmbeddingProvider not registered');\n }\n return this.embedding;\n }\n\n async search(query: string, options?: SearchOptions): Promise<Node[]> {\n const store = this.requireStore();\n const embedding = this.requireEmbedding();\n\n const limit = options?.limit ?? 10;\n const vector = await embedding.embed(query);\n const results = await store.searchByVector(vector, limit);\n\n // Results are already sorted by distance ascending\n const ids = results.map((r) => r.id);\n return store.getNodes(ids);\n }\n\n async getNode(id: string, depth?: number): Promise<NodeWithContext | null> {\n const store = this.requireStore();\n const node = await store.getNode(id);\n\n if (!node) {\n return null;\n }\n\n if (!depth || depth === 0) {\n return node;\n }\n\n // Fetch neighbors for context\n const [incomingNeighbors, outgoingNeighbors] = await Promise.all([\n store.getNeighbors(id, { direction: 'in' }),\n store.getNeighbors(id, { direction: 'out' }),\n ]);\n\n // Deduplicate neighbors (same node could be both incoming and outgoing)\n const neighborMap = new Map<string, Node>();\n for (const n of [...incomingNeighbors, ...outgoingNeighbors]) {\n neighborMap.set(n.id, n);\n }\n\n const result: NodeWithContext = {\n ...node,\n neighbors: Array.from(neighborMap.values()),\n incomingCount: incomingNeighbors.length,\n outgoingCount: outgoingNeighbors.length,\n };\n\n return result;\n }\n\n async createNode(partial: Partial<Node>): Promise<Node> {\n const store = this.requireStore();\n\n if (!partial.id || partial.id.trim() === '') {\n throw new Error('Node id is required and cannot be empty');\n }\n if (!partial.title) {\n throw new Error('Node title is required');\n }\n\n const node: Node = {\n id: partial.id,\n title: partial.title,\n content: partial.content ?? '',\n tags: partial.tags ?? [],\n outgoingLinks: partial.outgoingLinks ?? [],\n properties: partial.properties ?? {},\n ...(partial.sourceRef && { sourceRef: partial.sourceRef }),\n };\n\n await store.createNode(node);\n return (await store.getNode(node.id)) ?? node;\n }\n\n async updateNode(id: string, updates: Partial<Node>): Promise<Node> {\n const store = this.requireStore();\n await store.updateNode(id, updates);\n const updated = await store.getNode(id);\n if (!updated) {\n throw new Error(`Node not found after update: ${id}`);\n }\n return updated;\n }\n\n async deleteNode(id: string): Promise<boolean> {\n const store = this.requireStore();\n try {\n await store.deleteNode(id);\n return true;\n } catch (err) {\n // Only swallow \"not found\" errors - propagate everything else\n if (err instanceof Error && /not found/i.test(err.message)) {\n return false;\n }\n throw err;\n }\n }\n\n async getNeighbors(id: string, options: NeighborOptions): Promise<Node[]> {\n const store = this.requireStore();\n return store.getNeighbors(id, options);\n }\n\n async findPath(source: string, target: string): Promise<string[] | null> {\n const store = this.requireStore();\n return store.findPath(source, target);\n }\n\n async getHubs(\n metric: Metric,\n limit: number\n ): Promise<Array<[string, number]>> {\n const store = this.requireStore();\n return store.getHubs(metric, limit);\n }\n\n async searchByTags(\n tags: string[],\n mode: TagMode,\n limit?: number\n ): Promise<Node[]> {\n const store = this.requireStore();\n const results = await store.searchByTags(tags, mode);\n if (limit !== undefined) {\n return results.slice(0, limit);\n }\n return results;\n }\n\n async getRandomNode(tags?: string[]): Promise<Node | null> {\n const store = this.requireStore();\n return store.getRandomNode(tags);\n }\n\n async listNodes(\n filter: ListFilter,\n options?: ListOptions\n ): Promise<ListNodesResult> {\n return this.requireStore().listNodes(filter, options);\n }\n\n async resolveNodes(\n names: string[],\n options?: ResolveOptions\n ): Promise<ResolveResult[]> {\n const store = this.requireStore();\n const strategy = options?.strategy ?? 'fuzzy';\n\n // Semantic strategy requires embedding provider\n if (strategy === 'semantic') {\n if (!this.embedding) {\n throw new Error('Semantic resolution requires EmbeddingProvider');\n }\n\n // Build filter without undefined values\n const filter: ListFilter = {};\n if (options?.tag) filter.tag = options.tag;\n if (options?.path) filter.path = options.path;\n\n // Get candidates from store with filters\n const { nodes: candidates } = await store.listNodes(filter, { limit: 1000 });\n\n if (candidates.length === 0 || names.length === 0) {\n return names.map((query) => ({ query, match: null, score: 0 }));\n }\n\n const threshold = options?.threshold ?? 0.7;\n\n // Embed all queries in batch\n const queryVectors = await this.embedding.embedBatch(names);\n\n // Embed all candidate titles in batch\n const candidateTitles = candidates.map((c) => c.title);\n const candidateVectors = await this.embedding.embedBatch(candidateTitles);\n\n // Validate dimensions match\n if (queryVectors.length > 0 && candidateVectors.length > 0) {\n const queryDim = queryVectors[0]!.length;\n const candidateDim = candidateVectors[0]!.length;\n if (queryDim !== candidateDim) {\n throw new Error(\n `Embedding dimension mismatch: query=${queryDim}, candidate=${candidateDim}`\n );\n }\n }\n\n // For each query, find best matching candidate by cosine similarity\n return names.map((query, qIdx): ResolveResult => {\n const queryVector = queryVectors[qIdx]!;\n let bestScore = 0;\n let bestMatch: string | null = null;\n\n for (let cIdx = 0; cIdx < candidates.length; cIdx++) {\n const similarity = this.cosineSimilarity(queryVector, candidateVectors[cIdx]!);\n if (similarity > bestScore) {\n bestScore = similarity;\n bestMatch = candidates[cIdx]!.id;\n }\n }\n\n if (bestScore >= threshold) {\n return { query, match: bestMatch, score: bestScore };\n }\n return { query, match: null, score: 0 };\n });\n }\n\n // Exact and fuzzy delegate to store\n return store.resolveNodes(names, options);\n }\n\n private cosineSimilarity(a: number[], b: number[]): number {\n let dotProduct = 0;\n let normA = 0;\n let normB = 0;\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 if (normA === 0 || normB === 0) return 0;\n return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));\n }\n\n static fromConfig(config: RouxConfig): GraphCoreImpl {\n if (!config.providers?.store) {\n throw new Error('StoreProvider configuration is required');\n }\n\n const core = new GraphCoreImpl();\n\n // Create store based on config\n if (config.providers.store.type === 'docstore') {\n const sourcePath = config.source?.path ?? '.';\n const cachePath = config.cache?.path ?? '.roux';\n const store = new DocStore(sourcePath, cachePath);\n core.registerStore(store);\n } else {\n throw new Error(\n `Unsupported store provider type: ${config.providers.store.type}. Supported: docstore`\n );\n }\n\n // Create embedding provider (defaults to local transformers)\n const embeddingConfig = config.providers.embedding;\n if (!embeddingConfig || embeddingConfig.type === 'local') {\n const model = embeddingConfig?.model;\n const embedding = new TransformersEmbeddingProvider(model);\n core.registerEmbedding(embedding);\n } else {\n throw new Error(\n `Unsupported embedding provider type: ${embeddingConfig.type}. Supported: local`\n );\n }\n\n return core;\n }\n}\n","// Roux - Graph Programming Interface\n\nexport const VERSION = '0.1.0';\n\n// Re-export all types\nexport * from './types/index.js';\n\n// Core\nexport { GraphCoreImpl } from './core/graphcore.js';\n\n// Providers\nexport { DocStore } from './providers/docstore/index.js';\nexport { TransformersEmbeddingProvider } from './providers/embedding/index.js';\nexport { SqliteVectorProvider } from './providers/vector/index.js';\n"],"mappings":"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","names":["join","stringSimilarity","Database","join","join","resolve"]}
package/package.json ADDED
@@ -0,0 +1,67 @@
1
+ {
2
+ "name": "@gettymade/roux",
3
+ "version": "0.1.0",
4
+ "description": "Graph Programming Interface for knowledge bases",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "bin": {
9
+ "roux": "./dist/cli/index.js"
10
+ },
11
+ "files": [
12
+ "dist"
13
+ ],
14
+ "scripts": {
15
+ "build": "tsup",
16
+ "dev": "tsup --watch",
17
+ "test": "vitest run",
18
+ "test:watch": "vitest",
19
+ "test:coverage": "vitest run --coverage",
20
+ "lint": "eslint src tests",
21
+ "lint:fix": "eslint src tests --fix",
22
+ "format": "prettier --write .",
23
+ "format:check": "prettier --check .",
24
+ "typecheck": "tsc --noEmit"
25
+ },
26
+ "keywords": [
27
+ "graph",
28
+ "knowledge-base",
29
+ "mcp",
30
+ "obsidian",
31
+ "semantic-search"
32
+ ],
33
+ "author": "",
34
+ "license": "MIT",
35
+ "engines": {
36
+ "node": ">=20"
37
+ },
38
+ "devDependencies": {
39
+ "@types/better-sqlite3": "^7.6.13",
40
+ "@types/chokidar": "^1.7.5",
41
+ "@types/node": "^20.17.0",
42
+ "@types/string-similarity": "^4.0.2",
43
+ "@typescript-eslint/eslint-plugin": "^8.0.0",
44
+ "@typescript-eslint/parser": "^8.0.0",
45
+ "@vitest/coverage-v8": "^2.0.0",
46
+ "eslint": "^9.0.0",
47
+ "eslint-config-prettier": "^9.0.0",
48
+ "prettier": "^3.0.0",
49
+ "string-similarity": "^4.0.4",
50
+ "tsup": "^8.0.0",
51
+ "typescript": "^5.6.0",
52
+ "vitest": "^2.0.0"
53
+ },
54
+ "dependencies": {
55
+ "@modelcontextprotocol/sdk": "^1.25.3",
56
+ "@xenova/transformers": "^2.17.2",
57
+ "better-sqlite3": "^12.6.2",
58
+ "chokidar": "^5.0.0",
59
+ "commander": "^14.0.2",
60
+ "graphology": "^0.26.0",
61
+ "graphology-shortest-path": "^2.1.0",
62
+ "graphology-types": "^0.24.8",
63
+ "gray-matter": "^4.0.3",
64
+ "roux": "github:alexgetty/roux",
65
+ "yaml": "^2.8.2"
66
+ }
67
+ }