remem-mcp 0.7.0 → 0.7.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +79 -218
- package/dist/{chunk-OYUNKUZK.js → chunk-4WCDAEPP.js} +788 -11
- package/dist/chunk-4WCDAEPP.js.map +1 -0
- package/dist/{chunk-TGLOMFIE.js → chunk-ITMR6THY.js} +47 -7
- package/dist/chunk-ITMR6THY.js.map +1 -0
- package/dist/{chunk-ZXI67YIV.js → chunk-YU7WBJU5.js} +15 -3
- package/dist/{chunk-ZXI67YIV.js.map → chunk-YU7WBJU5.js.map} +1 -1
- package/dist/{engine-3JUSB3RK.js → engine-S47HHGAO.js} +2 -2
- package/dist/index.js +347 -39
- package/dist/index.js.map +1 -1
- package/dist/{resolver-YIFWRNMS.js → resolver-UHU4MBQX.js} +50 -15
- package/dist/resolver-UHU4MBQX.js.map +1 -0
- package/dist/sdk.js +3 -3
- package/dist/{server-SUKPVQWL.js → server-5PWQTRGZ.js} +2 -2
- package/dist/storage/schema.sql +63 -2
- package/package.json +1 -1
- package/scripts/verify-codegraph-stats.mjs +122 -0
- package/skills/remem-mcp/SKILL.md +11 -3
- package/dist/chunk-OYUNKUZK.js.map +0 -1
- package/dist/chunk-TGLOMFIE.js.map +0 -1
- package/dist/resolver-YIFWRNMS.js.map +0 -1
- /package/dist/{engine-3JUSB3RK.js.map → engine-S47HHGAO.js.map} +0 -0
- /package/dist/{server-SUKPVQWL.js.map → server-5PWQTRGZ.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/sdk.ts","../src/security/redactor.ts","../src/wiki/engine.ts"],"sourcesContent":["/**\n * Programmatic API for remem-mcp.\n * Use this to embed memory directly in your application without MCP.\n *\n * @example\n * ```ts\n * import { Memory } from \"remem-mcp\";\n *\n * const memory = new Memory();\n * await memory.capture(\"We chose SQLite for storage.\", \"decision\", [\"arch\"]);\n * const results = await memory.recall(\"storage decision\");\n * ```\n */\n\nimport { createHash } from \"node:crypto\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { LocalEmbedder } from \"./embedding/local.js\";\nimport { redact } from \"./security/redactor.js\";\nimport { SQLiteBackend, stripQueryProperNouns } from \"./storage/sqlite.js\";\nimport type {\n CaptureEntry,\n CaptureType,\n DeleteFilter,\n DeleteResult,\n SearchFilters,\n SearchMode,\n SearchResult,\n} from \"./storage/types.js\";\nimport { generateId } from \"./utils/ulid.js\";\n\n/**\n * Auto-classify content as global (cross-project) or project-specific.\n * Generic rules/conventions/learnings → global; content with file paths,\n * line numbers, project names, or specific identifiers → project.\n */\nexport function classifyGlobalContent(content: string, type: CaptureType): boolean {\n if (type !== \"learning\" && type !== \"decision\" && type !== \"task\") return false;\n\n // Project-specific signals → NOT global\n const projectSignals = [\n /\\b\\/[a-z]/i,\n /\\b\\w+\\/\\w+\\.\\w{1,5}\\b/,\n /line\\s*\\d+/i,\n /\\b\\d{4,}\\b/,\n /\\bcommit\\s+[0-9a-f]{7,}/i,\n /\\bsrc\\//,\n /\\bdist\\//,\n /\\btests?\\//,\n ];\n for (const sig of projectSignals) {\n if (sig.test(content)) return false;\n }\n\n const lower = content.toLowerCase();\n const globalSignals = [\n /\\balways\\s+/i,\n /\\bnever\\s+/i,\n /\\brule\\b/i,\n /\\bconvention\\b/i,\n /\\bpattern\\b/i,\n /\\bprefer\\b/i,\n /\\bavoid\\b/i,\n /\\bshould\\b/i,\n /\\bbest\\s+practice\\b/i,\n ];\n let score = 0;\n for (const sig of globalSignals) {\n if (sig.test(lower)) score++;\n }\n\n if (content.length < 300 && score >= 1) return true;\n if (content.length < 150 && type === \"learning\") return true;\n return false;\n}\n\nexport type {\n CaptureEntry,\n CaptureType,\n DeleteFilter,\n DeleteResult,\n SearchFilters,\n SearchMode,\n SearchResult,\n};\nexport { LocalEmbedder, SQLiteBackend };\n\n/** High-level memory API. */\nexport class Memory {\n private storage: SQLiteBackend;\n private embedder: LocalEmbedder;\n private sessionKey: string;\n private globalKey: string | null;\n private redactSecrets: boolean;\n\n constructor(opts?: {\n dbPath?: string;\n sessionKey?: string;\n globalSessionKey?: string;\n redactSecrets?: boolean;\n }) {\n const dbPath = opts?.dbPath ?? join(homedir(), \".local\", \"share\", \"remem-mcp\", \"memory.db\");\n this.storage = new SQLiteBackend(dbPath);\n this.embedder = new LocalEmbedder();\n this.sessionKey =\n opts?.sessionKey ??\n process.env.REMEM_SESSION_KEY ??\n createHash(\"sha256\").update(process.cwd()).digest(\"hex\").slice(0, 16);\n this.globalKey = opts?.globalSessionKey ?? process.env.REMEM_GLOBAL_SESSION_KEY ?? null;\n this.redactSecrets = opts?.redactSecrets ?? true;\n }\n\n /** Capture a memory entry. Returns the ID, or null if duplicate. */\n async capture(\n content: string,\n type: CaptureType,\n tags: string[] = [],\n opts?: { sessionKey?: string; autoGlobal?: boolean },\n ): Promise<string | null> {\n const { text: redactedContent } = this.redactSecrets ? redact(content) : { text: content };\n let sessionKey = opts?.sessionKey ?? this.sessionKey;\n\n // Auto-classify: route generic rules/learnings to global session\n if (opts?.autoGlobal && !opts?.sessionKey && this.globalKey && this.globalKey !== sessionKey) {\n if (classifyGlobalContent(content, type)) {\n sessionKey = this.globalKey;\n }\n }\n\n // Dedup check\n const contentHash = createHash(\"sha256\").update(redactedContent).digest(\"hex\");\n const existing = await this.storage.findByContentHash(contentHash, sessionKey);\n if (existing.length > 0) return null;\n\n const id = generateId();\n const entry: CaptureEntry = {\n id,\n sessionKey,\n agentId: \"sdk\",\n type,\n content: redactedContent,\n tags,\n createdAt: Date.now(),\n };\n\n await this.storage.put(entry);\n\n try {\n // v13: Contextual retrieval — prepend type + tags as preamble before embedding.\n // Content stays pristine for FTS; only the vector sees the enriched text.\n const contextualContent = this.buildContextualPreamble(type, tags) + redactedContent;\n const embedding = await this.embedder.embed(contextualContent);\n await this.storage.putVector(id, embedding);\n } catch {\n // Embedding is optional\n }\n\n return id;\n }\n\n /** Recall relevant memory. Searches project + global (if configured). */\n async recall(\n query: string,\n opts?: { limit?: number; mode?: SearchMode; sessionKey?: string },\n ): Promise<SearchResult[]> {\n const limit = Math.min(opts?.limit ?? 10, 50);\n const mode = opts?.mode ?? \"hybrid\";\n const sessionKey = opts?.sessionKey ?? this.sessionKey;\n\n let queryEmbedding: number[] | null = null;\n if (mode === \"hybrid\" || mode === \"vector\") {\n const stripped = stripQueryProperNouns(query);\n queryEmbedding = await this.embedder.embed(stripped || query);\n }\n\n // Global fallback: search project first, then global for remaining slots\n if (this.globalKey && !opts?.sessionKey && this.globalKey !== sessionKey) {\n const reservedGlobal = Math.min(3, limit);\n const projectLimit = limit - reservedGlobal;\n const projectResults = await this.storage.search(query, queryEmbedding, {\n sessionKey,\n limit: projectLimit,\n offset: 0,\n mode,\n });\n let globalResults: SearchResult[] = [];\n try {\n globalResults = await this.storage.search(query, queryEmbedding, {\n sessionKey: this.globalKey,\n limit: reservedGlobal,\n offset: 0,\n mode,\n });\n } catch {\n // Global search failure is non-fatal\n }\n const seen = new Set(projectResults.map((r) => r.entry.id));\n return [...projectResults, ...globalResults.filter((r) => !seen.has(r.entry.id))].slice(\n 0,\n limit,\n );\n }\n\n return this.storage.search(query, queryEmbedding, {\n sessionKey,\n limit,\n offset: 0,\n mode,\n });\n }\n\n /** Search with filters. Searches project + global (if configured). */\n async search(\n query: string,\n opts?: { mode?: SearchMode; filters?: SearchFilters; limit?: number; sessionKey?: string; explain?: boolean },\n ): Promise<SearchResult[]> {\n const limit = Math.min(opts?.limit ?? 20, 100);\n const mode = opts?.mode ?? \"hybrid\";\n const sessionKey = opts?.sessionKey ?? this.sessionKey;\n const explain = opts?.explain ?? false;\n\n let queryEmbedding: number[] | null = null;\n if (mode === \"hybrid\" || mode === \"vector\") {\n const stripped = stripQueryProperNouns(query);\n queryEmbedding = await this.embedder.embed(stripped || query);\n }\n\n // Global fallback\n if (this.globalKey && !opts?.sessionKey && this.globalKey !== sessionKey) {\n const reservedGlobal = Math.min(3, limit);\n const projectLimit = limit - reservedGlobal;\n const projectResults = await this.storage.search(query, queryEmbedding, {\n sessionKey,\n limit: projectLimit,\n offset: 0,\n mode,\n filters: opts?.filters,\n explain,\n });\n let globalResults: SearchResult[] = [];\n try {\n globalResults = await this.storage.search(query, queryEmbedding, {\n sessionKey: this.globalKey,\n limit: reservedGlobal,\n offset: 0,\n mode,\n filters: opts?.filters,\n explain,\n });\n } catch {\n // Global search failure is non-fatal\n }\n const seen = new Set(projectResults.map((r) => r.entry.id));\n return [...projectResults, ...globalResults.filter((r) => !seen.has(r.entry.id))].slice(\n 0,\n limit,\n );\n }\n\n return this.storage.search(query, queryEmbedding, {\n sessionKey,\n limit,\n offset: 0,\n mode,\n filters: opts?.filters,\n explain,\n });\n }\n\n /** Compute the embedding vector for a piece of text using the configured embedder. */\n async embed(text: string): Promise<number[]> {\n return this.embedder.embed(text);\n }\n\n /**\n * v13: Build a contextual preamble for embedding (Anthropic contextual retrieval technique).\n * Prepends type + tags to give the vector model more context about what the capture is.\n * The raw content stays pristine for FTS5 lexical search.\n */\n private buildContextualPreamble(type: string, tags: string[]): string {\n const parts: string[] = [];\n if (type && type !== \"conversation\") {\n parts.push(`[${type}]`);\n }\n if (tags && tags.length > 0) {\n parts.push(`tags: ${tags.join(\", \")}`);\n }\n return parts.length > 0 ? parts.join(\" \") + \". \" : \"\";\n }\n\n /** Delete a capture by ID. */\n async forget(id: string): Promise<DeleteResult> {\n return this.storage.delete(id);\n }\n\n /** Get a capture by ID. Returns null if not found or deleted. */\n async get(id: string): Promise<CaptureEntry | null> {\n return this.storage.get(id);\n }\n\n /** Run forget sweep to evict low-salience and TTL-expired captures. */\n async forgetSweep(opts?: { dryRun?: boolean; threshold?: number; maxAgeDays?: number }) {\n return this.storage.forgetSweep(opts ?? {});\n }\n\n /** Record feedback for a capture (v12). Adjusts salience multiplier. */\n async feedback(\n captureId: string,\n signal: \"helpful\" | \"not_helpful\" | \"stale\" | \"wrong\",\n reason?: string,\n ): Promise<void> {\n this.storage.recordFeedback(captureId, signal, reason, \"sdk\");\n }\n\n /** Get feedback signals for a capture (v12). */\n async getFeedback(captureId: string): Promise<{ signal: string; reason: string | null; created_at: number }[]> {\n return this.storage.getFeedback(captureId);\n }\n\n /** Query mutation log (v12). */\n async queryAudit(opts: { action?: string; captureId?: string; since?: number; limit?: number }) {\n return this.storage.queryAudit(opts);\n }\n\n /** Update an existing capture's content, tags, type, or trust state. */\n async update(\n id: string,\n opts: {\n content?: string;\n tags?: string[];\n type?: CaptureType;\n verified?: boolean;\n },\n ): Promise<boolean> {\n const existing = await this.storage.get(id);\n if (!existing) return false;\n\n const newContent = opts.content ?? existing.content;\n const newTags = opts.tags ?? existing.tags;\n const newType = opts.type ?? existing.type;\n const newTrust = opts.verified ? \"verified\" : (existing.trustState ?? \"candidate\");\n\n // Recompute content hash\n const contentHash = createHash(\"sha256\").update(newContent).digest(\"hex\");\n\n // Use raw SQL update (matches server.ts handleUpdate logic)\n const db = this.storage.getDatabase();\n db.prepare(\n \"UPDATE captures SET content = ?, tags = ?, type = ?, trust_state = ?, content_hash = ? WHERE id = ?\",\n ).run(newContent, JSON.stringify(newTags), newType, newTrust, contentHash, id);\n\n // Update FTS index\n const rowid = (\n db.prepare(\"SELECT rowid FROM captures WHERE id = ?\").get(id) as\n | { rowid?: number }\n | undefined\n )?.rowid;\n if (rowid) {\n db.prepare(\n \"INSERT INTO captures_fts(captures_fts, rowid, content, tags, type) VALUES('delete', ?, '', '', '')\",\n ).run(rowid);\n db.prepare(\n \"INSERT INTO captures_fts (rowid, id, content, tags, type) VALUES (?, ?, ?, ?, ?)\",\n ).run(rowid, id, newContent, JSON.stringify(newTags), newType);\n }\n\n // Re-embed if content changed\n if (opts.content && opts.content !== existing.content) {\n try {\n const embedding = await this.embedder.embed(newContent);\n await this.storage.putVector(id, embedding);\n } catch {\n // Embedding is optional\n }\n }\n\n return true;\n }\n\n /** Find and optionally merge duplicate captures by content similarity (Jaccard). */\n async consolidate(opts: { threshold?: number; confirm?: boolean; sessionKey?: string }): Promise<{\n groups: { ids: string[]; similarity: number; preview: string }[];\n merged: number;\n }> {\n const threshold = opts.threshold ?? 0.75;\n const confirm = opts.confirm ?? false;\n const sessionKey = opts.sessionKey ?? this.sessionKey;\n\n const db = this.storage.getDatabase();\n let sql = \"SELECT id, content, type, tags, created_at FROM captures WHERE deleted_at IS NULL\";\n const params: unknown[] = [];\n if (sessionKey !== \"all\") {\n sql += \" AND session_key = ?\";\n params.push(sessionKey);\n }\n sql += \" ORDER BY created_at DESC\";\n const rows = db.prepare(sql).all(...params) as {\n id: string;\n content: string;\n type: string;\n tags: string;\n created_at: number;\n }[];\n\n if (rows.length < 2) return { groups: [], merged: 0 };\n\n const groups: { ids: string[]; similarity: number; preview: string }[] = [];\n const seen = new Set<string>();\n\n for (let i = 0; i < rows.length; i++) {\n if (seen.has(rows[i].id)) continue;\n const words1 = new Set(rows[i].content.toLowerCase().split(/\\s+/));\n const group = [rows[i].id];\n\n for (let j = i + 1; j < rows.length; j++) {\n if (seen.has(rows[j].id)) continue;\n const words2 = new Set(rows[j].content.toLowerCase().split(/\\s+/));\n const intersection = [...words1].filter((w) => words2.has(w)).length;\n const union = new Set([...words1, ...words2]).size;\n const sim = union > 0 ? intersection / union : 0;\n if (sim >= threshold) {\n group.push(rows[j].id);\n seen.add(rows[j].id);\n }\n }\n\n if (group.length > 1) {\n seen.add(rows[i].id);\n groups.push({\n ids: group,\n similarity: threshold,\n preview: rows[i].content.slice(0, 80).replace(/\\n/g, \" \"),\n });\n }\n }\n\n if (!confirm || groups.length === 0) {\n return { groups, merged: 0 };\n }\n\n // Merge: keep oldest, soft-delete rest (transactional)\n let merged = 0;\n const softDelete = db.prepare(\"UPDATE captures SET deleted_at = ? WHERE id = ?\");\n const deleteVec = db.prepare(\"DELETE FROM captures_vec WHERE id = ?\");\n const deleteAtoms = db.prepare(\"DELETE FROM atoms WHERE capture_id = ?\");\n const mergeTx = db.transaction(() => {\n for (const g of groups) {\n const groupRows = g.ids\n .map((id) => rows.find((r) => r.id === id))\n .filter(Boolean)\n .sort((a, b) => a!.created_at - b!.created_at);\n const dups = groupRows.slice(1);\n for (const dup of dups) {\n softDelete.run(Date.now(), dup!.id);\n deleteVec.run(dup!.id);\n deleteAtoms.run(dup!.id);\n merged++;\n }\n }\n });\n mergeTx();\n\n return { groups, merged };\n }\n\n /** Create a handoff packet for the next agent session. */\n async handoff(opts: {\n task: string;\n status: \"in_progress\" | \"blocked\" | \"needs_review\" | \"done\" | \"assigned\";\n progress: string;\n decisions?: string[];\n files?: string[];\n nextSteps?: string[];\n }): Promise<string | null> {\n const lines: string[] = [];\n lines.push(`# Handoff: ${opts.task}`);\n lines.push(`Status: ${opts.status}`);\n lines.push(`Date: ${new Date().toISOString()}`);\n lines.push(\"\");\n lines.push(\"## Progress\");\n lines.push(opts.progress);\n lines.push(\"\");\n\n if (opts.decisions && opts.decisions.length > 0) {\n lines.push(\"## Decisions\");\n for (const d of opts.decisions) lines.push(`- ${d}`);\n lines.push(\"\");\n }\n if (opts.files && opts.files.length > 0) {\n lines.push(\"## Files\");\n for (const f of opts.files) lines.push(`- ${f}`);\n lines.push(\"\");\n }\n if (opts.nextSteps && opts.nextSteps.length > 0) {\n lines.push(\"## Next steps\");\n opts.nextSteps.forEach((s, i) => {\n lines.push(`${i + 1}. ${s}`);\n });\n lines.push(\"\");\n }\n\n const content = lines.join(\"\\n\");\n // Dedup: hash the structured data (excluding the timestamp)\n const dedupPayload = JSON.stringify({\n task: opts.task,\n status: opts.status,\n progress: opts.progress,\n decisions: opts.decisions ?? [],\n files: opts.files ?? [],\n nextSteps: opts.nextSteps ?? [],\n });\n const contentHash = createHash(\"sha256\").update(dedupPayload).digest(\"hex\");\n const existing = await this.storage.findByContentHash(contentHash, this.sessionKey);\n if (existing.length > 0) return null;\n\n const id = generateId();\n const entry: CaptureEntry = {\n id,\n sessionKey: this.sessionKey,\n agentId: \"sdk\",\n type: \"task\",\n content,\n tags: [\"handoff\", `status:${opts.status}`],\n createdAt: Date.now(),\n metadata: {\n handoff: true,\n task: opts.task,\n status: opts.status,\n progress: opts.progress,\n decisions: opts.decisions ?? [],\n files: opts.files ?? [],\n nextSteps: opts.nextSteps ?? [],\n },\n contentHash,\n };\n\n await this.storage.put(entry);\n\n try {\n const embedding = await this.embedder.embed(content);\n await this.storage.putVector(id, embedding);\n } catch {\n // Embedding is optional\n }\n\n return id;\n }\n\n /** Record an Architecture Decision Record (ADR). */\n async adr(opts: {\n title: string;\n context: string;\n decision: string;\n alternatives?: string[];\n consequences?: string;\n tags?: string[];\n }): Promise<string | null> {\n const lines: string[] = [];\n lines.push(`# ADR: ${opts.title}`);\n lines.push(`Date: ${new Date().toISOString()}`);\n lines.push(\"\");\n lines.push(\"## Context\");\n lines.push(opts.context);\n lines.push(\"\");\n lines.push(\"## Decision\");\n lines.push(opts.decision);\n lines.push(\"\");\n\n const alternatives = Array.isArray(opts.alternatives)\n ? opts.alternatives\n : typeof opts.alternatives === \"string\" && opts.alternatives\n ? [opts.alternatives]\n : [];\n if (alternatives.length > 0) {\n lines.push(\"## Alternatives considered\");\n for (const alt of alternatives) lines.push(`- ${alt}`);\n lines.push(\"\");\n }\n if (opts.consequences) {\n lines.push(\"## Consequences\");\n lines.push(opts.consequences);\n lines.push(\"\");\n }\n\n const content = lines.join(\"\\n\");\n const dedupPayload = JSON.stringify({\n title: opts.title,\n context: opts.context,\n decision: opts.decision,\n alternatives,\n consequences: opts.consequences ?? \"\",\n });\n const contentHash = createHash(\"sha256\").update(dedupPayload).digest(\"hex\");\n const existing = await this.storage.findByContentHash(contentHash, this.sessionKey);\n if (existing.length > 0) return null;\n\n const id = generateId();\n const entry: CaptureEntry = {\n id,\n sessionKey: this.sessionKey,\n agentId: \"sdk\",\n type: \"decision\",\n content,\n tags: [\"adr\", ...(opts.tags ?? [])],\n createdAt: Date.now(),\n metadata: {\n adr: true,\n title: opts.title,\n context: opts.context,\n decision: opts.decision,\n alternatives,\n consequences: opts.consequences ?? \"\",\n },\n contentHash,\n };\n\n await this.storage.put(entry);\n\n try {\n const embedding = await this.embedder.embed(content);\n await this.storage.putVector(id, embedding);\n } catch {\n // Embedding is optional\n }\n\n return id;\n }\n\n /** Close the database connection. */\n close(): void {\n this.storage.close();\n }\n}\n\nexport type {\n CallInfo,\n ImpactResult,\n ImportInfo,\n IndexResult,\n SymbolInfo,\n} from \"./codegraph/engine.js\";\n// Re-export CodeGraph engine for programmatic use\nexport {\n detectLanguage,\n findCallees,\n findCallers,\n impactAnalysis,\n indexDirectory,\n indexFile,\n listSymbols,\n SUPPORTED_LANGUAGES,\n searchSymbols,\n} from \"./codegraph/engine.js\";\nexport type { IngestResult as WikiIngestResult, WikiLink, WikiPage } from \"./wiki/engine.js\";\n// Re-export Wiki engine for programmatic use\nexport {\n findOutdatedPages,\n getWikiPage,\n ingestDirectory as wikiIngestDirectory,\n ingestFile as wikiIngestFile,\n searchWiki,\n} from \"./wiki/engine.js\";\n","/**\n * Secret redactor.\n * Scans text for secrets and replaces them with [REDACTED].\n * Uses regex patterns and a high-entropy detector.\n */\n\n/** Regex patterns for known secret formats. */\nconst SECRET_PATTERNS: RegExp[] = [\n // OpenAI API key\n /sk-[a-zA-Z0-9]{20,}/g,\n // Anthropic API key\n /sk-ant-[a-zA-Z0-9-]+/g,\n // GitHub personal access token\n /ghp_[a-zA-Z0-9]{36}/g,\n // GitHub OAuth token\n /gho_[a-zA-Z0-9]{36}/g,\n // GitHub fine-grained token\n /github_pat_[a-zA-Z0-9_]{82}/g,\n // Slack token\n /xox[baprs]-[a-zA-Z0-9-]+/g,\n // AWS access key ID\n /AKIA[0-9A-Z]{16}/g,\n // AWS secret access key (40 chars, base64-ish)\n /(?<![A-Za-z0-9+/])[A-Za-z0-9+/]{40}(?![A-Za-z0-9+/])/g,\n // PEM private key block\n /-----BEGIN [A-Z ]*PRIVATE KEY-----[\\s\\S]*?-----END [A-Z ]*PRIVATE KEY-----/g,\n // Google API key\n /AIza[0-9A-Za-z\\-_]{35}/g,\n // Generic bearer token (require 20+ char token to avoid redacting \"Bearer with JWT\")\n /Bearer\\s+[a-zA-Z0-9\\-._~+/]{20,}=*/g,\n];\n\n/** Minimum length for high-entropy detection. */\nconst MIN_LENGTH = 40;\n\n/** Entropy threshold in bits per character. */\nconst ENTROPY_THRESHOLD = 4.5;\n\n/** Compute the Shannon entropy of a string, in bits per character. */\nfunction shannonEntropy(str: string): number {\n const freq = new Map<string, number>();\n for (const ch of str) {\n freq.set(ch, (freq.get(ch) ?? 0) + 1);\n }\n let entropy = 0;\n const len = str.length;\n for (const count of freq.values()) {\n const p = count / len;\n entropy -= p * Math.log2(p);\n }\n return entropy;\n}\n\n/** Find high-entropy strings that look like secrets. */\nfunction findHighEntropyStrings(text: string): string[] {\n const results: string[] = [];\n // Match long strings of alphanumeric, +, /, =\n const regex = /[a-zA-Z0-9+/=]{40,}/g;\n let match: RegExpExecArray | null;\n match = regex.exec(text);\n while (match !== null) {\n const str = match[0];\n if (str.length >= MIN_LENGTH) {\n const entropy = shannonEntropy(str);\n if (entropy >= ENTROPY_THRESHOLD) {\n results.push(str);\n }\n }\n match = regex.exec(text);\n }\n return results;\n}\n\nexport interface RedactionResult {\n /** The redacted text. */\n text: string;\n /** Whether any secrets were found and redacted. */\n redacted: boolean;\n}\n\n/** Redact secrets from text. Returns the redacted text and a flag. */\nexport function redact(text: string): RedactionResult {\n let result = text;\n let redacted = false;\n\n // Apply regex patterns\n for (const pattern of SECRET_PATTERNS) {\n const before = result;\n result = result.replace(pattern, \"[REDACTED]\");\n if (result !== before) redacted = true;\n }\n\n // Apply high-entropy detection\n const highEntropy = findHighEntropyStrings(result);\n for (const str of highEntropy) {\n // Make sure we did not already redact this region\n result = result.replace(str, \"[REDACTED]\");\n redacted = true;\n }\n\n return { text: result, redacted };\n}\n","/**\n * Wiki engine: parse markdown docs into structured pages with a link graph.\n *\n * Extracts frontmatter, headings, [[wikilinks]], and [text](url) links.\n * Builds an adjacency list for the link graph.\n */\nimport { createHash } from \"node:crypto\";\nimport { existsSync, readdirSync, readFileSync, statSync } from \"node:fs\";\nimport { basename, extname, join, relative, sep } from \"node:path\";\nimport type { Database } from \"better-sqlite3\";\nimport { generateId } from \"../utils/ulid.js\";\n\n/** A parsed wiki page. */\nexport interface WikiPage {\n id: string;\n title: string;\n content: string;\n sourceFile: string;\n section: string | null;\n tags: string | null;\n frontmatter: string | null;\n contentHash: string;\n}\n\n/** A link between wiki pages. */\nexport interface WikiLink {\n fromPageId: string;\n toPageId: string | null;\n toTitle: string;\n linkText: string;\n linkType: string;\n line: number;\n}\n\n/** Result of ingesting a file. */\nexport interface IngestResult {\n file: string;\n pages: number;\n links: number;\n skipped: boolean;\n reason?: string;\n}\n\n/** Parse frontmatter (YAML-like) from markdown content. */\nfunction parseFrontmatter(content: string): { frontmatter: string | null; body: string } {\n if (!content.startsWith(\"---\")) {\n return { frontmatter: null, body: content };\n }\n const end = content.indexOf(\"\\n---\", 3);\n if (end === -1) {\n return { frontmatter: null, body: content };\n }\n const frontmatter = content.slice(3, end).trim();\n const body = content.slice(end + 4).replace(/^\\n/, \"\");\n return { frontmatter, body };\n}\n\n/** Extract tags from frontmatter (simple key: value parsing). */\nfunction extractTags(frontmatter: string | null): string | null {\n if (!frontmatter) return null;\n const match = frontmatter.match(/^tags:\\s*(.+)$/m);\n if (!match) return null;\n return match[1].replace(/[[\\]]/g, \"\").trim();\n}\n\n/** Extract title from frontmatter or first heading. */\nfunction extractTitle(frontmatter: string | null, body: string, fileName: string): string {\n if (frontmatter) {\n const titleMatch = frontmatter.match(/^title:\\s*(.+)$/m);\n if (titleMatch) return titleMatch[1].replace(/[\"']/g, \"\").trim();\n }\n // First H1 heading\n const h1Match = body.match(/^#\\s+(.+)$/m);\n if (h1Match) return h1Match[1].trim();\n // Fallback: file name without extension\n return basename(fileName, extname(fileName));\n}\n\n/** Extract [[wikilinks]] from content. Returns array of { target, text, line }. */\nfunction extractWikilinks(content: string): Array<{ target: string; text: string; line: number }> {\n const links: Array<{ target: string; text: string; line: number }> = [];\n const lines = content.split(\"\\n\");\n const regex = /\\[\\[([^\\]|]+)(?:\\|([^\\]]+))?\\]\\]/g;\n for (let i = 0; i < lines.length; i++) {\n let match: RegExpExecArray | null;\n regex.lastIndex = 0;\n match = regex.exec(lines[i]);\n while (match !== null) {\n links.push({\n target: match[1].trim(),\n text: (match[2] ?? match[1]).trim(),\n line: i + 1,\n });\n match = regex.exec(lines[i]);\n }\n }\n return links;\n}\n\n/** Extract [text](url) markdown links from content. */\nfunction extractMarkdownLinks(\n content: string,\n): Array<{ target: string; text: string; line: number }> {\n const links: Array<{ target: string; text: string; line: number }> = [];\n const lines = content.split(\"\\n\");\n // Match [text](path) but not  (images)\n const regex = /(?<!!)\\[([^\\]]+)\\]\\(([^)]+)\\)/g;\n for (let i = 0; i < lines.length; i++) {\n let match: RegExpExecArray | null;\n regex.lastIndex = 0;\n match = regex.exec(lines[i]);\n while (match !== null) {\n const target = match[2].trim();\n // Only include local .md links (not http URLs)\n if (!target.startsWith(\"http\") && !target.startsWith(\"mailto:\")) {\n links.push({\n target: target.replace(/\\.md$/i, \"\"),\n text: match[1].trim(),\n line: i + 1,\n });\n }\n match = regex.exec(lines[i]);\n }\n }\n return links;\n}\n\n/** Parse a markdown file into a wiki page with links. */\nfunction parseMarkdownFile(\n filePath: string,\n repoPath: string,\n): {\n page: WikiPage;\n links: Array<{ target: string; text: string; line: number; type: string }>;\n} | null {\n const ext = extname(filePath).toLowerCase();\n if (ext !== \".md\" && ext !== \".markdown\") return null;\n\n let source: string;\n try {\n source = readFileSync(filePath, \"utf-8\");\n } catch {\n return null;\n }\n\n const relPath = relative(repoPath, filePath).split(sep).join(\"/\");\n const { frontmatter, body } = parseFrontmatter(source);\n const title = extractTitle(frontmatter, body, filePath);\n const tags = extractTags(frontmatter);\n const contentHash = createHash(\"sha256\").update(source).digest(\"hex\");\n\n const page: WikiPage = {\n id: generateId(),\n title,\n content: body,\n sourceFile: relPath,\n section: null,\n tags,\n frontmatter,\n contentHash,\n };\n\n const wikilinks = extractWikilinks(body).map((l) => ({ ...l, type: \"wikilink\" }));\n const mdlinks = extractMarkdownLinks(body).map((l) => ({ ...l, type: \"markdown\" }));\n const links = [...wikilinks, ...mdlinks];\n\n return { page, links };\n}\n\n/** Ingest a single markdown file into the database. */\nexport function ingestFile(\n db: Database,\n filePath: string,\n repoPath: string,\n teamId: string | null,\n): IngestResult {\n const ext = extname(filePath).toLowerCase();\n if (ext !== \".md\" && ext !== \".markdown\") {\n return { file: filePath, pages: 0, links: 0, skipped: true, reason: \"not markdown\" };\n }\n\n const parsed = parseMarkdownFile(filePath, repoPath);\n if (!parsed) {\n return { file: filePath, pages: 0, links: 0, skipped: true, reason: \"parse failed\" };\n }\n\n const relPath = relative(repoPath, filePath).split(sep).join(\"/\");\n const now = Date.now();\n\n // Check if page already exists (by source_file)\n const existing = db\n .prepare(\"SELECT id FROM wiki_pages WHERE source_file = ? AND team_id IS ?\")\n .get(relPath, teamId) as { id: string } | undefined;\n\n let pageId = parsed.page.id;\n if (existing) {\n // Update existing page\n pageId = existing.id;\n db.prepare(\n \"UPDATE wiki_pages SET title = ?, content = ?, tags = ?, frontmatter = ?, content_hash = ?, updated_at = ? WHERE id = ?\",\n ).run(\n parsed.page.title,\n parsed.page.content,\n parsed.page.tags,\n parsed.page.frontmatter,\n parsed.page.contentHash,\n now,\n pageId,\n );\n // Delete old links\n db.prepare(\"DELETE FROM wiki_links WHERE from_page_id = ?\").run(pageId);\n } else {\n // Insert new page\n db.prepare(\n `INSERT INTO wiki_pages (id, title, content, source_file, section, tags, frontmatter, content_hash, team_id, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n ).run(\n parsed.page.id,\n parsed.page.title,\n parsed.page.content,\n parsed.page.sourceFile,\n parsed.page.section,\n parsed.page.tags,\n parsed.page.frontmatter,\n parsed.page.contentHash,\n teamId,\n now,\n now,\n );\n }\n\n // Insert links (resolve targets later)\n const linkStmt = db.prepare(\n \"INSERT INTO wiki_links (from_page_id, to_page_id, to_title, link_text, link_type, line) VALUES (?, ?, ?, ?, ?, ?)\",\n );\n for (const link of parsed.links) {\n // Try to resolve target by title\n const target = db\n .prepare(\"SELECT id FROM wiki_pages WHERE title = ? AND team_id IS ? LIMIT 1\")\n .get(link.target, teamId) as { id: string } | undefined;\n linkStmt.run(pageId, target?.id ?? null, link.target, link.text, link.type, link.line);\n }\n\n return {\n file: relPath,\n pages: 1,\n links: parsed.links.length,\n skipped: false,\n };\n}\n\n/** Ingest a directory of markdown files. */\nexport function ingestDirectory(\n db: Database,\n dirPath: string,\n repoPath: string,\n teamId: string | null,\n maxFiles = 200,\n): IngestResult[] {\n const results: IngestResult[] = [];\n const files: string[] = [];\n\n const walk = (dir: string) => {\n if (files.length >= maxFiles) return;\n let entries: string[];\n try {\n entries = readdirSync(dir);\n } catch {\n return;\n }\n for (const entry of entries) {\n if (files.length >= maxFiles) return;\n const fullPath = join(dir, entry);\n let stat: ReturnType<typeof statSync>;\n try {\n stat = statSync(fullPath);\n } catch {\n continue;\n }\n if (stat.isDirectory()) {\n if (entry.startsWith(\".\") || entry === \"node_modules\" || entry === \"vendor\") continue;\n walk(fullPath);\n } else if (stat.isFile()) {\n const ext = extname(fullPath).toLowerCase();\n if (ext === \".md\" || ext === \".markdown\") {\n files.push(fullPath);\n }\n }\n }\n };\n\n walk(dirPath);\n\n for (const file of files) {\n const result = ingestFile(db, file, repoPath, teamId);\n results.push(result);\n }\n\n // Re-resolve links now that all pages are indexed\n const unresolved = db\n .prepare(\"SELECT id, to_title FROM wiki_links WHERE to_page_id IS NULL\")\n .all() as { id: number; to_title: string }[];\n if (unresolved.length > 0) {\n const updateStmt = db.prepare(\"UPDATE wiki_links SET to_page_id = ? WHERE id = ?\");\n for (const u of unresolved) {\n const target = db\n .prepare(\"SELECT id FROM wiki_pages WHERE title = ? AND team_id IS ? LIMIT 1\")\n .get(u.to_title, teamId) as { id: string } | undefined;\n if (target) {\n updateStmt.run(target.id, u.id);\n }\n }\n }\n\n return results;\n}\n\n/** Search wiki pages using FTS5. */\nexport function searchWiki(\n db: Database,\n query: string,\n opts: { teamId?: string; limit?: number } = {},\n): Array<{ id: string; title: string; sourceFile: string; snippet: string }> {\n const limit = opts.limit ?? 10;\n let sql = `\n SELECT w.id, w.title, w.source_file, snippet(wiki_fts, 1, '<b>', '</b>', '...', 20) as snippet\n FROM wiki_fts f\n JOIN wiki_pages w ON w.id = f.id\n WHERE wiki_fts MATCH ?\n `;\n const params: unknown[] = [query];\n if (opts.teamId !== undefined) {\n sql += \" AND w.team_id IS ?\";\n params.push(opts.teamId);\n }\n sql += \" LIMIT ?\";\n params.push(limit);\n\n const rows = db.prepare(sql).all(...params) as Array<{\n id: string;\n title: string;\n source_file: string;\n snippet: string;\n }>;\n\n return rows.map((r) => ({\n id: r.id,\n title: r.title,\n sourceFile: r.source_file,\n snippet: r.snippet,\n }));\n}\n\n/** Get a wiki page by ID, including linked pages. */\nexport function getWikiPage(\n db: Database,\n pageId: string,\n): { page: WikiPage; links: WikiLink[]; backlinks: WikiLink[] } | null {\n const row = db.prepare(\"SELECT * FROM wiki_pages WHERE id = ?\").get(pageId) as\n | {\n id: string;\n title: string;\n content: string;\n source_file: string;\n section: string | null;\n tags: string | null;\n frontmatter: string | null;\n content_hash: string;\n }\n | undefined;\n\n if (!row) return null;\n\n const page: WikiPage = {\n id: row.id,\n title: row.title,\n content: row.content,\n sourceFile: row.source_file,\n section: row.section,\n tags: row.tags,\n frontmatter: row.frontmatter,\n contentHash: row.content_hash,\n };\n\n const linkRows = db\n .prepare(\"SELECT * FROM wiki_links WHERE from_page_id = ? ORDER BY line\")\n .all(pageId) as Array<{\n from_page_id: string;\n to_page_id: string | null;\n to_title: string;\n link_text: string;\n link_type: string;\n line: number;\n }>;\n\n const links: WikiLink[] = linkRows.map((r) => ({\n fromPageId: r.from_page_id,\n toPageId: r.to_page_id,\n toTitle: r.to_title,\n linkText: r.link_text,\n linkType: r.link_type,\n line: r.line,\n }));\n\n const backlinkRows = db\n .prepare(\"SELECT * FROM wiki_links WHERE to_page_id = ? ORDER BY line\")\n .all(pageId) as Array<{\n from_page_id: string;\n to_page_id: string | null;\n to_title: string;\n link_text: string;\n link_type: string;\n line: number;\n }>;\n\n const backlinks: WikiLink[] = backlinkRows.map((r) => ({\n fromPageId: r.from_page_id,\n toPageId: r.to_page_id,\n toTitle: r.to_title,\n linkText: r.link_text,\n linkType: r.link_type,\n line: r.line,\n }));\n\n return { page, links, backlinks };\n}\n\n/** Find pages whose source file has changed (content_hash mismatch). */\nexport function findOutdatedPages(\n db: Database,\n repoPath: string,\n opts: { teamId?: string } = {},\n): Array<{ id: string; title: string; sourceFile: string; reason: string }> {\n const pages = db\n .prepare(\"SELECT id, title, source_file, content_hash FROM wiki_pages WHERE team_id IS ?\")\n .all(opts.teamId ?? null) as Array<{\n id: string;\n title: string;\n source_file: string;\n content_hash: string;\n }>;\n\n const outdated: Array<{ id: string; title: string; sourceFile: string; reason: string }> = [];\n\n for (const page of pages) {\n const fullPath = join(repoPath, page.source_file);\n if (!existsSync(fullPath)) {\n outdated.push({\n id: page.id,\n title: page.title,\n sourceFile: page.source_file,\n reason: \"file deleted\",\n });\n continue;\n }\n try {\n const content = readFileSync(fullPath, \"utf-8\");\n const hash = createHash(\"sha256\").update(content).digest(\"hex\");\n if (hash !== page.content_hash) {\n outdated.push({\n id: page.id,\n title: page.title,\n sourceFile: page.source_file,\n reason: \"content changed\",\n });\n }\n } catch {\n outdated.push({\n id: page.id,\n title: page.title,\n sourceFile: page.source_file,\n reason: \"read error\",\n });\n }\n }\n\n return outdated;\n}\n"],"mappings":"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","names":["createHash","join","join","createHash"]}
|
|
@@ -363,12 +363,24 @@ async function indexDirectory(db, dirPath, repoPath, teamId, maxFiles = 1e4) {
|
|
|
363
363
|
}
|
|
364
364
|
};
|
|
365
365
|
walk(dirPath);
|
|
366
|
+
const indexedSymbolIds = /* @__PURE__ */ new Set();
|
|
366
367
|
for (const file of files) {
|
|
367
368
|
const result = await indexFile(db, file, repoPath, teamId);
|
|
368
369
|
results.push(result);
|
|
369
370
|
}
|
|
370
|
-
|
|
371
|
-
|
|
371
|
+
if (results.length > 0) {
|
|
372
|
+
const indexedFiles = results.filter((r) => !r.skipped).map((r) => r.file);
|
|
373
|
+
for (let i = 0; i < indexedFiles.length; i += 500) {
|
|
374
|
+
const chunk = indexedFiles.slice(i, i + 500);
|
|
375
|
+
const placeholders = chunk.map(() => "?").join(",");
|
|
376
|
+
const rows = db.prepare(`SELECT id FROM symbols WHERE file_path IN (${placeholders})`).all(...chunk);
|
|
377
|
+
for (const r of rows) {
|
|
378
|
+
indexedSymbolIds.add(r.id);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
const { resolveAllCalls } = await import("./resolver-UHU4MBQX.js");
|
|
383
|
+
const stats = resolveAllCalls(db, indexedSymbolIds);
|
|
372
384
|
if (stats.total > 0) {
|
|
373
385
|
console.error(
|
|
374
386
|
`[remem-mcp] indexDirectory: resolved ${stats.resolved}/${stats.total} calls` + (Object.keys(stats.byStrategy).length > 0 ? ` (${JSON.stringify(stats.byStrategy)})` : "")
|
|
@@ -893,4 +905,4 @@ export {
|
|
|
893
905
|
engine_exports,
|
|
894
906
|
init_engine
|
|
895
907
|
};
|
|
896
|
-
//# sourceMappingURL=chunk-
|
|
908
|
+
//# sourceMappingURL=chunk-YU7WBJU5.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/codegraph/engine.ts"],"sourcesContent":["/**\n * CodeGraph engine: parse code, extract symbols, build call graph, impact analysis.\n *\n * Uses @kreuzberg/tree-sitter-language-pack for multi-language parsing.\n * Supports: TypeScript, JavaScript, Python, Go, Rust, Java, C, C++, C#.\n */\nimport { createHash } from \"node:crypto\";\nimport { readdirSync, readFileSync, statSync } from \"node:fs\";\nimport { extname, join, relative, sep } from \"node:path\";\nimport type { Database } from \"better-sqlite3\";\nimport { generateId } from \"../utils/ulid.js\";\n\n// Lazy-load the language pack (CommonJS interop)\nlet _pack: unknown = null;\nasync function getPack(): Promise<Record<string, unknown>> {\n if (!_pack) {\n const mod = await import(\"@kreuzberg/tree-sitter-language-pack\");\n // Handle both ESM default and CJS module.exports\n _pack = mod.default ?? mod;\n }\n return _pack as Record<string, unknown>;\n}\n\n/** Supported languages mapped to file extensions. */\nconst EXTENSION_MAP: Record<string, string> = {\n \".ts\": \"typescript\",\n \".tsx\": \"tsx\",\n \".js\": \"javascript\",\n \".jsx\": \"javascript\",\n \".mjs\": \"javascript\",\n \".cjs\": \"javascript\",\n \".py\": \"python\",\n \".go\": \"go\",\n \".rs\": \"rust\",\n \".java\": \"java\",\n \".c\": \"c\",\n \".h\": \"c\",\n \".cpp\": \"cpp\",\n \".cc\": \"cpp\",\n \".cxx\": \"cpp\",\n \".hpp\": \"cpp\",\n \".cs\": \"csharp\",\n};\n\n/** Languages we support for symbol extraction. */\nexport const SUPPORTED_LANGUAGES = new Set(Object.values(EXTENSION_MAP));\n\n/** Detect language from file extension. Returns null if unsupported. */\nexport function detectLanguage(filePath: string): string | null {\n const ext = extname(filePath).toLowerCase();\n return EXTENSION_MAP[ext] ?? null;\n}\n\n/** A symbol extracted from code. */\nexport interface SymbolInfo {\n id: string;\n name: string;\n kind: string;\n filePath: string;\n lineStart: number;\n lineEnd: number;\n language: string;\n signature: string | null;\n docstring: string | null;\n parentId: string | null;\n contentHash: string;\n}\n\n/** A call relationship. */\nexport interface CallInfo {\n callerId: string;\n calleeName: string;\n calleeId: string | null;\n line: number;\n kind: string;\n callType?: string;\n}\n\n/** An import relationship. */\nexport interface ImportInfo {\n filePath: string;\n symbolName: string;\n sourcePath: string | null;\n line: number;\n language: string;\n}\n\n/** Result of indexing a file. */\nexport interface IndexResult {\n file: string;\n language: string;\n symbols: number;\n calls: number;\n imports: number;\n skipped: boolean;\n}\n\n/** Impact analysis result. */\nexport interface ImpactResult {\n rootSymbol: SymbolInfo;\n affected: Array<{ symbol: SymbolInfo; depth: number; path: string[] }>;\n}\n\n/** Parse a file and extract symbols, calls, and imports. */\nexport async function parseFile(\n filePath: string,\n repoPath: string,\n): Promise<{ symbols: SymbolInfo[]; calls: CallInfo[]; imports: ImportInfo[] } | null> {\n const language = detectLanguage(filePath);\n if (!language) return null;\n\n const pack = (await getPack()) as {\n hasLanguage: (lang: string) => boolean;\n process: (\n source: string,\n opts: { language: string },\n ) => {\n structure: Array<{\n kind?: string;\n name?: string;\n span?: { startLine?: number; endLine?: number };\n signature?: string;\n docComment?: string;\n children?: Array<{\n kind?: string;\n name?: string;\n span?: { startLine?: number; endLine?: number };\n signature?: string;\n docComment?: string;\n }>;\n }>;\n imports: Array<{\n items?: string[];\n source?: string;\n span?: { startLine?: number };\n }>;\n } | null;\n };\n if (!pack.hasLanguage(language)) return null;\n\n let source: string;\n try {\n source = readFileSync(filePath, \"utf-8\");\n } catch {\n return null;\n }\n\n // Skip files that are too large — tree-sitter parsing + regex extraction\n // scales O(n) with file size, and very large files are usually generated/vendored\n const MAX_FILE_LINES = 3000;\n const MAX_FILE_BYTES = 200_000; // 200KB\n if (source.length > MAX_FILE_BYTES || source.split(\"\\n\").length > MAX_FILE_LINES) {\n return null;\n }\n\n const result = pack.process(source, { language });\n if (!result) return null;\n\n const relPath = relative(repoPath, filePath).split(sep).join(\"/\");\n const symbols: SymbolInfo[] = [];\n const calls: CallInfo[] = [];\n const imports: ImportInfo[] = [];\n\n // Cache source lines once — used for offset calculation in extractSymbols\n const sourceLines = source.split(\"\\n\");\n // Precompute cumulative line start offsets for O(1) line→offset lookup\n const lineOffsets: number[] = [0];\n for (let i = 0; i < sourceLines.length; i++) {\n lineOffsets.push(lineOffsets[i] + sourceLines[i].length + 1); // +1 for \\n\n }\n\n // Extract symbols from structure\n const extractSymbols = (\n items: Array<{\n kind?: string;\n name?: string;\n span?: { startLine?: number; endLine?: number };\n signature?: string;\n docComment?: string;\n children?: Array<{\n kind?: string;\n name?: string;\n span?: { startLine?: number; endLine?: number };\n signature?: string;\n docComment?: string;\n }>;\n }>,\n parentId: string | null,\n ) => {\n for (const item of items) {\n if (!item.name) continue;\n const id = generateId();\n const lineStart = (item.span?.startLine ?? 0) + 1; // 1-indexed\n const lineEnd = (item.span?.endLine ?? lineStart) + 1;\n // Use cached lineOffsets instead of source.split(\"\\n\") per symbol\n const bodyStart = item.span?.startLine !== undefined ? lineOffsets[item.span.startLine] : 0;\n const bodyEnd =\n item.span?.endLine !== undefined ? lineOffsets[item.span.endLine + 1] - 1 : source.length;\n const bodyText = source.slice(bodyStart, bodyEnd);\n symbols.push({\n id,\n name: item.name,\n kind: item.kind ?? \"unknown\",\n filePath: relPath,\n lineStart,\n lineEnd,\n language,\n signature: item.signature ?? null,\n docstring: item.docComment ?? null,\n parentId,\n contentHash: createHash(\"sha256\")\n .update(item.name + relPath + lineStart)\n .digest(\"hex\"),\n });\n\n // Extract calls within this symbol's body — single-pass on body text\n // Captures: foo(), obj.method(), <Component/>, Class.create()\n // Uses cached bodyText + offset→line map (no per-line regex)\n const bodyStartLine = lineStart;\n\n // Build offset→line map for this body using cached lineOffsets\n const offsetToLine = (offset: number): number => {\n // offset is relative to bodyText which starts at bodyStart in source\n const sourceOffset = bodyStart + offset;\n // Binary search in lineOffsets\n let lo = 0,\n hi = lineOffsets.length - 1;\n while (lo < hi) {\n const mid = (lo + hi + 1) >> 1;\n if (lineOffsets[mid] <= sourceOffset) lo = mid;\n else hi = mid - 1;\n }\n return lo + 1; // 1-indexed\n };\n\n // Track offsets already captured to avoid duplicates\n const capturedOffsets = new Set<number>();\n\n // Pass 1: JSX components <Component> — capitalized identifiers\n const jsxRegex = /<([A-Z][a-zA-Z0-9_$]*)\\b/g;\n let jMatch: RegExpExecArray | null;\n while ((jMatch = jsxRegex.exec(bodyText)) !== null) {\n const calleeName = jMatch[1];\n const offset = jMatch.index;\n if (!isKeywordOrSelf(calleeName, item.name) && !capturedOffsets.has(offset)) {\n calls.push({\n callerId: id,\n calleeName,\n calleeId: null,\n line: offsetToLine(offset),\n kind: \"call\",\n callType: \"jsx\",\n });\n capturedOffsets.add(offset);\n }\n }\n\n // Pass 2: Method calls (obj.method) — captures full qualified name\n const methodCallRegex = /\\b([a-zA-Z_$][a-zA-Z0-9_$]*)\\.([a-zA-Z_$][a-zA-Z0-9_$]*)\\s*\\(/g;\n let mMatch: RegExpExecArray | null;\n while ((mMatch = methodCallRegex.exec(bodyText)) !== null) {\n const receiver = mMatch[1];\n const methodName = mMatch[2];\n const calleeName = `${receiver}.${methodName}`;\n const offset = mMatch.index;\n if (\n !isKeywordOrSelf(methodName, item.name) &&\n !isKeywordOrSelf(receiver, item.name) &&\n !isStdlibCall(calleeName, language) &&\n !capturedOffsets.has(offset)\n ) {\n calls.push({\n callerId: id,\n calleeName,\n calleeId: null,\n line: offsetToLine(offset),\n kind: \"call\",\n callType: \"method\",\n });\n capturedOffsets.add(offset);\n }\n }\n\n // Pass 3: Simple calls (foo) — skip if offset already captured or stdlib\n const simpleCallRegex = /\\b([a-zA-Z_$][a-zA-Z0-9_$]*)\\s*\\(/g;\n let match: RegExpExecArray | null;\n while ((match = simpleCallRegex.exec(bodyText)) !== null) {\n const calleeName = match[1];\n const offset = match.index;\n if (\n !isKeywordOrSelf(calleeName, item.name) &&\n !isStdlibCall(calleeName, language) &&\n !capturedOffsets.has(offset)\n ) {\n calls.push({\n callerId: id,\n calleeName,\n calleeId: null,\n line: offsetToLine(offset),\n kind: \"call\",\n callType: \"direct\",\n });\n capturedOffsets.add(offset);\n }\n }\n\n // Recurse into children\n if (item.children && item.children.length > 0) {\n extractSymbols(item.children, id);\n }\n }\n };\n\n extractSymbols(result.structure ?? [], null);\n\n // Extract imports\n for (const imp of result.imports ?? []) {\n imports.push({\n filePath: relPath,\n symbolName: imp.items?.join(\", \") ?? imp.source ?? \"unknown\",\n sourcePath: imp.source ?? null,\n line: (imp.span?.startLine ?? 0) + 1,\n language,\n });\n }\n\n return { symbols, calls, imports };\n}\n\n/** Check if a name is a language keyword or the symbol itself (should be skipped in call extraction). */\nfunction isKeywordOrSelf(name: string, symbolName: string): boolean {\n if (name === symbolName) return true;\n const keywords = new Set([\n \"if\",\n \"for\",\n \"while\",\n \"switch\",\n \"return\",\n \"function\",\n \"def\",\n \"func\",\n \"fn\",\n \"print\",\n \"console\",\n \"require\",\n \"import\",\n \"export\",\n \"class\",\n \"struct\",\n \"enum\",\n \"interface\",\n \"type\",\n \"const\",\n \"let\",\n \"var\",\n \"new\",\n \"delete\",\n \"typeof\",\n \"instanceof\",\n \"void\",\n \"in\",\n \"of\",\n \"await\",\n \"async\",\n \"yield\",\n \"throw\",\n \"try\",\n \"catch\",\n \"finally\",\n \"break\",\n \"continue\",\n \"do\",\n \"else\",\n \"case\",\n \"default\",\n \"extends\",\n \"implements\",\n \"super\",\n \"this\",\n \"self\",\n \"true\",\n \"false\",\n \"null\",\n \"undefined\",\n \"nil\",\n \"None\",\n \"True\",\n \"False\",\n \"println\",\n \"printf\",\n \"fmt\",\n \"err\",\n \"panic\",\n \"recover\",\n ]);\n return keywords.has(name);\n}\n\n/** Stdlib prefixes per language — calls to these are skipped (not indexed). */\nconst STDLIB_PREFIXES: Record<string, Set<string>> = {\n go: new Set([\n \"fmt\",\n \"json\",\n \"os\",\n \"io\",\n \"strings\",\n \"strconv\",\n \"time\",\n \"errors\",\n \"sync\",\n \"context\",\n \"path\",\n \"filepath\",\n \"sort\",\n \"bytes\",\n \"bufio\",\n \"encoding\",\n \"net\",\n \"http\",\n \"url\",\n \"regexp\",\n \"math\",\n \"log\",\n \"reflect\",\n \"runtime\",\n \"unsafe\",\n \"atomic\",\n \"crypto\",\n \"hash\",\n \"base64\",\n \"hex\",\n \"ioutil\",\n \"filepath\",\n \"unicode\",\n \"testing\",\n \"flag\",\n \"env\",\n ]),\n typescript: new Set([\n \"console\",\n \"JSON\",\n \"Math\",\n \"Date\",\n \"Object\",\n \"Array\",\n \"String\",\n \"Number\",\n \"Boolean\",\n \"Promise\",\n \"Symbol\",\n \"Map\",\n \"Set\",\n \"WeakMap\",\n \"WeakSet\",\n \"Error\",\n \"RegExp\",\n \"Buffer\",\n \"process\",\n \"setTimeout\",\n \"setInterval\",\n \"clearTimeout\",\n \"clearInterval\",\n \"fetch\",\n \"URL\",\n \"URLSearchParams\",\n \"FormData\",\n \"Headers\",\n \"Request\",\n \"Response\",\n \"AbortController\",\n \"Event\",\n \"EventTarget\",\n \"CustomEvent\",\n \"TextEncoder\",\n \"TextDecoder\",\n \"crypto\",\n \"performance\",\n \"queueMicrotask\",\n \"atob\",\n \"btoa\",\n \"parseInt\",\n \"parseFloat\",\n \"isNaN\",\n \"isFinite\",\n \"encodeURIComponent\",\n \"decodeURIComponent\",\n \"encodeURI\",\n \"decodeURI\",\n ]),\n javascript: new Set([\n \"console\",\n \"JSON\",\n \"Math\",\n \"Date\",\n \"Object\",\n \"Array\",\n \"String\",\n \"Number\",\n \"Boolean\",\n \"Promise\",\n \"Symbol\",\n \"Map\",\n \"Set\",\n \"WeakMap\",\n \"WeakSet\",\n \"Error\",\n \"RegExp\",\n \"Buffer\",\n \"process\",\n \"setTimeout\",\n \"setInterval\",\n \"clearTimeout\",\n \"clearInterval\",\n \"fetch\",\n \"URL\",\n \"URLSearchParams\",\n \"FormData\",\n \"Headers\",\n \"Request\",\n \"Response\",\n \"AbortController\",\n \"Event\",\n \"EventTarget\",\n \"CustomEvent\",\n \"TextEncoder\",\n \"TextDecoder\",\n \"crypto\",\n \"performance\",\n \"queueMicrotask\",\n \"atob\",\n \"btoa\",\n \"parseInt\",\n \"parseFloat\",\n \"isNaN\",\n \"isFinite\",\n \"encodeURIComponent\",\n \"decodeURIComponent\",\n \"encodeURI\",\n \"decodeURI\",\n ]),\n python: new Set([\n \"print\",\n \"len\",\n \"range\",\n \"str\",\n \"int\",\n \"float\",\n \"bool\",\n \"list\",\n \"dict\",\n \"set\",\n \"tuple\",\n \"type\",\n \"isinstance\",\n \"issubclass\",\n \"id\",\n \"hash\",\n \"dir\",\n \"vars\",\n \"globals\",\n \"locals\",\n \"exec\",\n \"eval\",\n \"compile\",\n \"open\",\n \"input\",\n \"repr\",\n \"format\",\n \"chr\",\n \"ord\",\n \"hex\",\n \"oct\",\n \"bin\",\n \"abs\",\n \"min\",\n \"max\",\n \"sum\",\n \"round\",\n \"pow\",\n \"divmod\",\n \"sorted\",\n \"reversed\",\n \"enumerate\",\n \"zip\",\n \"map\",\n \"filter\",\n \"any\",\n \"all\",\n \"next\",\n \"iter\",\n \"getattr\",\n \"setattr\",\n \"hasattr\",\n \"delattr\",\n \"property\",\n \"staticmethod\",\n \"classmethod\",\n \"super\",\n \"object\",\n \"Exception\",\n \"ValueError\",\n \"TypeError\",\n \"KeyError\",\n \"IndexError\",\n \"AttributeError\",\n \"RuntimeError\",\n \"StopIteration\",\n \"os\",\n \"sys\",\n \"json\",\n \"re\",\n \"time\",\n \"datetime\",\n \"pathlib\",\n \"typing\",\n \"collections\",\n \"itertools\",\n \"functools\",\n \"subprocess\",\n \"argparse\",\n \"logging\",\n \"unittest\",\n \"asyncio\",\n \"threading\",\n \"multiprocessing\",\n \"pickle\",\n \"shutil\",\n \"tempfile\",\n \"glob\",\n \"fnmatch\",\n \"csv\",\n \"io\",\n \"base64\",\n \"hashlib\",\n \"hmac\",\n \"secrets\",\n \"uuid\",\n \"copy\",\n \"math\",\n \"random\",\n \"statistics\",\n \"decimal\",\n \"fractions\",\n \"sqlite3\",\n ]),\n rust: new Set([\n \"println\",\n \"print\",\n \"eprintln\",\n \"eprint\",\n \"format\",\n \"vec\",\n \"String\",\n \"Vec\",\n \"Option\",\n \"Result\",\n \"Some\",\n \"None\",\n \"Ok\",\n \"Err\",\n \"Box\",\n \"Rc\",\n \"Arc\",\n \"RefCell\",\n \"Cell\",\n \"Mutex\",\n \"RwLock\",\n \"HashMap\",\n \"HashSet\",\n \"BTreeMap\",\n \"BTreeSet\",\n \"VecDeque\",\n \"LinkedList\",\n \"std\",\n \"core\",\n \"alloc\",\n \"macro\",\n \"todo\",\n \"unimplemented\",\n \"panic\",\n \"assert\",\n \"assert_eq\",\n \"assert_ne\",\n \"debug_assert\",\n \"debug_assert_eq\",\n \"cfg\",\n \"env\",\n \"include\",\n \"concat\",\n \"stringify\",\n \"file\",\n \"line\",\n \"module_path\",\n \"column\",\n \"format_args\",\n \"write\",\n \"writeln\",\n ]),\n};\n\n/** Check if a callee name is a stdlib call for the given language. */\nfunction isStdlibCall(calleeName: string, language: string): boolean {\n const prefixes = STDLIB_PREFIXES[language];\n if (!prefixes) return false;\n // Check direct match (e.g. \"println\", \"len\")\n if (prefixes.has(calleeName)) return true;\n // Check prefix match (e.g. \"fmt.Printf\" → prefix \"fmt\")\n const dotIdx = calleeName.indexOf(\".\");\n if (dotIdx > 0) {\n const prefix = calleeName.slice(0, dotIdx);\n if (prefixes.has(prefix)) return true;\n }\n return false;\n}\n\n/** Index a single file into the database. */\nexport async function indexFile(\n db: Database,\n filePath: string,\n repoPath: string,\n teamId: string | null,\n): Promise<IndexResult> {\n const language = detectLanguage(filePath);\n if (!language) {\n return { file: filePath, language: \"unknown\", symbols: 0, calls: 0, imports: 0, skipped: true };\n }\n\n const parsed = await parseFile(filePath, repoPath);\n if (!parsed) {\n return { file: filePath, language, symbols: 0, calls: 0, imports: 0, skipped: true };\n }\n\n const relPath = relative(repoPath, filePath).split(sep).join(\"/\");\n const now = Date.now();\n\n // Delete existing symbols for this file\n const existingIds = db\n .prepare(\"SELECT id FROM symbols WHERE file_path = ? AND team_id IS ?\")\n .all(relPath, teamId) as { id: string }[];\n if (existingIds.length > 0) {\n const placeholders = existingIds.map(() => \"?\").join(\",\");\n db.prepare(`DELETE FROM calls WHERE caller_id IN (${placeholders})`).run(\n ...existingIds.map((e) => e.id),\n );\n db.prepare(\"DELETE FROM symbols WHERE file_path = ? AND team_id IS ?\").run(relPath, teamId);\n }\n db.prepare(\"DELETE FROM imports WHERE file_path = ? AND team_id IS ?\").run(relPath, teamId);\n\n // Insert symbols\n const symbolStmt = db.prepare(\n `INSERT INTO symbols (id, name, kind, file_path, line_start, line_end, language, signature, docstring, parent_id, team_id, repo_path, content_hash, module_path, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n );\n const modulePath = relPath.replace(\n /\\.(ts|tsx|js|jsx|mjs|cjs|py|go|rs|java|c|cpp|cc|cxx|hpp|cs)$/,\n \"\",\n );\n for (const s of parsed.symbols) {\n symbolStmt.run(\n s.id,\n s.name,\n s.kind,\n s.filePath,\n s.lineStart,\n s.lineEnd,\n s.language,\n s.signature,\n s.docstring,\n s.parentId,\n teamId,\n repoPath,\n s.contentHash,\n modulePath,\n now,\n now,\n );\n }\n\n // Insert calls (callee_id resolved later by 6-strategy cascade in indexDirectory)\n const callStmt = db.prepare(\n `INSERT INTO calls (caller_id, callee_name, callee_id, line, kind, call_type, team_id) VALUES (?, ?, ?, ?, ?, ?, ?)`,\n );\n for (const c of parsed.calls) {\n callStmt.run(\n c.callerId,\n c.calleeName,\n null, // Will be resolved by resolveAllCalls() in indexDirectory\n c.line,\n c.kind,\n (c as { callType?: string }).callType ?? \"direct\",\n teamId,\n );\n }\n\n // Insert imports\n const importStmt = db.prepare(\n `INSERT INTO imports (file_path, symbol_name, source_path, line, language, team_id, repo_path) VALUES (?, ?, ?, ?, ?, ?, ?)`,\n );\n for (const imp of parsed.imports) {\n importStmt.run(\n imp.filePath,\n imp.symbolName,\n imp.sourcePath,\n imp.line,\n imp.language,\n teamId,\n repoPath,\n );\n }\n\n return {\n file: relPath,\n language,\n symbols: parsed.symbols.length,\n calls: parsed.calls.length,\n imports: parsed.imports.length,\n skipped: false,\n };\n}\n\n/** Index a directory recursively. */\nexport async function indexDirectory(\n db: Database,\n dirPath: string,\n repoPath: string,\n teamId: string | null,\n maxFiles = 10000,\n): Promise<IndexResult[]> {\n const results: IndexResult[] = [];\n const files: string[] = [];\n\n const walk = (dir: string) => {\n if (files.length >= maxFiles) return;\n let entries: string[];\n try {\n entries = readdirSync(dir);\n } catch {\n return;\n }\n for (const entry of entries) {\n if (files.length >= maxFiles) return;\n const fullPath = join(dir, entry);\n let stat: ReturnType<typeof statSync>;\n try {\n stat = statSync(fullPath);\n } catch {\n continue;\n }\n if (stat.isDirectory()) {\n // Skip common ignore dirs\n if (\n entry === \"node_modules\" ||\n entry === \".git\" ||\n entry === \"dist\" ||\n entry === \"build\" ||\n entry === \"target\" ||\n entry === \"__pycache__\" ||\n entry === \".next\" ||\n entry === \"vendor\" ||\n entry === \".venv\" ||\n entry.startsWith(\".\")\n )\n continue;\n walk(fullPath);\n } else if (stat.isFile()) {\n if (detectLanguage(fullPath)) {\n files.push(fullPath);\n }\n }\n }\n };\n\n walk(dirPath);\n\n for (const file of files) {\n const result = await indexFile(db, file, repoPath, teamId);\n results.push(result);\n }\n\n // Resolve callee IDs using 6-strategy cascade (import-map, same-module, unique-name, suffix, fuzzy)\n // Adapted from Codebase-Memory (arXiv:2603.27277)\n const { resolveAllCalls } = await import(\"./resolver.js\");\n const stats = resolveAllCalls(db);\n if (stats.total > 0) {\n console.error(\n `[remem-mcp] indexDirectory: resolved ${stats.resolved}/${stats.total} calls` +\n (Object.keys(stats.byStrategy).length > 0 ? ` (${JSON.stringify(stats.byStrategy)})` : \"\"),\n );\n }\n\n return results;\n}\n\n/** Search symbols by name or pattern. */\nexport function searchSymbols(\n db: Database,\n query: string,\n opts: {\n teamId?: string;\n kind?: string;\n language?: string;\n limit?: number;\n repoPath?: string;\n } = {},\n): SymbolInfo[] {\n const limit = opts.limit ?? 20;\n const pattern = `%${query}%`;\n let sql = \"SELECT * FROM symbols WHERE name LIKE ?\";\n const params: unknown[] = [pattern];\n if (opts.teamId !== undefined) {\n sql += \" AND team_id IS ?\";\n params.push(opts.teamId);\n }\n if (opts.repoPath !== undefined) {\n // Use LIKE prefix match so /path/to/src also matches repo_path /path/to\n sql += \" AND (repo_path = ? OR repo_path LIKE ?)\";\n params.push(opts.repoPath, `${opts.repoPath}%`);\n }\n if (opts.kind) {\n sql += \" AND kind = ?\";\n params.push(opts.kind);\n }\n if (opts.language) {\n sql += \" AND language = ?\";\n params.push(opts.language);\n }\n sql += \" LIMIT ?\";\n params.push(limit);\n\n const rows = db.prepare(sql).all(...params) as Array<{\n id: string;\n name: string;\n kind: string;\n file_path: string;\n line_start: number;\n line_end: number;\n language: string;\n signature: string | null;\n docstring: string | null;\n parent_id: string | null;\n content_hash: string;\n }>;\n\n return rows.map((r) => ({\n id: r.id,\n name: r.name,\n kind: r.kind,\n filePath: r.file_path,\n lineStart: r.line_start,\n lineEnd: r.line_end,\n language: r.language,\n signature: r.signature,\n docstring: r.docstring,\n parentId: r.parent_id,\n contentHash: r.content_hash,\n }));\n}\n\n/** Find all callers of a symbol (who calls X?). */\nexport function findCallers(\n db: Database,\n symbolId: string,\n opts: { limit?: number } = {},\n): Array<{ caller: SymbolInfo; line: number }> {\n const limit = opts.limit ?? 50;\n const rows = db\n .prepare(\n `SELECT s.*, c.line as call_line\n FROM calls c\n JOIN symbols s ON s.id = c.caller_id\n WHERE c.callee_id = ? OR c.callee_name = (SELECT name FROM symbols WHERE id = ?)\n LIMIT ?`,\n )\n .all(symbolId, symbolId, limit) as Array<{\n id: string;\n name: string;\n kind: string;\n file_path: string;\n line_start: number;\n line_end: number;\n language: string;\n signature: string | null;\n docstring: string | null;\n parent_id: string | null;\n content_hash: string;\n call_line: number;\n }>;\n\n return rows.map((r) => ({\n caller: {\n id: r.id,\n name: r.name,\n kind: r.kind,\n filePath: r.file_path,\n lineStart: r.line_start,\n lineEnd: r.line_end,\n language: r.language,\n signature: r.signature,\n docstring: r.docstring,\n parentId: r.parent_id,\n contentHash: r.content_hash,\n },\n line: r.call_line,\n }));\n}\n\n/** Find all callees of a symbol (X calls whom?). */\nexport function findCallees(\n db: Database,\n symbolId: string,\n opts: { limit?: number } = {},\n): Array<{ callee: SymbolInfo | null; calleeName: string; line: number }> {\n const limit = opts.limit ?? 50;\n const rows = db\n .prepare(\n `SELECT c.callee_name, c.callee_id, c.line,\n s.id as sid, s.name as sname, s.kind as skind, s.file_path as sfile,\n s.line_start as sline_start, s.line_end as sline_end, s.language as slang,\n s.signature as ssig, s.docstring as sdoc, s.parent_id as sparent, s.content_hash as shash\n FROM calls c\n LEFT JOIN symbols s ON s.id = c.callee_id\n WHERE c.caller_id = ?\n LIMIT ?`,\n )\n .all(symbolId, limit) as Array<{\n callee_name: string;\n callee_id: string | null;\n line: number;\n sid: string | null;\n sname: string | null;\n skind: string | null;\n sfile: string | null;\n sline_start: number | null;\n sline_end: number | null;\n slang: string | null;\n ssig: string | null;\n sdoc: string | null;\n sparent: string | null;\n shash: string | null;\n }>;\n\n return rows.map((r) => ({\n callee: r.sid\n ? {\n id: r.sid,\n name: r.sname ?? \"\",\n kind: r.skind ?? \"\",\n filePath: r.sfile ?? \"\",\n lineStart: r.sline_start ?? 0,\n lineEnd: r.sline_end ?? 0,\n language: r.slang ?? \"\",\n signature: r.ssig,\n docstring: r.sdoc,\n parentId: r.sparent,\n contentHash: r.shash ?? \"\",\n }\n : null,\n calleeName: r.callee_name,\n line: r.line,\n }));\n}\n\n/** Impact analysis: BFS from a symbol through the caller chain.\n * Returns all symbols that might be affected if the given symbol changes. */\nexport function impactAnalysis(\n db: Database,\n symbolId: string,\n opts: { maxDepth?: number } = {},\n): ImpactResult {\n const maxDepth = opts.maxDepth ?? 5;\n\n const rootRow = db.prepare(\"SELECT * FROM symbols WHERE id = ?\").get(symbolId) as\n | {\n id: string;\n name: string;\n kind: string;\n file_path: string;\n line_start: number;\n line_end: number;\n language: string;\n signature: string | null;\n docstring: string | null;\n parent_id: string | null;\n content_hash: string;\n }\n | undefined;\n\n if (!rootRow) {\n throw new Error(`Symbol not found: ${symbolId}`);\n }\n\n const root: SymbolInfo = {\n id: rootRow.id,\n name: rootRow.name,\n kind: rootRow.kind,\n filePath: rootRow.file_path,\n lineStart: rootRow.line_start,\n lineEnd: rootRow.line_end,\n language: rootRow.language,\n signature: rootRow.signature,\n docstring: rootRow.docstring,\n parentId: rootRow.parent_id,\n contentHash: rootRow.content_hash,\n };\n\n const affected: Array<{ symbol: SymbolInfo; depth: number; path: string[] }> = [];\n const visited = new Set<string>([symbolId]);\n\n // BFS through callers (who calls X → who calls them → ...)\n const queue: Array<{ id: string; depth: number; path: string[] }> = [\n { id: symbolId, depth: 0, path: [root.name] },\n ];\n\n while (queue.length > 0) {\n const item = queue.shift();\n if (!item) continue;\n const { id, depth, path } = item;\n if (depth >= maxDepth) continue;\n\n const callers = findCallers(db, id, { limit: 100 });\n for (const { caller } of callers) {\n if (visited.has(caller.id)) continue;\n visited.add(caller.id);\n const newPath = [...path, caller.name];\n affected.push({ symbol: caller, depth: depth + 1, path: newPath });\n queue.push({ id: caller.id, depth: depth + 1, path: newPath });\n }\n }\n\n return { rootSymbol: root, affected };\n}\n\n/** List symbols in a file or directory. */\nexport function listSymbols(\n db: Database,\n filePath: string,\n opts: { teamId?: string; kind?: string; limit?: number; repoPath?: string } = {},\n): SymbolInfo[] {\n const limit = opts.limit ?? 100;\n\n // Convert absolute path to relative if repoPath is provided\n let relPath = filePath;\n if (opts.repoPath) {\n try {\n relPath = relative(opts.repoPath, filePath).split(sep).join(\"/\");\n } catch {\n // If relative() fails, use the original path\n }\n }\n\n let sql = \"SELECT * FROM symbols WHERE file_path LIKE ?\";\n const params: unknown[] = [`${relPath}%`];\n if (opts.teamId !== undefined) {\n sql += \" AND team_id IS ?\";\n params.push(opts.teamId);\n }\n if (opts.repoPath !== undefined) {\n // Use LIKE prefix match so /path/to/src also matches repo_path /path/to\n sql += \" AND (repo_path = ? OR repo_path LIKE ?)\";\n params.push(opts.repoPath, `${opts.repoPath}%`);\n }\n if (opts.kind) {\n sql += \" AND kind = ?\";\n params.push(opts.kind);\n }\n sql += \" ORDER BY line_start LIMIT ?\";\n params.push(limit);\n\n const rows = db.prepare(sql).all(...params) as Array<{\n id: string;\n name: string;\n kind: string;\n file_path: string;\n line_start: number;\n line_end: number;\n language: string;\n signature: string | null;\n docstring: string | null;\n parent_id: string | null;\n content_hash: string;\n }>;\n\n return rows.map((r) => ({\n id: r.id,\n name: r.name,\n kind: r.kind,\n filePath: r.file_path,\n lineStart: r.line_start,\n lineEnd: r.line_end,\n language: r.language,\n signature: r.signature,\n docstring: r.docstring,\n parentId: r.parent_id,\n contentHash: r.content_hash,\n }));\n}\n"],"mappings":"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CA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AAAA,MACD,YAAY,oBAAI,IAAI;AAAA,QAClB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AAAA,MACD,QAAQ,oBAAI,IAAI;AAAA,QACd;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AAAA,MACD,MAAM,oBAAI,IAAI;AAAA,QACZ;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AAAA,IACH;AAAA;AAAA;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/codegraph/engine.ts"],"sourcesContent":["/**\n * CodeGraph engine: parse code, extract symbols, build call graph, impact analysis.\n *\n * Uses @kreuzberg/tree-sitter-language-pack for multi-language parsing.\n * Supports: TypeScript, JavaScript, Python, Go, Rust, Java, C, C++, C#.\n */\nimport { createHash } from \"node:crypto\";\nimport { readdirSync, readFileSync, statSync } from \"node:fs\";\nimport { extname, join, relative, sep } from \"node:path\";\nimport type { Database } from \"better-sqlite3\";\nimport { generateId } from \"../utils/ulid.js\";\n\n// Lazy-load the language pack (CommonJS interop)\nlet _pack: unknown = null;\nasync function getPack(): Promise<Record<string, unknown>> {\n if (!_pack) {\n const mod = await import(\"@kreuzberg/tree-sitter-language-pack\");\n // Handle both ESM default and CJS module.exports\n _pack = mod.default ?? mod;\n }\n return _pack as Record<string, unknown>;\n}\n\n/** Supported languages mapped to file extensions. */\nconst EXTENSION_MAP: Record<string, string> = {\n \".ts\": \"typescript\",\n \".tsx\": \"tsx\",\n \".js\": \"javascript\",\n \".jsx\": \"javascript\",\n \".mjs\": \"javascript\",\n \".cjs\": \"javascript\",\n \".py\": \"python\",\n \".go\": \"go\",\n \".rs\": \"rust\",\n \".java\": \"java\",\n \".c\": \"c\",\n \".h\": \"c\",\n \".cpp\": \"cpp\",\n \".cc\": \"cpp\",\n \".cxx\": \"cpp\",\n \".hpp\": \"cpp\",\n \".cs\": \"csharp\",\n};\n\n/** Languages we support for symbol extraction. */\nexport const SUPPORTED_LANGUAGES = new Set(Object.values(EXTENSION_MAP));\n\n/** Detect language from file extension. Returns null if unsupported. */\nexport function detectLanguage(filePath: string): string | null {\n const ext = extname(filePath).toLowerCase();\n return EXTENSION_MAP[ext] ?? null;\n}\n\n/** A symbol extracted from code. */\nexport interface SymbolInfo {\n id: string;\n name: string;\n kind: string;\n filePath: string;\n lineStart: number;\n lineEnd: number;\n language: string;\n signature: string | null;\n docstring: string | null;\n parentId: string | null;\n contentHash: string;\n}\n\n/** A call relationship. */\nexport interface CallInfo {\n callerId: string;\n calleeName: string;\n calleeId: string | null;\n line: number;\n kind: string;\n callType?: string;\n}\n\n/** An import relationship. */\nexport interface ImportInfo {\n filePath: string;\n symbolName: string;\n sourcePath: string | null;\n line: number;\n language: string;\n}\n\n/** Result of indexing a file. */\nexport interface IndexResult {\n file: string;\n language: string;\n symbols: number;\n calls: number;\n imports: number;\n skipped: boolean;\n}\n\n/** Impact analysis result. */\nexport interface ImpactResult {\n rootSymbol: SymbolInfo;\n affected: Array<{ symbol: SymbolInfo; depth: number; path: string[] }>;\n}\n\n/** Parse a file and extract symbols, calls, and imports. */\nexport async function parseFile(\n filePath: string,\n repoPath: string,\n): Promise<{ symbols: SymbolInfo[]; calls: CallInfo[]; imports: ImportInfo[] } | null> {\n const language = detectLanguage(filePath);\n if (!language) return null;\n\n const pack = (await getPack()) as {\n hasLanguage: (lang: string) => boolean;\n process: (\n source: string,\n opts: { language: string },\n ) => {\n structure: Array<{\n kind?: string;\n name?: string;\n span?: { startLine?: number; endLine?: number };\n signature?: string;\n docComment?: string;\n children?: Array<{\n kind?: string;\n name?: string;\n span?: { startLine?: number; endLine?: number };\n signature?: string;\n docComment?: string;\n }>;\n }>;\n imports: Array<{\n items?: string[];\n source?: string;\n span?: { startLine?: number };\n }>;\n } | null;\n };\n if (!pack.hasLanguage(language)) return null;\n\n let source: string;\n try {\n source = readFileSync(filePath, \"utf-8\");\n } catch {\n return null;\n }\n\n // Skip files that are too large — tree-sitter parsing + regex extraction\n // scales O(n) with file size, and very large files are usually generated/vendored\n const MAX_FILE_LINES = 3000;\n const MAX_FILE_BYTES = 200_000; // 200KB\n if (source.length > MAX_FILE_BYTES || source.split(\"\\n\").length > MAX_FILE_LINES) {\n return null;\n }\n\n const result = pack.process(source, { language });\n if (!result) return null;\n\n const relPath = relative(repoPath, filePath).split(sep).join(\"/\");\n const symbols: SymbolInfo[] = [];\n const calls: CallInfo[] = [];\n const imports: ImportInfo[] = [];\n\n // Cache source lines once — used for offset calculation in extractSymbols\n const sourceLines = source.split(\"\\n\");\n // Precompute cumulative line start offsets for O(1) line→offset lookup\n const lineOffsets: number[] = [0];\n for (let i = 0; i < sourceLines.length; i++) {\n lineOffsets.push(lineOffsets[i] + sourceLines[i].length + 1); // +1 for \\n\n }\n\n // Extract symbols from structure\n const extractSymbols = (\n items: Array<{\n kind?: string;\n name?: string;\n span?: { startLine?: number; endLine?: number };\n signature?: string;\n docComment?: string;\n children?: Array<{\n kind?: string;\n name?: string;\n span?: { startLine?: number; endLine?: number };\n signature?: string;\n docComment?: string;\n }>;\n }>,\n parentId: string | null,\n ) => {\n for (const item of items) {\n if (!item.name) continue;\n const id = generateId();\n const lineStart = (item.span?.startLine ?? 0) + 1; // 1-indexed\n const lineEnd = (item.span?.endLine ?? lineStart) + 1;\n // Use cached lineOffsets instead of source.split(\"\\n\") per symbol\n const bodyStart = item.span?.startLine !== undefined ? lineOffsets[item.span.startLine] : 0;\n const bodyEnd =\n item.span?.endLine !== undefined ? lineOffsets[item.span.endLine + 1] - 1 : source.length;\n const bodyText = source.slice(bodyStart, bodyEnd);\n symbols.push({\n id,\n name: item.name,\n kind: item.kind ?? \"unknown\",\n filePath: relPath,\n lineStart,\n lineEnd,\n language,\n signature: item.signature ?? null,\n docstring: item.docComment ?? null,\n parentId,\n contentHash: createHash(\"sha256\")\n .update(item.name + relPath + lineStart)\n .digest(\"hex\"),\n });\n\n // Extract calls within this symbol's body — single-pass on body text\n // Captures: foo(), obj.method(), <Component/>, Class.create()\n // Uses cached bodyText + offset→line map (no per-line regex)\n const bodyStartLine = lineStart;\n\n // Build offset→line map for this body using cached lineOffsets\n const offsetToLine = (offset: number): number => {\n // offset is relative to bodyText which starts at bodyStart in source\n const sourceOffset = bodyStart + offset;\n // Binary search in lineOffsets\n let lo = 0,\n hi = lineOffsets.length - 1;\n while (lo < hi) {\n const mid = (lo + hi + 1) >> 1;\n if (lineOffsets[mid] <= sourceOffset) lo = mid;\n else hi = mid - 1;\n }\n return lo + 1; // 1-indexed\n };\n\n // Track offsets already captured to avoid duplicates\n const capturedOffsets = new Set<number>();\n\n // Pass 1: JSX components <Component> — capitalized identifiers\n const jsxRegex = /<([A-Z][a-zA-Z0-9_$]*)\\b/g;\n let jMatch: RegExpExecArray | null;\n while ((jMatch = jsxRegex.exec(bodyText)) !== null) {\n const calleeName = jMatch[1];\n const offset = jMatch.index;\n if (!isKeywordOrSelf(calleeName, item.name) && !capturedOffsets.has(offset)) {\n calls.push({\n callerId: id,\n calleeName,\n calleeId: null,\n line: offsetToLine(offset),\n kind: \"call\",\n callType: \"jsx\",\n });\n capturedOffsets.add(offset);\n }\n }\n\n // Pass 2: Method calls (obj.method) — captures full qualified name\n const methodCallRegex = /\\b([a-zA-Z_$][a-zA-Z0-9_$]*)\\.([a-zA-Z_$][a-zA-Z0-9_$]*)\\s*\\(/g;\n let mMatch: RegExpExecArray | null;\n while ((mMatch = methodCallRegex.exec(bodyText)) !== null) {\n const receiver = mMatch[1];\n const methodName = mMatch[2];\n const calleeName = `${receiver}.${methodName}`;\n const offset = mMatch.index;\n if (\n !isKeywordOrSelf(methodName, item.name) &&\n !isKeywordOrSelf(receiver, item.name) &&\n !isStdlibCall(calleeName, language) &&\n !capturedOffsets.has(offset)\n ) {\n calls.push({\n callerId: id,\n calleeName,\n calleeId: null,\n line: offsetToLine(offset),\n kind: \"call\",\n callType: \"method\",\n });\n capturedOffsets.add(offset);\n }\n }\n\n // Pass 3: Simple calls (foo) — skip if offset already captured or stdlib\n const simpleCallRegex = /\\b([a-zA-Z_$][a-zA-Z0-9_$]*)\\s*\\(/g;\n let match: RegExpExecArray | null;\n while ((match = simpleCallRegex.exec(bodyText)) !== null) {\n const calleeName = match[1];\n const offset = match.index;\n if (\n !isKeywordOrSelf(calleeName, item.name) &&\n !isStdlibCall(calleeName, language) &&\n !capturedOffsets.has(offset)\n ) {\n calls.push({\n callerId: id,\n calleeName,\n calleeId: null,\n line: offsetToLine(offset),\n kind: \"call\",\n callType: \"direct\",\n });\n capturedOffsets.add(offset);\n }\n }\n\n // Recurse into children\n if (item.children && item.children.length > 0) {\n extractSymbols(item.children, id);\n }\n }\n };\n\n extractSymbols(result.structure ?? [], null);\n\n // Extract imports\n for (const imp of result.imports ?? []) {\n imports.push({\n filePath: relPath,\n symbolName: imp.items?.join(\", \") ?? imp.source ?? \"unknown\",\n sourcePath: imp.source ?? null,\n line: (imp.span?.startLine ?? 0) + 1,\n language,\n });\n }\n\n return { symbols, calls, imports };\n}\n\n/** Check if a name is a language keyword or the symbol itself (should be skipped in call extraction). */\nfunction isKeywordOrSelf(name: string, symbolName: string): boolean {\n if (name === symbolName) return true;\n const keywords = new Set([\n \"if\",\n \"for\",\n \"while\",\n \"switch\",\n \"return\",\n \"function\",\n \"def\",\n \"func\",\n \"fn\",\n \"print\",\n \"console\",\n \"require\",\n \"import\",\n \"export\",\n \"class\",\n \"struct\",\n \"enum\",\n \"interface\",\n \"type\",\n \"const\",\n \"let\",\n \"var\",\n \"new\",\n \"delete\",\n \"typeof\",\n \"instanceof\",\n \"void\",\n \"in\",\n \"of\",\n \"await\",\n \"async\",\n \"yield\",\n \"throw\",\n \"try\",\n \"catch\",\n \"finally\",\n \"break\",\n \"continue\",\n \"do\",\n \"else\",\n \"case\",\n \"default\",\n \"extends\",\n \"implements\",\n \"super\",\n \"this\",\n \"self\",\n \"true\",\n \"false\",\n \"null\",\n \"undefined\",\n \"nil\",\n \"None\",\n \"True\",\n \"False\",\n \"println\",\n \"printf\",\n \"fmt\",\n \"err\",\n \"panic\",\n \"recover\",\n ]);\n return keywords.has(name);\n}\n\n/** Stdlib prefixes per language — calls to these are skipped (not indexed). */\nconst STDLIB_PREFIXES: Record<string, Set<string>> = {\n go: new Set([\n \"fmt\",\n \"json\",\n \"os\",\n \"io\",\n \"strings\",\n \"strconv\",\n \"time\",\n \"errors\",\n \"sync\",\n \"context\",\n \"path\",\n \"filepath\",\n \"sort\",\n \"bytes\",\n \"bufio\",\n \"encoding\",\n \"net\",\n \"http\",\n \"url\",\n \"regexp\",\n \"math\",\n \"log\",\n \"reflect\",\n \"runtime\",\n \"unsafe\",\n \"atomic\",\n \"crypto\",\n \"hash\",\n \"base64\",\n \"hex\",\n \"ioutil\",\n \"filepath\",\n \"unicode\",\n \"testing\",\n \"flag\",\n \"env\",\n ]),\n typescript: new Set([\n \"console\",\n \"JSON\",\n \"Math\",\n \"Date\",\n \"Object\",\n \"Array\",\n \"String\",\n \"Number\",\n \"Boolean\",\n \"Promise\",\n \"Symbol\",\n \"Map\",\n \"Set\",\n \"WeakMap\",\n \"WeakSet\",\n \"Error\",\n \"RegExp\",\n \"Buffer\",\n \"process\",\n \"setTimeout\",\n \"setInterval\",\n \"clearTimeout\",\n \"clearInterval\",\n \"fetch\",\n \"URL\",\n \"URLSearchParams\",\n \"FormData\",\n \"Headers\",\n \"Request\",\n \"Response\",\n \"AbortController\",\n \"Event\",\n \"EventTarget\",\n \"CustomEvent\",\n \"TextEncoder\",\n \"TextDecoder\",\n \"crypto\",\n \"performance\",\n \"queueMicrotask\",\n \"atob\",\n \"btoa\",\n \"parseInt\",\n \"parseFloat\",\n \"isNaN\",\n \"isFinite\",\n \"encodeURIComponent\",\n \"decodeURIComponent\",\n \"encodeURI\",\n \"decodeURI\",\n ]),\n javascript: new Set([\n \"console\",\n \"JSON\",\n \"Math\",\n \"Date\",\n \"Object\",\n \"Array\",\n \"String\",\n \"Number\",\n \"Boolean\",\n \"Promise\",\n \"Symbol\",\n \"Map\",\n \"Set\",\n \"WeakMap\",\n \"WeakSet\",\n \"Error\",\n \"RegExp\",\n \"Buffer\",\n \"process\",\n \"setTimeout\",\n \"setInterval\",\n \"clearTimeout\",\n \"clearInterval\",\n \"fetch\",\n \"URL\",\n \"URLSearchParams\",\n \"FormData\",\n \"Headers\",\n \"Request\",\n \"Response\",\n \"AbortController\",\n \"Event\",\n \"EventTarget\",\n \"CustomEvent\",\n \"TextEncoder\",\n \"TextDecoder\",\n \"crypto\",\n \"performance\",\n \"queueMicrotask\",\n \"atob\",\n \"btoa\",\n \"parseInt\",\n \"parseFloat\",\n \"isNaN\",\n \"isFinite\",\n \"encodeURIComponent\",\n \"decodeURIComponent\",\n \"encodeURI\",\n \"decodeURI\",\n ]),\n python: new Set([\n \"print\",\n \"len\",\n \"range\",\n \"str\",\n \"int\",\n \"float\",\n \"bool\",\n \"list\",\n \"dict\",\n \"set\",\n \"tuple\",\n \"type\",\n \"isinstance\",\n \"issubclass\",\n \"id\",\n \"hash\",\n \"dir\",\n \"vars\",\n \"globals\",\n \"locals\",\n \"exec\",\n \"eval\",\n \"compile\",\n \"open\",\n \"input\",\n \"repr\",\n \"format\",\n \"chr\",\n \"ord\",\n \"hex\",\n \"oct\",\n \"bin\",\n \"abs\",\n \"min\",\n \"max\",\n \"sum\",\n \"round\",\n \"pow\",\n \"divmod\",\n \"sorted\",\n \"reversed\",\n \"enumerate\",\n \"zip\",\n \"map\",\n \"filter\",\n \"any\",\n \"all\",\n \"next\",\n \"iter\",\n \"getattr\",\n \"setattr\",\n \"hasattr\",\n \"delattr\",\n \"property\",\n \"staticmethod\",\n \"classmethod\",\n \"super\",\n \"object\",\n \"Exception\",\n \"ValueError\",\n \"TypeError\",\n \"KeyError\",\n \"IndexError\",\n \"AttributeError\",\n \"RuntimeError\",\n \"StopIteration\",\n \"os\",\n \"sys\",\n \"json\",\n \"re\",\n \"time\",\n \"datetime\",\n \"pathlib\",\n \"typing\",\n \"collections\",\n \"itertools\",\n \"functools\",\n \"subprocess\",\n \"argparse\",\n \"logging\",\n \"unittest\",\n \"asyncio\",\n \"threading\",\n \"multiprocessing\",\n \"pickle\",\n \"shutil\",\n \"tempfile\",\n \"glob\",\n \"fnmatch\",\n \"csv\",\n \"io\",\n \"base64\",\n \"hashlib\",\n \"hmac\",\n \"secrets\",\n \"uuid\",\n \"copy\",\n \"math\",\n \"random\",\n \"statistics\",\n \"decimal\",\n \"fractions\",\n \"sqlite3\",\n ]),\n rust: new Set([\n \"println\",\n \"print\",\n \"eprintln\",\n \"eprint\",\n \"format\",\n \"vec\",\n \"String\",\n \"Vec\",\n \"Option\",\n \"Result\",\n \"Some\",\n \"None\",\n \"Ok\",\n \"Err\",\n \"Box\",\n \"Rc\",\n \"Arc\",\n \"RefCell\",\n \"Cell\",\n \"Mutex\",\n \"RwLock\",\n \"HashMap\",\n \"HashSet\",\n \"BTreeMap\",\n \"BTreeSet\",\n \"VecDeque\",\n \"LinkedList\",\n \"std\",\n \"core\",\n \"alloc\",\n \"macro\",\n \"todo\",\n \"unimplemented\",\n \"panic\",\n \"assert\",\n \"assert_eq\",\n \"assert_ne\",\n \"debug_assert\",\n \"debug_assert_eq\",\n \"cfg\",\n \"env\",\n \"include\",\n \"concat\",\n \"stringify\",\n \"file\",\n \"line\",\n \"module_path\",\n \"column\",\n \"format_args\",\n \"write\",\n \"writeln\",\n ]),\n};\n\n/** Check if a callee name is a stdlib call for the given language. */\nfunction isStdlibCall(calleeName: string, language: string): boolean {\n const prefixes = STDLIB_PREFIXES[language];\n if (!prefixes) return false;\n // Check direct match (e.g. \"println\", \"len\")\n if (prefixes.has(calleeName)) return true;\n // Check prefix match (e.g. \"fmt.Printf\" → prefix \"fmt\")\n const dotIdx = calleeName.indexOf(\".\");\n if (dotIdx > 0) {\n const prefix = calleeName.slice(0, dotIdx);\n if (prefixes.has(prefix)) return true;\n }\n return false;\n}\n\n/** Index a single file into the database. */\nexport async function indexFile(\n db: Database,\n filePath: string,\n repoPath: string,\n teamId: string | null,\n): Promise<IndexResult> {\n const language = detectLanguage(filePath);\n if (!language) {\n return { file: filePath, language: \"unknown\", symbols: 0, calls: 0, imports: 0, skipped: true };\n }\n\n const parsed = await parseFile(filePath, repoPath);\n if (!parsed) {\n return { file: filePath, language, symbols: 0, calls: 0, imports: 0, skipped: true };\n }\n\n const relPath = relative(repoPath, filePath).split(sep).join(\"/\");\n const now = Date.now();\n\n // Delete existing symbols for this file\n const existingIds = db\n .prepare(\"SELECT id FROM symbols WHERE file_path = ? AND team_id IS ?\")\n .all(relPath, teamId) as { id: string }[];\n if (existingIds.length > 0) {\n const placeholders = existingIds.map(() => \"?\").join(\",\");\n db.prepare(`DELETE FROM calls WHERE caller_id IN (${placeholders})`).run(\n ...existingIds.map((e) => e.id),\n );\n db.prepare(\"DELETE FROM symbols WHERE file_path = ? AND team_id IS ?\").run(relPath, teamId);\n }\n db.prepare(\"DELETE FROM imports WHERE file_path = ? AND team_id IS ?\").run(relPath, teamId);\n\n // Insert symbols\n const symbolStmt = db.prepare(\n `INSERT INTO symbols (id, name, kind, file_path, line_start, line_end, language, signature, docstring, parent_id, team_id, repo_path, content_hash, module_path, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n );\n const modulePath = relPath.replace(\n /\\.(ts|tsx|js|jsx|mjs|cjs|py|go|rs|java|c|cpp|cc|cxx|hpp|cs)$/,\n \"\",\n );\n for (const s of parsed.symbols) {\n symbolStmt.run(\n s.id,\n s.name,\n s.kind,\n s.filePath,\n s.lineStart,\n s.lineEnd,\n s.language,\n s.signature,\n s.docstring,\n s.parentId,\n teamId,\n repoPath,\n s.contentHash,\n modulePath,\n now,\n now,\n );\n }\n\n // Insert calls (callee_id resolved later by 6-strategy cascade in indexDirectory)\n const callStmt = db.prepare(\n `INSERT INTO calls (caller_id, callee_name, callee_id, line, kind, call_type, team_id) VALUES (?, ?, ?, ?, ?, ?, ?)`,\n );\n for (const c of parsed.calls) {\n callStmt.run(\n c.callerId,\n c.calleeName,\n null, // Will be resolved by resolveAllCalls() in indexDirectory\n c.line,\n c.kind,\n (c as { callType?: string }).callType ?? \"direct\",\n teamId,\n );\n }\n\n // Insert imports\n const importStmt = db.prepare(\n `INSERT INTO imports (file_path, symbol_name, source_path, line, language, team_id, repo_path) VALUES (?, ?, ?, ?, ?, ?, ?)`,\n );\n for (const imp of parsed.imports) {\n importStmt.run(\n imp.filePath,\n imp.symbolName,\n imp.sourcePath,\n imp.line,\n imp.language,\n teamId,\n repoPath,\n );\n }\n\n return {\n file: relPath,\n language,\n symbols: parsed.symbols.length,\n calls: parsed.calls.length,\n imports: parsed.imports.length,\n skipped: false,\n };\n}\n\n/** Index a directory recursively. */\nexport async function indexDirectory(\n db: Database,\n dirPath: string,\n repoPath: string,\n teamId: string | null,\n maxFiles = 10000,\n): Promise<IndexResult[]> {\n const results: IndexResult[] = [];\n const files: string[] = [];\n\n const walk = (dir: string) => {\n if (files.length >= maxFiles) return;\n let entries: string[];\n try {\n entries = readdirSync(dir);\n } catch {\n return;\n }\n for (const entry of entries) {\n if (files.length >= maxFiles) return;\n const fullPath = join(dir, entry);\n let stat: ReturnType<typeof statSync>;\n try {\n stat = statSync(fullPath);\n } catch {\n continue;\n }\n if (stat.isDirectory()) {\n // Skip common ignore dirs\n if (\n entry === \"node_modules\" ||\n entry === \".git\" ||\n entry === \"dist\" ||\n entry === \"build\" ||\n entry === \"target\" ||\n entry === \"__pycache__\" ||\n entry === \".next\" ||\n entry === \"vendor\" ||\n entry === \".venv\" ||\n entry.startsWith(\".\")\n )\n continue;\n walk(fullPath);\n } else if (stat.isFile()) {\n if (detectLanguage(fullPath)) {\n files.push(fullPath);\n }\n }\n }\n };\n\n walk(dirPath);\n\n const indexedSymbolIds = new Set<string>();\n for (const file of files) {\n const result = await indexFile(db, file, repoPath, teamId);\n results.push(result);\n }\n\n // Collect symbol IDs from the just-indexed files — resolveAllCalls will only\n // resolve calls whose caller_id is in this set, avoiding re-processing 25K+\n // historical calls (fuzzy strategy is O(n²)).\n if (results.length > 0) {\n const indexedFiles = results.filter((r) => !r.skipped).map((r) => r.file);\n for (let i = 0; i < indexedFiles.length; i += 500) {\n const chunk = indexedFiles.slice(i, i + 500);\n const placeholders = chunk.map(() => \"?\").join(\",\");\n const rows = db\n .prepare(`SELECT id FROM symbols WHERE file_path IN (${placeholders})`)\n .all(...chunk) as { id: string }[];\n for (const r of rows) {\n indexedSymbolIds.add(r.id);\n }\n }\n }\n\n // Resolve callee IDs using 6-strategy cascade (import-map, same-module, unique-name, suffix, fuzzy)\n // Adapted from Codebase-Memory (arXiv:2603.27277)\n const { resolveAllCalls } = await import(\"./resolver.js\");\n const stats = resolveAllCalls(db, indexedSymbolIds);\n if (stats.total > 0) {\n console.error(\n `[remem-mcp] indexDirectory: resolved ${stats.resolved}/${stats.total} calls` +\n (Object.keys(stats.byStrategy).length > 0 ? ` (${JSON.stringify(stats.byStrategy)})` : \"\"),\n );\n }\n\n return results;\n}\n\n/** Search symbols by name or pattern. */\nexport function searchSymbols(\n db: Database,\n query: string,\n opts: {\n teamId?: string;\n kind?: string;\n language?: string;\n limit?: number;\n repoPath?: string;\n } = {},\n): SymbolInfo[] {\n const limit = opts.limit ?? 20;\n const pattern = `%${query}%`;\n let sql = \"SELECT * FROM symbols WHERE name LIKE ?\";\n const params: unknown[] = [pattern];\n if (opts.teamId !== undefined) {\n sql += \" AND team_id IS ?\";\n params.push(opts.teamId);\n }\n if (opts.repoPath !== undefined) {\n // Use LIKE prefix match so /path/to/src also matches repo_path /path/to\n sql += \" AND (repo_path = ? OR repo_path LIKE ?)\";\n params.push(opts.repoPath, `${opts.repoPath}%`);\n }\n if (opts.kind) {\n sql += \" AND kind = ?\";\n params.push(opts.kind);\n }\n if (opts.language) {\n sql += \" AND language = ?\";\n params.push(opts.language);\n }\n sql += \" LIMIT ?\";\n params.push(limit);\n\n const rows = db.prepare(sql).all(...params) as Array<{\n id: string;\n name: string;\n kind: string;\n file_path: string;\n line_start: number;\n line_end: number;\n language: string;\n signature: string | null;\n docstring: string | null;\n parent_id: string | null;\n content_hash: string;\n }>;\n\n return rows.map((r) => ({\n id: r.id,\n name: r.name,\n kind: r.kind,\n filePath: r.file_path,\n lineStart: r.line_start,\n lineEnd: r.line_end,\n language: r.language,\n signature: r.signature,\n docstring: r.docstring,\n parentId: r.parent_id,\n contentHash: r.content_hash,\n }));\n}\n\n/** Find all callers of a symbol (who calls X?). */\nexport function findCallers(\n db: Database,\n symbolId: string,\n opts: { limit?: number } = {},\n): Array<{ caller: SymbolInfo; line: number }> {\n const limit = opts.limit ?? 50;\n const rows = db\n .prepare(\n `SELECT s.*, c.line as call_line\n FROM calls c\n JOIN symbols s ON s.id = c.caller_id\n WHERE c.callee_id = ? OR c.callee_name = (SELECT name FROM symbols WHERE id = ?)\n LIMIT ?`,\n )\n .all(symbolId, symbolId, limit) as Array<{\n id: string;\n name: string;\n kind: string;\n file_path: string;\n line_start: number;\n line_end: number;\n language: string;\n signature: string | null;\n docstring: string | null;\n parent_id: string | null;\n content_hash: string;\n call_line: number;\n }>;\n\n return rows.map((r) => ({\n caller: {\n id: r.id,\n name: r.name,\n kind: r.kind,\n filePath: r.file_path,\n lineStart: r.line_start,\n lineEnd: r.line_end,\n language: r.language,\n signature: r.signature,\n docstring: r.docstring,\n parentId: r.parent_id,\n contentHash: r.content_hash,\n },\n line: r.call_line,\n }));\n}\n\n/** Find all callees of a symbol (X calls whom?). */\nexport function findCallees(\n db: Database,\n symbolId: string,\n opts: { limit?: number } = {},\n): Array<{ callee: SymbolInfo | null; calleeName: string; line: number }> {\n const limit = opts.limit ?? 50;\n const rows = db\n .prepare(\n `SELECT c.callee_name, c.callee_id, c.line,\n s.id as sid, s.name as sname, s.kind as skind, s.file_path as sfile,\n s.line_start as sline_start, s.line_end as sline_end, s.language as slang,\n s.signature as ssig, s.docstring as sdoc, s.parent_id as sparent, s.content_hash as shash\n FROM calls c\n LEFT JOIN symbols s ON s.id = c.callee_id\n WHERE c.caller_id = ?\n LIMIT ?`,\n )\n .all(symbolId, limit) as Array<{\n callee_name: string;\n callee_id: string | null;\n line: number;\n sid: string | null;\n sname: string | null;\n skind: string | null;\n sfile: string | null;\n sline_start: number | null;\n sline_end: number | null;\n slang: string | null;\n ssig: string | null;\n sdoc: string | null;\n sparent: string | null;\n shash: string | null;\n }>;\n\n return rows.map((r) => ({\n callee: r.sid\n ? {\n id: r.sid,\n name: r.sname ?? \"\",\n kind: r.skind ?? \"\",\n filePath: r.sfile ?? \"\",\n lineStart: r.sline_start ?? 0,\n lineEnd: r.sline_end ?? 0,\n language: r.slang ?? \"\",\n signature: r.ssig,\n docstring: r.sdoc,\n parentId: r.sparent,\n contentHash: r.shash ?? \"\",\n }\n : null,\n calleeName: r.callee_name,\n line: r.line,\n }));\n}\n\n/** Impact analysis: BFS from a symbol through the caller chain.\n * Returns all symbols that might be affected if the given symbol changes. */\nexport function impactAnalysis(\n db: Database,\n symbolId: string,\n opts: { maxDepth?: number } = {},\n): ImpactResult {\n const maxDepth = opts.maxDepth ?? 5;\n\n const rootRow = db.prepare(\"SELECT * FROM symbols WHERE id = ?\").get(symbolId) as\n | {\n id: string;\n name: string;\n kind: string;\n file_path: string;\n line_start: number;\n line_end: number;\n language: string;\n signature: string | null;\n docstring: string | null;\n parent_id: string | null;\n content_hash: string;\n }\n | undefined;\n\n if (!rootRow) {\n throw new Error(`Symbol not found: ${symbolId}`);\n }\n\n const root: SymbolInfo = {\n id: rootRow.id,\n name: rootRow.name,\n kind: rootRow.kind,\n filePath: rootRow.file_path,\n lineStart: rootRow.line_start,\n lineEnd: rootRow.line_end,\n language: rootRow.language,\n signature: rootRow.signature,\n docstring: rootRow.docstring,\n parentId: rootRow.parent_id,\n contentHash: rootRow.content_hash,\n };\n\n const affected: Array<{ symbol: SymbolInfo; depth: number; path: string[] }> = [];\n const visited = new Set<string>([symbolId]);\n\n // BFS through callers (who calls X → who calls them → ...)\n const queue: Array<{ id: string; depth: number; path: string[] }> = [\n { id: symbolId, depth: 0, path: [root.name] },\n ];\n\n while (queue.length > 0) {\n const item = queue.shift();\n if (!item) continue;\n const { id, depth, path } = item;\n if (depth >= maxDepth) continue;\n\n const callers = findCallers(db, id, { limit: 100 });\n for (const { caller } of callers) {\n if (visited.has(caller.id)) continue;\n visited.add(caller.id);\n const newPath = [...path, caller.name];\n affected.push({ symbol: caller, depth: depth + 1, path: newPath });\n queue.push({ id: caller.id, depth: depth + 1, path: newPath });\n }\n }\n\n return { rootSymbol: root, affected };\n}\n\n/** List symbols in a file or directory. */\nexport function listSymbols(\n db: Database,\n filePath: string,\n opts: { teamId?: string; kind?: string; limit?: number; repoPath?: string } = {},\n): SymbolInfo[] {\n const limit = opts.limit ?? 100;\n\n // Convert absolute path to relative if repoPath is provided\n let relPath = filePath;\n if (opts.repoPath) {\n try {\n relPath = relative(opts.repoPath, filePath).split(sep).join(\"/\");\n } catch {\n // If relative() fails, use the original path\n }\n }\n\n let sql = \"SELECT * FROM symbols WHERE file_path LIKE ?\";\n const params: unknown[] = [`${relPath}%`];\n if (opts.teamId !== undefined) {\n sql += \" AND team_id IS ?\";\n params.push(opts.teamId);\n }\n if (opts.repoPath !== undefined) {\n // Use LIKE prefix match so /path/to/src also matches repo_path /path/to\n sql += \" AND (repo_path = ? OR repo_path LIKE ?)\";\n params.push(opts.repoPath, `${opts.repoPath}%`);\n }\n if (opts.kind) {\n sql += \" AND kind = ?\";\n params.push(opts.kind);\n }\n sql += \" ORDER BY line_start LIMIT ?\";\n params.push(limit);\n\n const rows = db.prepare(sql).all(...params) as Array<{\n id: string;\n name: string;\n kind: string;\n file_path: string;\n line_start: number;\n line_end: number;\n language: string;\n signature: string | null;\n docstring: string | null;\n parent_id: string | null;\n content_hash: string;\n }>;\n\n return rows.map((r) => ({\n id: r.id,\n name: r.name,\n kind: r.kind,\n filePath: r.file_path,\n lineStart: r.line_start,\n lineEnd: r.line_end,\n language: r.language,\n signature: r.signature,\n docstring: r.docstring,\n parentId: r.parent_id,\n contentHash: r.content_hash,\n }));\n}\n"],"mappings":"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QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AAAA,MACD,YAAY,oBAAI,IAAI;AAAA,QAClB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AAAA,MACD,YAAY,oBAAI,IAAI;AAAA,QAClB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AAAA,MACD,QAAQ,oBAAI,IAAI;AAAA,QACd;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AAAA,MACD,MAAM,oBAAI,IAAI;AAAA,QACZ;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AAAA,IACH;AAAA;AAAA;","names":[]}
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
listSymbols,
|
|
11
11
|
parseFile,
|
|
12
12
|
searchSymbols
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-YU7WBJU5.js";
|
|
14
14
|
import "./chunk-XJGDYQ34.js";
|
|
15
15
|
import "./chunk-ONQHLUGM.js";
|
|
16
16
|
init_engine();
|
|
@@ -26,4 +26,4 @@ export {
|
|
|
26
26
|
parseFile,
|
|
27
27
|
searchSymbols
|
|
28
28
|
};
|
|
29
|
-
//# sourceMappingURL=engine-
|
|
29
|
+
//# sourceMappingURL=engine-S47HHGAO.js.map
|