kirograph 0.20.1 → 0.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/README.md +4 -3
  2. package/dist/bin/commands/data.js +52 -0
  3. package/dist/bin/commands/data.js.map +2 -2
  4. package/dist/bin/commands/docs.js +2 -1
  5. package/dist/bin/commands/docs.js.map +2 -2
  6. package/dist/bin/commands/gain.js +21 -1
  7. package/dist/bin/commands/gain.js.map +2 -2
  8. package/dist/bin/commands/status.js +23 -1
  9. package/dist/bin/commands/status.js.map +2 -2
  10. package/dist/bin/installer/config-prompt.js +30 -1
  11. package/dist/bin/installer/config-prompt.js.map +2 -2
  12. package/dist/bin/installer/index.js +108 -0
  13. package/dist/bin/installer/index.js.map +2 -2
  14. package/dist/bin/kirograph.js +1 -1
  15. package/dist/config.js +19 -2
  16. package/dist/config.js.map +2 -2
  17. package/dist/core/pipeline.js +3 -1
  18. package/dist/core/pipeline.js.map +2 -2
  19. package/dist/data/indexer.js +4 -4
  20. package/dist/data/indexer.js.map +2 -2
  21. package/dist/data/linker.js +9 -5
  22. package/dist/data/linker.js.map +2 -2
  23. package/dist/data/linker.test.js +60 -0
  24. package/dist/data/linker.test.js.map +7 -0
  25. package/dist/data/parsers/__fixtures__/pdf-inspector-stub.js +41 -0
  26. package/dist/data/parsers/__fixtures__/pdf-inspector-stub.js.map +7 -0
  27. package/dist/data/parsers/index.js +3 -1
  28. package/dist/data/parsers/index.js.map +2 -2
  29. package/dist/data/parsers/pdf.js +95 -0
  30. package/dist/data/parsers/pdf.js.map +7 -0
  31. package/dist/data/parsers/pdf.test.js +125 -0
  32. package/dist/data/parsers/pdf.test.js.map +7 -0
  33. package/dist/data/queries.js +39 -2
  34. package/dist/data/queries.js.map +2 -2
  35. package/dist/data/types.js.map +1 -1
  36. package/dist/db/data-schema.sql +2 -1
  37. package/dist/db/database.js +7 -0
  38. package/dist/db/database.js.map +2 -2
  39. package/dist/docs/indexer.js +2 -1
  40. package/dist/docs/indexer.js.map +2 -2
  41. package/dist/docs/queries.js +2 -1
  42. package/dist/docs/queries.js.map +2 -2
  43. package/dist/docs/vectors.js +46 -5
  44. package/dist/docs/vectors.js.map +2 -2
  45. package/dist/index.js +1 -0
  46. package/dist/index.js.map +2 -2
  47. package/dist/mcp/tools.js +1 -1
  48. package/dist/mcp/tools.js.map +2 -2
  49. package/dist/memory/index.js +2 -1
  50. package/dist/memory/index.js.map +2 -2
  51. package/dist/memory/vectors.js +52 -8
  52. package/dist/memory/vectors.js.map +3 -3
  53. package/dist/types.js.map +2 -2
  54. package/dist/vectors/index.js +66 -3
  55. package/dist/vectors/index.js.map +2 -2
  56. package/dist/vectors/turbovec-index.js +189 -0
  57. package/dist/vectors/turbovec-index.js.map +7 -0
  58. package/package.json +7 -1
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/core/pipeline.ts"],
4
- "sourcesContent": ["/**\n * IndexPipeline \u2014 full-index and incremental-sync pipelines.\n *\n * Owns the two heavy workflows:\n * - indexAll(): scan all files, extract, store, resolve, detect frameworks,\n * generate embeddings, analyze architecture.\n * - sync(): detect changed files via git (or full scan fallback),\n * re-extract only what changed, then run the same tail pipeline.\n *\n * Everything that touches the filesystem or sub-systems is injected via the\n * constructor, keeping this class testable and free of global state.\n */\n\nimport * as path from 'path';\nimport * as fs from 'fs';\nimport { GraphDatabase } from '../db/database';\nimport { scanDirectory, hashContent, getChangedFiles, shouldIncludeFile } from '../sync/index';\nimport { extractFile } from '../extraction/extractor';\nimport { clearParserCache, initGrammars, hasWasmGrammar } from '../extraction/grammars';\nimport { detectFrameworks } from '../frameworks/index';\nimport { ReferenceResolver } from '../resolution/index';\nimport { VectorManager } from '../vectors/index';\nimport { ArchitectureAnalyzer } from '../architecture/index';\nimport type { KiroGraphConfig } from '../config';\nimport type { IndexResult, IndexProgress, SyncResult } from '../types';\nimport { LockManager } from './lock-manager';\nimport { Mutex } from '../utils';\n\nconst FILE_IO_BATCH_SIZE = 10;\n\nexport class IndexPipeline {\n private readonly mutex = new Mutex();\n\n constructor(\n private readonly db: GraphDatabase,\n private readonly vectors: VectorManager,\n private readonly resolver: ReferenceResolver,\n private readonly arch: ArchitectureAnalyzer,\n private readonly lock: LockManager,\n private readonly config: KiroGraphConfig,\n private readonly projectRoot: string,\n ) {}\n\n async indexAll(opts?: {\n onProgress?: (p: IndexProgress) => void;\n force?: boolean;\n signal?: AbortSignal;\n }): Promise<IndexResult> {\n const release = await this.mutex.acquire();\n this.lock.acquire();\n const start = Date.now();\n const errors: string[] = [];\n let filesIndexed = 0;\n let nodesCreated = 0;\n let edgesCreated = 0;\n\n // Track languages whose WASM parser is currently poisoned (ABORT=true on the module).\n // Once a language's parser aborts, every subsequent parse call for that language\n // fails instantly. We skip those files until clearParserCache + initGrammars succeeds.\n const poisonedLanguages = new Set<string>();\n\n try {\n const files = await scanDirectory(this.projectRoot, this.config, opts?.signal);\n opts?.onProgress?.({ phase: 'scanning', current: files.length, total: files.length });\n\n // Batch-read files in parallel\n const contentMap = new Map<string, Buffer>();\n for (let b = 0; b < files.length; b += FILE_IO_BATCH_SIZE) {\n const batch = files.slice(b, b + FILE_IO_BATCH_SIZE);\n const results = await Promise.all(batch.map(f => fs.promises.readFile(f).catch(() => null)));\n for (let i = 0; i < batch.length; i++) {\n if (results[i]) contentMap.set(batch[i], results[i]!);\n }\n }\n\n for (let i = 0; i < files.length; i++) {\n const file = files[i];\n opts?.onProgress?.({ phase: 'parsing', current: i + 1, total: files.length, currentFile: file });\n\n try {\n const content = contentMap.get(file);\n if (!content) continue;\n if (content.length > this.config.maxFileSize) continue;\n\n const relPath = path.relative(this.projectRoot, file).replace(/\\\\/g, '/');\n\n if (!opts?.force) {\n const existing = this.db.getFile(relPath);\n if (existing && hashContent(content) === existing.contentHash) continue;\n }\n\n // Skip files whose language parser is currently poisoned\n const { detectLanguage } = await Promise.resolve().then(() => require('../extraction/languages.js'));\n const lang = detectLanguage(file);\n if (poisonedLanguages.has(lang)) continue;\n\n const extracted = await extractFile(file, this.projectRoot, content);\n if (!extracted) continue;\n\n const oldNodes = this.db.getNodesByFile(extracted.filePath);\n if (oldNodes.length > 0) await this.vectors.deleteEmbeddings(oldNodes.map(n => n.id));\n\n this.db.transaction(() => {\n this.db.deleteNodesByFile(extracted.filePath);\n this.db.deleteUnresolvedRefsByFile(extracted.filePath);\n this.db.upsertFile({\n path: extracted.filePath,\n contentHash: extracted.contentHash,\n language: extracted.language,\n fileSize: extracted.fileSize,\n symbolCount: extracted.nodes.length,\n indexedAt: Date.now(),\n });\n for (const node of extracted.nodes) { this.db.upsertNode(node); nodesCreated++; }\n for (const edge of extracted.edges) { this.db.insertEdge(edge); edgesCreated++; }\n for (const ref of extracted.unresolvedRefs) {\n this.db.insertUnresolvedRef(ref.sourceId, ref.refName, ref.refKind, extracted.filePath, ref.line, ref.column);\n }\n });\n\n filesIndexed++;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n errors.push(`${file}: ${msg}`);\n\n // Detect WASM runtime abort and attempt recovery\n const isWasmCrash = (err as any)?.constructor?.name === 'RuntimeError'\n || msg.includes('Aborted(') \n || msg.includes('RuntimeError')\n || msg.includes('WASM grammar exists but failed to load');\n if (isWasmCrash) {\n // Mark the language as poisoned so we skip remaining files of this language\n const { detectLanguage } = await Promise.resolve().then(() => require('../extraction/languages.js'));\n const lang = detectLanguage(file);\n poisonedLanguages.add(lang);\n\n clearParserCache();\n try {\n await initGrammars();\n // Recovery succeeded \u2014 un-poison all languages\n poisonedLanguages.clear();\n } catch {\n errors.push('WASM runtime unrecoverable after crash \u2014 aborting batch');\n break;\n }\n }\n }\n }\n\n // Re-process files that have symbolCount=0 but should have symbols (WASM recovery)\n const emptyFiles = this.db.getAllFiles().filter(\n (f: any) => f.symbolCount === 0 && hasWasmGrammar(f.language)\n );\n if (emptyFiles.length > 0) {\n opts?.onProgress?.({ phase: 'retrying', current: 0, total: emptyFiles.length });\n for (let i = 0; i < emptyFiles.length; i++) {\n const ef = emptyFiles[i];\n const absPath = path.join(this.projectRoot, ef.path);\n opts?.onProgress?.({ phase: 'retrying', current: i + 1, total: emptyFiles.length, currentFile: absPath });\n try {\n const extracted = await extractFile(absPath, this.projectRoot);\n if (!extracted || extracted.nodes.length === 0) continue;\n\n const oldNodes = this.db.getNodesByFile(extracted.filePath);\n if (oldNodes.length > 0) await this.vectors.deleteEmbeddings(oldNodes.map(n => n.id));\n\n this.db.transaction(() => {\n this.db.deleteNodesByFile(extracted.filePath);\n this.db.deleteUnresolvedRefsByFile(extracted.filePath);\n this.db.upsertFile({\n path: extracted.filePath,\n contentHash: extracted.contentHash,\n language: extracted.language,\n fileSize: extracted.fileSize,\n symbolCount: extracted.nodes.length,\n indexedAt: Date.now(),\n });\n for (const node of extracted.nodes) { this.db.upsertNode(node); nodesCreated++; }\n for (const edge of extracted.edges) { this.db.insertEdge(edge); edgesCreated++; }\n for (const ref of extracted.unresolvedRefs) {\n this.db.insertUnresolvedRef(ref.sourceId, ref.refName, ref.refKind, extracted.filePath, ref.line, ref.column);\n }\n });\n filesIndexed++;\n } catch {\n // Already logged in first pass or genuinely broken \u2014 skip\n }\n }\n }\n\n // Resolve cross-file references\n opts?.onProgress?.({ phase: 'resolving', current: 0, total: 1 });\n await this.resolver.resolveAll((current, total) => {\n opts?.onProgress?.({ phase: 'resolving', current, total });\n });\n\n // Detect frameworks\n opts?.onProgress?.({ phase: 'detecting frameworks', current: 0, total: 1 });\n const detectedFrameworks = await detectFrameworks(this.projectRoot, this.db);\n const languages = [...new Set(this.db.getAllFiles().map(f => (f as any).language).filter(Boolean))];\n opts?.onProgress?.({\n phase: 'detecting frameworks', current: 1, total: 1,\n meta: { frameworks: detectedFrameworks.map(f => f.name), languages },\n });\n\n // Generate embeddings (if enabled)\n if (this.vectors.isInitialized()) {\n opts?.onProgress?.({ phase: 'embeddings', current: 0, total: 1 });\n await this.vectors.embedAll((current, total) =>\n opts?.onProgress?.({ phase: 'embeddings', current, total })\n );\n }\n\n // Analyze architecture (if enabled, or auto-enabled for security)\n if (this.config.enableArchitecture || this.config.enableSecurity) {\n if (this.config.enableSecurity && !this.config.enableArchitecture) {\n const { logWarn } = await Promise.resolve().then(() => require('../errors.js'));\n logWarn('enableSecurity requires enableArchitecture \u2014 auto-enabling architecture analysis for this run');\n }\n opts?.onProgress?.({ phase: 'architecture', current: 0, total: 1 });\n await this.arch.analyze(msg =>\n opts?.onProgress?.({ phase: 'architecture', current: 0, total: 1, meta: { msg } })\n );\n opts?.onProgress?.({ phase: 'architecture', current: 1, total: 1 });\n }\n\n // Run security analysis (if enabled)\n if (this.config.enableSecurity) {\n try {\n const { SecurityPipeline } = await Promise.resolve().then(() => require('../security/pipeline.js'));\n this.db.applySecuritySchema();\n const secPipeline = new SecurityPipeline(this.db, this.config, this.projectRoot);\n opts?.onProgress?.({ phase: 'security', current: 0, total: 1 });\n await secPipeline.run((phase, current, total) =>\n opts?.onProgress?.({ phase: 'security', current, total, meta: { secPhase: phase } })\n );\n opts?.onProgress?.({ phase: 'security', current: 1, total: 1 });\n } catch { /* security analysis is non-critical */ }\n }\n\n // Index documentation (if enabled)\n if (this.config.enableDocs) {\n try {\n const { DocsIndexer } = await Promise.resolve().then(() => require('../docs/indexer.js'));\n this.db.applyDocsSchema();\n const docsIndexer = new DocsIndexer(this.db.getRawDb(), this.config, this.projectRoot);\n await docsIndexer.indexAll({\n force: opts?.force,\n onProgress: msg => opts?.onProgress?.({ phase: 'docs', current: 0, total: 1, meta: { msg } }),\n });\n } catch { /* docs indexing is non-critical */ }\n }\n\n // Index data files (if enabled)\n if ((this.config as any).enableData) {\n try {\n const { DataIndexer } = await Promise.resolve().then(() => require('../data/indexer.js'));\n this.db.applyDataSchema();\n const dataIndexer = new DataIndexer(this.db.getRawDb(), this.config, this.projectRoot);\n await dataIndexer.indexAll({\n onProgress: msg => opts?.onProgress?.({ phase: 'data', current: 0, total: 1, meta: { msg } }),\n });\n\n // Assign data files to 'data' architecture layer if architecture is enabled\n if (this.config.enableArchitecture) {\n try {\n const rawDb = this.db.getRawDb();\n // Check if arch_file_layers table exists\n const tableExists = rawDb.get(\"SELECT name FROM sqlite_master WHERE type='table' AND name='arch_file_layers'\");\n if (tableExists) {\n const datasets = rawDb.all('SELECT file_path FROM data_datasets') as Array<{ file_path: string }>;\n for (const ds of datasets) {\n rawDb.run(\n `INSERT OR REPLACE INTO arch_file_layers (file_path, layer_id, confidence) VALUES (?, ?, ?)`,\n [ds.file_path, 'layer:data', 1.0],\n );\n }\n }\n } catch { /* non-critical */ }\n }\n } catch { /* data indexing is non-critical */ }\n }\n\n // Index pattern matches (if enabled)\n if ((this.config as any).enablePatterns) {\n try {\n this.db.applyPatternsSchema();\n const { PatternIndexer } = await Promise.resolve().then(() => require('../patterns/indexer.js'));\n const indexer = new PatternIndexer(this.db.getRawDb(), this.config, this.projectRoot);\n await indexer.indexAll((phase, current, total) => {\n opts?.onProgress?.({ phase: 'patterns' as any, current, total });\n });\n } catch (err) {\n // Patterns are non-critical \u2014 log and continue\n const { logWarn } = await Promise.resolve().then(() => require('../errors.js'));\n const msg = err instanceof Error ? err.message : String(err);\n logWarn(`[patterns] Pattern indexing failed (non-critical): ${msg}`);\n }\n }\n\n this.lock.clearDirty();\n return { success: errors.length === 0, filesIndexed, nodesCreated, edgesCreated, errors, duration: Date.now() - start };\n } finally {\n this.lock.release();\n release();\n }\n }\n\n async sync(opts?: {\n changedFiles?: string[];\n onProgress?: (p: IndexProgress) => void;\n }): Promise<SyncResult> {\n const release = await this.mutex.acquire();\n this.lock.acquire();\n const start = Date.now();\n const changedFiles = opts?.changedFiles;\n const onProgress = opts?.onProgress;\n const result: SyncResult = {\n added: [], modified: [], removed: [],\n nodesCreated: 0, nodesUpdated: 0, nodesRemoved: 0,\n edgesCreated: 0, edgesRemoved: 0,\n filesScanned: 0, errors: [], duration: 0,\n };\n\n try {\n const removeFile = async (rel: string) => {\n const oldNodes = this.db.getNodesByFile(rel);\n const oldEdgeCount = this.db.getEdgesForNodes(oldNodes.map(n => n.id)).length;\n result.nodesRemoved += oldNodes.length;\n result.edgesRemoved += oldEdgeCount;\n await this.vectors.deleteEmbeddings(oldNodes.map(n => n.id));\n this.db.deleteFile(rel);\n this.db.deleteUnresolvedRefsByFile(rel);\n // Clean up pattern matches for removed files\n this.db.getRawDb().run('DELETE FROM pattern_matches WHERE file_path = ?', [rel]);\n result.removed.push(rel);\n };\n\n // \u2500\u2500 Exclude-rule cleanup \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // Remove any indexed files that now match the current exclude patterns.\n // This handles the case where a user adds a new exclude pattern (e.g.\n // \"**/.vite/**\") and expects those files to disappear from the index on\n // the next sync without needing a full --force re-index.\n const allIndexed = this.db.getAllFiles();\n for (const f of allIndexed) {\n if (!shouldIncludeFile(f.path, this.config)) {\n onProgress?.({ phase: 'scanning', current: 0, total: 0, meta: { excludeCleanup: true, file: f.path } });\n await removeFile(f.path);\n }\n }\n\n let filesToProcess: string[];\n\n onProgress?.({ phase: 'scanning', current: 0, total: 0 });\n\n if (changedFiles) {\n filesToProcess = changedFiles.map(f => path.resolve(this.projectRoot, f));\n } else {\n const gitChanged = await getChangedFiles(this.projectRoot, this.config);\n const hasChanges = gitChanged.added.length > 0 || gitChanged.modified.length > 0 || gitChanged.removed.length > 0;\n\n if (hasChanges) {\n for (const p of gitChanged.removed) {\n await removeFile(path.relative(this.projectRoot, p).replace(/\\\\/g, '/'));\n }\n filesToProcess = [...gitChanged.added, ...gitChanged.modified];\n } else {\n // Fallback: full scan + detect removed files\n const indexed = new Set(this.db.getAllFiles().map(f => f.path));\n const current = new Set(\n (await scanDirectory(this.projectRoot, this.config))\n .map(f => path.relative(this.projectRoot, f).replace(/\\\\/g, '/'))\n );\n result.filesScanned = current.size;\n for (const p of indexed) {\n if (!current.has(p)) await removeFile(p);\n }\n filesToProcess = await scanDirectory(this.projectRoot, this.config);\n }\n }\n\n result.filesScanned = result.filesScanned || filesToProcess.length;\n onProgress?.({ phase: 'scanning', current: result.filesScanned, total: result.filesScanned });\n\n const poisonedLanguages = new Set<string>();\n\n for (let i = 0; i < filesToProcess.length; i++) {\n const file = filesToProcess[i];\n onProgress?.({ phase: 'parsing', current: i + 1, total: filesToProcess.length, currentFile: file });\n\n if (!fs.existsSync(file)) {\n const rel = path.relative(this.projectRoot, file).replace(/\\\\/g, '/');\n await removeFile(rel);\n continue;\n }\n\n try {\n // Skip files whose language parser is currently poisoned\n const { detectLanguage } = await Promise.resolve().then(() => require('../extraction/languages.js'));\n const lang = detectLanguage(file);\n if (poisonedLanguages.has(lang)) continue;\n\n const extracted = await extractFile(file, this.projectRoot);\n if (!extracted) continue;\n\n const existing = this.db.getFile(extracted.filePath);\n const isNew = !existing;\n if (!isNew && existing!.contentHash === extracted.contentHash) continue;\n\n const oldNodes = this.db.getNodesByFile(extracted.filePath);\n const oldEdgeCount = this.db.getEdgesForNodes(oldNodes.map(n => n.id)).length;\n await this.vectors.deleteEmbeddings(oldNodes.map(n => n.id));\n\n this.db.transaction(() => {\n result.nodesRemoved += oldNodes.length;\n result.edgesRemoved += oldEdgeCount;\n this.db.deleteNodesByFile(extracted.filePath);\n this.db.deleteUnresolvedRefsByFile(extracted.filePath);\n this.db.upsertFile({\n path: extracted.filePath,\n contentHash: extracted.contentHash,\n language: extracted.language,\n fileSize: extracted.fileSize,\n symbolCount: extracted.nodes.length,\n indexedAt: Date.now(),\n });\n for (const node of extracted.nodes) { this.db.upsertNode(node); result.nodesCreated++; }\n for (const edge of extracted.edges) { this.db.insertEdge(edge); result.edgesCreated++; }\n for (const ref of extracted.unresolvedRefs) {\n this.db.insertUnresolvedRef(ref.sourceId, ref.refName, ref.refKind, extracted.filePath, ref.line, ref.column);\n }\n });\n\n this.resolver.invalidateFile(extracted.filePath);\n if (isNew) result.added.push(extracted.filePath);\n else { result.modified.push(extracted.filePath); result.nodesUpdated += extracted.nodes.length; }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n result.errors.push(`${file}: ${msg}`);\n\n // Detect WASM runtime abort and attempt recovery\n const isWasmCrash = (err as any)?.constructor?.name === 'RuntimeError'\n || msg.includes('Aborted(') \n || msg.includes('RuntimeError')\n || msg.includes('WASM grammar exists but failed to load');\n if (isWasmCrash) {\n const { detectLanguage } = await Promise.resolve().then(() => require('../extraction/languages.js'));\n const lang = detectLanguage(file);\n poisonedLanguages.add(lang);\n\n clearParserCache();\n try {\n await initGrammars();\n poisonedLanguages.clear();\n } catch {\n result.errors.push('WASM runtime unrecoverable after crash \u2014 aborting sync');\n break;\n }\n }\n }\n }\n\n // Resolve cross-file references\n onProgress?.({ phase: 'resolving', current: 0, total: 1 });\n await this.resolver.resolveAll((current, total) => {\n onProgress?.({ phase: 'resolving', current, total });\n });\n\n await detectFrameworks(this.projectRoot);\n\n // Generate embeddings (if enabled)\n if (this.vectors.isInitialized()) {\n onProgress?.({ phase: 'embeddings', current: 0, total: 1 });\n await this.vectors.embedAll((current, total) =>\n onProgress?.({ phase: 'embeddings', current, total })\n );\n }\n\n // Analyze architecture (if enabled, or auto-enabled for security)\n if (this.config.enableArchitecture || this.config.enableSecurity) {\n if (this.config.enableSecurity && !this.config.enableArchitecture) {\n const { logWarn } = await Promise.resolve().then(() => require('../errors.js'));\n logWarn('enableSecurity requires enableArchitecture \u2014 auto-enabling architecture analysis for this run');\n }\n onProgress?.({ phase: 'architecture', current: 0, total: 1 });\n await this.arch.analyze(msg =>\n onProgress?.({ phase: 'architecture', current: 0, total: 1, meta: { msg } })\n );\n onProgress?.({ phase: 'architecture', current: 1, total: 1 });\n }\n\n // Run security analysis (if enabled)\n if (this.config.enableSecurity) {\n try {\n const { SecurityPipeline } = await Promise.resolve().then(() => require('../security/pipeline.js'));\n this.db.applySecuritySchema();\n const secPipeline = new SecurityPipeline(this.db, this.config, this.projectRoot);\n onProgress?.({ phase: 'security', current: 0, total: 1 });\n await secPipeline.run((phase, current, total) =>\n onProgress?.({ phase: 'security', current, total, meta: { secPhase: phase } })\n );\n onProgress?.({ phase: 'security', current: 1, total: 1 });\n } catch { /* security analysis is non-critical */ }\n }\n\n // Re-index documentation (if enabled)\n if (this.config.enableDocs) {\n try {\n const { DocsIndexer } = await Promise.resolve().then(() => require('../docs/indexer.js'));\n this.db.applyDocsSchema();\n const docsIndexer = new DocsIndexer(this.db.getRawDb(), this.config, this.projectRoot);\n await docsIndexer.indexAll({\n onProgress: msg => onProgress?.({ phase: 'docs', current: 0, total: 1, meta: { msg } }),\n });\n } catch { /* docs indexing is non-critical */ }\n }\n\n // Re-index data files (if enabled)\n if ((this.config as any).enableData) {\n try {\n const { DataIndexer } = await Promise.resolve().then(() => require('../data/indexer.js'));\n this.db.applyDataSchema();\n const dataIndexer = new DataIndexer(this.db.getRawDb(), this.config, this.projectRoot);\n await dataIndexer.indexAll({\n onProgress: msg => onProgress?.({ phase: 'data', current: 0, total: 1, meta: { msg } }),\n });\n\n // Assign data files to 'data' architecture layer if architecture is enabled\n if (this.config.enableArchitecture) {\n try {\n const rawDb = this.db.getRawDb();\n const tableExists = rawDb.get(\"SELECT name FROM sqlite_master WHERE type='table' AND name='arch_file_layers'\");\n if (tableExists) {\n const datasets = rawDb.all('SELECT file_path FROM data_datasets') as Array<{ file_path: string }>;\n for (const ds of datasets) {\n rawDb.run(\n `INSERT OR REPLACE INTO arch_file_layers (file_path, layer_id, confidence) VALUES (?, ?, ?)`,\n [ds.file_path, 'layer:data', 1.0],\n );\n }\n }\n } catch { /* non-critical */ }\n }\n } catch { /* data indexing is non-critical */ }\n }\n\n // Re-index pattern matches for changed files (if enabled)\n if ((this.config as any).enablePatterns) {\n try {\n const tableExists = this.db.getRawDb().get(\n \"SELECT name FROM sqlite_master WHERE type='table' AND name='pattern_matches'\"\n );\n if (tableExists) {\n const { PatternIndexer } = await Promise.resolve().then(() => require('../patterns/indexer.js'));\n const { PatternLibraryLoader } = await Promise.resolve().then(() => require('../patterns/loader.js'));\n const { PatternRunner } = await Promise.resolve().then(() => require('../patterns/runner.js'));\n const runner = new PatternRunner();\n if (runner.isAvailable()) {\n const loader = new PatternLibraryLoader();\n const builtinPath = require('path').join(__dirname, '../patterns/library');\n const rules = loader.load(builtinPath, (this.config as any).patternLibraryPath);\n const threshold = (this.config as any).patternSeverityThreshold ?? 'low';\n const indexer = new PatternIndexer(this.db.getRawDb(), this.config, this.projectRoot);\n const changedPaths = [...result.added, ...result.modified];\n for (const filePath of changedPaths) {\n const fileRecord = this.db.getFile(filePath);\n const language = fileRecord?.language ?? 'unknown';\n await indexer.indexFile(filePath, language, rules, runner, threshold, Date.now());\n }\n }\n }\n } catch { /* non-critical */ }\n }\n\n this.lock.clearDirty();\n result.duration = Date.now() - start;\n return result;\n } finally {\n this.lock.release();\n release();\n }\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * IndexPipeline \u2014 full-index and incremental-sync pipelines.\n *\n * Owns the two heavy workflows:\n * - indexAll(): scan all files, extract, store, resolve, detect frameworks,\n * generate embeddings, analyze architecture.\n * - sync(): detect changed files via git (or full scan fallback),\n * re-extract only what changed, then run the same tail pipeline.\n *\n * Everything that touches the filesystem or sub-systems is injected via the\n * constructor, keeping this class testable and free of global state.\n */\n\nimport * as path from 'path';\nimport * as fs from 'fs';\nimport { GraphDatabase } from '../db/database';\nimport { scanDirectory, hashContent, getChangedFiles, shouldIncludeFile } from '../sync/index';\nimport { extractFile } from '../extraction/extractor';\nimport { clearParserCache, initGrammars, hasWasmGrammar } from '../extraction/grammars';\nimport { detectFrameworks } from '../frameworks/index';\nimport { ReferenceResolver } from '../resolution/index';\nimport { VectorManager } from '../vectors/index';\nimport { ArchitectureAnalyzer } from '../architecture/index';\nimport type { KiroGraphConfig } from '../config';\nimport type { IndexResult, IndexProgress, SyncResult } from '../types';\nimport { LockManager } from './lock-manager';\nimport { Mutex } from '../utils';\n\nconst FILE_IO_BATCH_SIZE = 10;\n\nexport class IndexPipeline {\n private readonly mutex = new Mutex();\n\n constructor(\n private readonly db: GraphDatabase,\n private readonly vectors: VectorManager,\n private readonly resolver: ReferenceResolver,\n private readonly arch: ArchitectureAnalyzer,\n private readonly lock: LockManager,\n private readonly config: KiroGraphConfig,\n private readonly projectRoot: string,\n ) {}\n\n async indexAll(opts?: {\n onProgress?: (p: IndexProgress) => void;\n force?: boolean;\n signal?: AbortSignal;\n }): Promise<IndexResult> {\n const release = await this.mutex.acquire();\n this.lock.acquire();\n const start = Date.now();\n const errors: string[] = [];\n let filesIndexed = 0;\n let nodesCreated = 0;\n let edgesCreated = 0;\n\n // Track languages whose WASM parser is currently poisoned (ABORT=true on the module).\n // Once a language's parser aborts, every subsequent parse call for that language\n // fails instantly. We skip those files until clearParserCache + initGrammars succeeds.\n const poisonedLanguages = new Set<string>();\n\n try {\n const files = await scanDirectory(this.projectRoot, this.config, opts?.signal);\n opts?.onProgress?.({ phase: 'scanning', current: files.length, total: files.length });\n\n // Batch-read files in parallel\n const contentMap = new Map<string, Buffer>();\n for (let b = 0; b < files.length; b += FILE_IO_BATCH_SIZE) {\n const batch = files.slice(b, b + FILE_IO_BATCH_SIZE);\n const results = await Promise.all(batch.map(f => fs.promises.readFile(f).catch(() => null)));\n for (let i = 0; i < batch.length; i++) {\n if (results[i]) contentMap.set(batch[i], results[i]!);\n }\n }\n\n for (let i = 0; i < files.length; i++) {\n const file = files[i];\n opts?.onProgress?.({ phase: 'parsing', current: i + 1, total: files.length, currentFile: file });\n\n try {\n const content = contentMap.get(file);\n if (!content) continue;\n if (content.length > this.config.maxFileSize) continue;\n\n const relPath = path.relative(this.projectRoot, file).replace(/\\\\/g, '/');\n\n if (!opts?.force) {\n const existing = this.db.getFile(relPath);\n if (existing && hashContent(content) === existing.contentHash) continue;\n }\n\n // Skip files whose language parser is currently poisoned\n const { detectLanguage } = await Promise.resolve().then(() => require('../extraction/languages.js'));\n const lang = detectLanguage(file);\n if (poisonedLanguages.has(lang)) continue;\n\n const extracted = await extractFile(file, this.projectRoot, content);\n if (!extracted) continue;\n\n const oldNodes = this.db.getNodesByFile(extracted.filePath);\n if (oldNodes.length > 0) await this.vectors.deleteEmbeddings(oldNodes.map(n => n.id));\n\n this.db.transaction(() => {\n this.db.deleteNodesByFile(extracted.filePath);\n this.db.deleteUnresolvedRefsByFile(extracted.filePath);\n this.db.upsertFile({\n path: extracted.filePath,\n contentHash: extracted.contentHash,\n language: extracted.language,\n fileSize: extracted.fileSize,\n symbolCount: extracted.nodes.length,\n indexedAt: Date.now(),\n });\n for (const node of extracted.nodes) { this.db.upsertNode(node); nodesCreated++; }\n for (const edge of extracted.edges) { this.db.insertEdge(edge); edgesCreated++; }\n for (const ref of extracted.unresolvedRefs) {\n this.db.insertUnresolvedRef(ref.sourceId, ref.refName, ref.refKind, extracted.filePath, ref.line, ref.column);\n }\n });\n\n filesIndexed++;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n errors.push(`${file}: ${msg}`);\n\n // Detect WASM runtime abort and attempt recovery\n const isWasmCrash = (err as any)?.constructor?.name === 'RuntimeError'\n || msg.includes('Aborted(') \n || msg.includes('RuntimeError')\n || msg.includes('WASM grammar exists but failed to load');\n if (isWasmCrash) {\n // Mark the language as poisoned so we skip remaining files of this language\n const { detectLanguage } = await Promise.resolve().then(() => require('../extraction/languages.js'));\n const lang = detectLanguage(file);\n poisonedLanguages.add(lang);\n\n clearParserCache();\n try {\n await initGrammars();\n // Recovery succeeded \u2014 un-poison all languages\n poisonedLanguages.clear();\n } catch {\n errors.push('WASM runtime unrecoverable after crash \u2014 aborting batch');\n break;\n }\n }\n }\n }\n\n // Re-process files that have symbolCount=0 but should have symbols (WASM recovery)\n const emptyFiles = this.db.getAllFiles().filter(\n (f: any) => f.symbolCount === 0 && hasWasmGrammar(f.language)\n );\n if (emptyFiles.length > 0) {\n opts?.onProgress?.({ phase: 'retrying', current: 0, total: emptyFiles.length });\n for (let i = 0; i < emptyFiles.length; i++) {\n const ef = emptyFiles[i];\n const absPath = path.join(this.projectRoot, ef.path);\n opts?.onProgress?.({ phase: 'retrying', current: i + 1, total: emptyFiles.length, currentFile: absPath });\n try {\n const extracted = await extractFile(absPath, this.projectRoot);\n if (!extracted || extracted.nodes.length === 0) continue;\n\n const oldNodes = this.db.getNodesByFile(extracted.filePath);\n if (oldNodes.length > 0) await this.vectors.deleteEmbeddings(oldNodes.map(n => n.id));\n\n this.db.transaction(() => {\n this.db.deleteNodesByFile(extracted.filePath);\n this.db.deleteUnresolvedRefsByFile(extracted.filePath);\n this.db.upsertFile({\n path: extracted.filePath,\n contentHash: extracted.contentHash,\n language: extracted.language,\n fileSize: extracted.fileSize,\n symbolCount: extracted.nodes.length,\n indexedAt: Date.now(),\n });\n for (const node of extracted.nodes) { this.db.upsertNode(node); nodesCreated++; }\n for (const edge of extracted.edges) { this.db.insertEdge(edge); edgesCreated++; }\n for (const ref of extracted.unresolvedRefs) {\n this.db.insertUnresolvedRef(ref.sourceId, ref.refName, ref.refKind, extracted.filePath, ref.line, ref.column);\n }\n });\n filesIndexed++;\n } catch {\n // Already logged in first pass or genuinely broken \u2014 skip\n }\n }\n }\n\n // Resolve cross-file references\n opts?.onProgress?.({ phase: 'resolving', current: 0, total: 1 });\n await this.resolver.resolveAll((current, total) => {\n opts?.onProgress?.({ phase: 'resolving', current, total });\n });\n\n // Detect frameworks\n opts?.onProgress?.({ phase: 'detecting frameworks', current: 0, total: 1 });\n const detectedFrameworks = await detectFrameworks(this.projectRoot, this.db);\n const languages = [...new Set(this.db.getAllFiles().map(f => (f as any).language).filter(Boolean))];\n opts?.onProgress?.({\n phase: 'detecting frameworks', current: 1, total: 1,\n meta: { frameworks: detectedFrameworks.map(f => f.name), languages },\n });\n\n // Generate embeddings (if enabled)\n if (this.vectors.isInitialized()) {\n opts?.onProgress?.({ phase: 'embeddings', current: 0, total: 1 });\n await this.vectors.embedAll((current, total) =>\n opts?.onProgress?.({ phase: 'embeddings', current, total })\n );\n }\n\n // Analyze architecture (if enabled, or auto-enabled for security)\n if (this.config.enableArchitecture || this.config.enableSecurity) {\n if (this.config.enableSecurity && !this.config.enableArchitecture) {\n const { logWarn } = await Promise.resolve().then(() => require('../errors.js'));\n logWarn('enableSecurity requires enableArchitecture \u2014 auto-enabling architecture analysis for this run');\n }\n opts?.onProgress?.({ phase: 'architecture', current: 0, total: 1 });\n await this.arch.analyze(msg =>\n opts?.onProgress?.({ phase: 'architecture', current: 0, total: 1, meta: { msg } })\n );\n opts?.onProgress?.({ phase: 'architecture', current: 1, total: 1 });\n }\n\n // Run security analysis (if enabled)\n if (this.config.enableSecurity) {\n try {\n const { SecurityPipeline } = await Promise.resolve().then(() => require('../security/pipeline.js'));\n this.db.applySecuritySchema();\n const secPipeline = new SecurityPipeline(this.db, this.config, this.projectRoot);\n opts?.onProgress?.({ phase: 'security', current: 0, total: 1 });\n await secPipeline.run((phase, current, total) =>\n opts?.onProgress?.({ phase: 'security', current, total, meta: { secPhase: phase } })\n );\n opts?.onProgress?.({ phase: 'security', current: 1, total: 1 });\n } catch { /* security analysis is non-critical */ }\n }\n\n // Index documentation (if enabled)\n if (this.config.enableDocs) {\n try {\n const { DocsIndexer } = await Promise.resolve().then(() => require('../docs/indexer.js'));\n this.db.applyDocsSchema();\n const docsIndexer = new DocsIndexer(this.db.getRawDb(), this.config, this.projectRoot);\n await docsIndexer.indexAll({\n force: opts?.force,\n onProgress: msg => opts?.onProgress?.({ phase: 'docs', current: 0, total: 1, meta: { msg } }),\n });\n } catch { /* docs indexing is non-critical */ }\n }\n\n // Index data files (if enabled)\n if ((this.config as any).enableData) {\n try {\n const { DataIndexer } = await Promise.resolve().then(() => require('../data/indexer.js'));\n this.db.applyDataSchema();\n const dataIndexer = new DataIndexer(this.db.getRawDb(), this.config, this.projectRoot);\n await dataIndexer.indexAll({\n onProgress: msg => opts?.onProgress?.({ phase: 'data', current: 0, total: 1, meta: { msg } }),\n });\n\n // Assign data files to 'data' architecture layer if architecture is enabled\n if (this.config.enableArchitecture) {\n try {\n const rawDb = this.db.getRawDb();\n // Check if arch_file_layers table exists\n const tableExists = rawDb.get(\"SELECT name FROM sqlite_master WHERE type='table' AND name='arch_file_layers'\");\n if (tableExists) {\n const datasets = rawDb.all('SELECT file_path FROM data_datasets') as Array<{ file_path: string }>;\n for (const ds of datasets) {\n rawDb.run(\n `INSERT OR REPLACE INTO arch_file_layers (file_path, layer_id, confidence) VALUES (?, ?, ?)`,\n [ds.file_path, 'layer:data', 1.0],\n );\n }\n }\n } catch { /* non-critical */ }\n }\n } catch { /* data indexing is non-critical */ }\n }\n\n // Index pattern matches (if enabled)\n if ((this.config as any).enablePatterns) {\n try {\n this.db.applyPatternsSchema();\n const { PatternIndexer } = await Promise.resolve().then(() => require('../patterns/indexer.js'));\n const indexer = new PatternIndexer(this.db.getRawDb(), this.config, this.projectRoot);\n await indexer.indexAll((phase, current, total) => {\n opts?.onProgress?.({ phase: 'patterns' as any, current, total });\n });\n } catch (err) {\n // Patterns are non-critical \u2014 log and continue\n const { logWarn } = await Promise.resolve().then(() => require('../errors.js'));\n const msg = err instanceof Error ? err.message : String(err);\n logWarn(`[patterns] Pattern indexing failed (non-critical): ${msg}`);\n }\n }\n\n this.lock.clearDirty();\n return { success: errors.length === 0, filesIndexed, nodesCreated, edgesCreated, errors, duration: Date.now() - start };\n } finally {\n this.lock.release();\n release();\n }\n }\n\n async sync(opts?: {\n changedFiles?: string[];\n onProgress?: (p: IndexProgress) => void;\n }): Promise<SyncResult> {\n const release = await this.mutex.acquire();\n this.lock.acquire();\n const start = Date.now();\n const changedFiles = opts?.changedFiles;\n const onProgress = opts?.onProgress;\n const result: SyncResult = {\n added: [], modified: [], removed: [],\n nodesCreated: 0, nodesUpdated: 0, nodesRemoved: 0,\n edgesCreated: 0, edgesRemoved: 0,\n filesScanned: 0, errors: [], duration: 0,\n };\n\n try {\n const removeFile = async (rel: string) => {\n const oldNodes = this.db.getNodesByFile(rel);\n const oldEdgeCount = this.db.getEdgesForNodes(oldNodes.map(n => n.id)).length;\n result.nodesRemoved += oldNodes.length;\n result.edgesRemoved += oldEdgeCount;\n await this.vectors.deleteEmbeddings(oldNodes.map(n => n.id));\n this.db.deleteFile(rel);\n this.db.deleteUnresolvedRefsByFile(rel);\n // Clean up pattern matches for removed files (only if patterns are enabled)\n if ((this.config as any).enablePatterns) {\n this.db.getRawDb().run('DELETE FROM pattern_matches WHERE file_path = ?', [rel]);\n }\n result.removed.push(rel);\n };\n\n // \u2500\u2500 Exclude-rule cleanup \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // Remove any indexed files that now match the current exclude patterns.\n // This handles the case where a user adds a new exclude pattern (e.g.\n // \"**/.vite/**\") and expects those files to disappear from the index on\n // the next sync without needing a full --force re-index.\n const allIndexed = this.db.getAllFiles();\n for (const f of allIndexed) {\n if (!shouldIncludeFile(f.path, this.config)) {\n onProgress?.({ phase: 'scanning', current: 0, total: 0, meta: { excludeCleanup: true, file: f.path } });\n await removeFile(f.path);\n }\n }\n\n let filesToProcess: string[];\n\n onProgress?.({ phase: 'scanning', current: 0, total: 0 });\n\n if (changedFiles) {\n filesToProcess = changedFiles.map(f => path.resolve(this.projectRoot, f));\n } else {\n const gitChanged = await getChangedFiles(this.projectRoot, this.config);\n const hasChanges = gitChanged.added.length > 0 || gitChanged.modified.length > 0 || gitChanged.removed.length > 0;\n\n if (hasChanges) {\n for (const p of gitChanged.removed) {\n await removeFile(path.relative(this.projectRoot, p).replace(/\\\\/g, '/'));\n }\n filesToProcess = [...gitChanged.added, ...gitChanged.modified];\n } else {\n // Fallback: full scan + detect removed files\n const indexed = new Set(this.db.getAllFiles().map(f => f.path));\n const current = new Set(\n (await scanDirectory(this.projectRoot, this.config))\n .map(f => path.relative(this.projectRoot, f).replace(/\\\\/g, '/'))\n );\n result.filesScanned = current.size;\n for (const p of indexed) {\n if (!current.has(p)) await removeFile(p);\n }\n filesToProcess = await scanDirectory(this.projectRoot, this.config);\n }\n }\n\n result.filesScanned = result.filesScanned || filesToProcess.length;\n onProgress?.({ phase: 'scanning', current: result.filesScanned, total: result.filesScanned });\n\n const poisonedLanguages = new Set<string>();\n\n for (let i = 0; i < filesToProcess.length; i++) {\n const file = filesToProcess[i];\n onProgress?.({ phase: 'parsing', current: i + 1, total: filesToProcess.length, currentFile: file });\n\n if (!fs.existsSync(file)) {\n const rel = path.relative(this.projectRoot, file).replace(/\\\\/g, '/');\n await removeFile(rel);\n continue;\n }\n\n try {\n // Skip files whose language parser is currently poisoned\n const { detectLanguage } = await Promise.resolve().then(() => require('../extraction/languages.js'));\n const lang = detectLanguage(file);\n if (poisonedLanguages.has(lang)) continue;\n\n const extracted = await extractFile(file, this.projectRoot);\n if (!extracted) continue;\n\n const existing = this.db.getFile(extracted.filePath);\n const isNew = !existing;\n if (!isNew && existing!.contentHash === extracted.contentHash) continue;\n\n const oldNodes = this.db.getNodesByFile(extracted.filePath);\n const oldEdgeCount = this.db.getEdgesForNodes(oldNodes.map(n => n.id)).length;\n await this.vectors.deleteEmbeddings(oldNodes.map(n => n.id));\n\n this.db.transaction(() => {\n result.nodesRemoved += oldNodes.length;\n result.edgesRemoved += oldEdgeCount;\n this.db.deleteNodesByFile(extracted.filePath);\n this.db.deleteUnresolvedRefsByFile(extracted.filePath);\n this.db.upsertFile({\n path: extracted.filePath,\n contentHash: extracted.contentHash,\n language: extracted.language,\n fileSize: extracted.fileSize,\n symbolCount: extracted.nodes.length,\n indexedAt: Date.now(),\n });\n for (const node of extracted.nodes) { this.db.upsertNode(node); result.nodesCreated++; }\n for (const edge of extracted.edges) { this.db.insertEdge(edge); result.edgesCreated++; }\n for (const ref of extracted.unresolvedRefs) {\n this.db.insertUnresolvedRef(ref.sourceId, ref.refName, ref.refKind, extracted.filePath, ref.line, ref.column);\n }\n });\n\n this.resolver.invalidateFile(extracted.filePath);\n if (isNew) result.added.push(extracted.filePath);\n else { result.modified.push(extracted.filePath); result.nodesUpdated += extracted.nodes.length; }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n result.errors.push(`${file}: ${msg}`);\n\n // Detect WASM runtime abort and attempt recovery\n const isWasmCrash = (err as any)?.constructor?.name === 'RuntimeError'\n || msg.includes('Aborted(') \n || msg.includes('RuntimeError')\n || msg.includes('WASM grammar exists but failed to load');\n if (isWasmCrash) {\n const { detectLanguage } = await Promise.resolve().then(() => require('../extraction/languages.js'));\n const lang = detectLanguage(file);\n poisonedLanguages.add(lang);\n\n clearParserCache();\n try {\n await initGrammars();\n poisonedLanguages.clear();\n } catch {\n result.errors.push('WASM runtime unrecoverable after crash \u2014 aborting sync');\n break;\n }\n }\n }\n }\n\n // Resolve cross-file references\n onProgress?.({ phase: 'resolving', current: 0, total: 1 });\n await this.resolver.resolveAll((current, total) => {\n onProgress?.({ phase: 'resolving', current, total });\n });\n\n await detectFrameworks(this.projectRoot);\n\n // Generate embeddings (if enabled)\n if (this.vectors.isInitialized()) {\n onProgress?.({ phase: 'embeddings', current: 0, total: 1 });\n await this.vectors.embedAll((current, total) =>\n onProgress?.({ phase: 'embeddings', current, total })\n );\n }\n\n // Analyze architecture (if enabled, or auto-enabled for security)\n if (this.config.enableArchitecture || this.config.enableSecurity) {\n if (this.config.enableSecurity && !this.config.enableArchitecture) {\n const { logWarn } = await Promise.resolve().then(() => require('../errors.js'));\n logWarn('enableSecurity requires enableArchitecture \u2014 auto-enabling architecture analysis for this run');\n }\n onProgress?.({ phase: 'architecture', current: 0, total: 1 });\n await this.arch.analyze(msg =>\n onProgress?.({ phase: 'architecture', current: 0, total: 1, meta: { msg } })\n );\n onProgress?.({ phase: 'architecture', current: 1, total: 1 });\n }\n\n // Run security analysis (if enabled)\n if (this.config.enableSecurity) {\n try {\n const { SecurityPipeline } = await Promise.resolve().then(() => require('../security/pipeline.js'));\n this.db.applySecuritySchema();\n const secPipeline = new SecurityPipeline(this.db, this.config, this.projectRoot);\n onProgress?.({ phase: 'security', current: 0, total: 1 });\n await secPipeline.run((phase, current, total) =>\n onProgress?.({ phase: 'security', current, total, meta: { secPhase: phase } })\n );\n onProgress?.({ phase: 'security', current: 1, total: 1 });\n } catch { /* security analysis is non-critical */ }\n }\n\n // Re-index documentation (if enabled)\n if (this.config.enableDocs) {\n try {\n const { DocsIndexer } = await Promise.resolve().then(() => require('../docs/indexer.js'));\n this.db.applyDocsSchema();\n const docsIndexer = new DocsIndexer(this.db.getRawDb(), this.config, this.projectRoot);\n await docsIndexer.indexAll({\n onProgress: msg => onProgress?.({ phase: 'docs', current: 0, total: 1, meta: { msg } }),\n });\n } catch { /* docs indexing is non-critical */ }\n }\n\n // Re-index data files (if enabled)\n if ((this.config as any).enableData) {\n try {\n const { DataIndexer } = await Promise.resolve().then(() => require('../data/indexer.js'));\n this.db.applyDataSchema();\n const dataIndexer = new DataIndexer(this.db.getRawDb(), this.config, this.projectRoot);\n await dataIndexer.indexAll({\n onProgress: msg => onProgress?.({ phase: 'data', current: 0, total: 1, meta: { msg } }),\n });\n\n // Assign data files to 'data' architecture layer if architecture is enabled\n if (this.config.enableArchitecture) {\n try {\n const rawDb = this.db.getRawDb();\n const tableExists = rawDb.get(\"SELECT name FROM sqlite_master WHERE type='table' AND name='arch_file_layers'\");\n if (tableExists) {\n const datasets = rawDb.all('SELECT file_path FROM data_datasets') as Array<{ file_path: string }>;\n for (const ds of datasets) {\n rawDb.run(\n `INSERT OR REPLACE INTO arch_file_layers (file_path, layer_id, confidence) VALUES (?, ?, ?)`,\n [ds.file_path, 'layer:data', 1.0],\n );\n }\n }\n } catch { /* non-critical */ }\n }\n } catch { /* data indexing is non-critical */ }\n }\n\n // Re-index pattern matches for changed files (if enabled)\n if ((this.config as any).enablePatterns) {\n try {\n const tableExists = this.db.getRawDb().get(\n \"SELECT name FROM sqlite_master WHERE type='table' AND name='pattern_matches'\"\n );\n if (tableExists) {\n const { PatternIndexer } = await Promise.resolve().then(() => require('../patterns/indexer.js'));\n const { PatternLibraryLoader } = await Promise.resolve().then(() => require('../patterns/loader.js'));\n const { PatternRunner } = await Promise.resolve().then(() => require('../patterns/runner.js'));\n const runner = new PatternRunner();\n if (runner.isAvailable()) {\n const loader = new PatternLibraryLoader();\n const builtinPath = require('path').join(__dirname, '../patterns/library');\n const rules = loader.load(builtinPath, (this.config as any).patternLibraryPath);\n const threshold = (this.config as any).patternSeverityThreshold ?? 'low';\n const indexer = new PatternIndexer(this.db.getRawDb(), this.config, this.projectRoot);\n const changedPaths = [...result.added, ...result.modified];\n for (const filePath of changedPaths) {\n const fileRecord = this.db.getFile(filePath);\n const language = fileRecord?.language ?? 'unknown';\n await indexer.indexFile(filePath, language, rules, runner, threshold, Date.now());\n }\n }\n }\n } catch { /* non-critical */ }\n }\n\n this.lock.clearDirty();\n result.duration = Date.now() - start;\n return result;\n } finally {\n this.lock.release();\n release();\n }\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -99,7 +99,7 @@ class DataIndexer {
99
99
  const profiler = new import_profiler.ColumnProfiler();
100
100
  const allRows = [];
101
101
  const maxRows = this.config.dataMaxRows ?? 1e6;
102
- const { columns, totalRows } = await parser.parse(absPath, {
102
+ const { columns, totalRows, metadataJson } = await parser.parse(absPath, {
103
103
  maxRows,
104
104
  onBatch: (rows, cols) => {
105
105
  profiler.addBatch(rows, cols);
@@ -115,9 +115,9 @@ class DataIndexer {
115
115
  this.db.run("DELETE FROM data_columns WHERE dataset_id = ?", [datasetId]);
116
116
  this.db.run("DELETE FROM data_datasets WHERE id = ?", [datasetId]);
117
117
  this.db.run(`
118
- INSERT INTO data_datasets (id, file_path, format, row_count, column_count, file_size, content_hash, summary, indexed_at)
119
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
120
- `, [datasetId, relPath, parser.name, totalRows, columns.length, stat.size, contentHash, null, Date.now()]);
118
+ INSERT INTO data_datasets (id, file_path, format, row_count, column_count, file_size, content_hash, summary, indexed_at, metadata_json)
119
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
120
+ `, [datasetId, relPath, parser.name, totalRows, columns.length, stat.size, contentHash, null, Date.now(), metadataJson ?? null]);
121
121
  for (const col of columnProfiles) {
122
122
  this.db.run(`
123
123
  INSERT INTO data_columns (id, dataset_id, name, position, inferred_type, nullable, null_count, null_pct, cardinality, min_value, max_value, mean_value, sample_values, summary, updated_at)
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/data/indexer.ts"],
4
- "sourcesContent": ["/**\n * Data Indexer\n *\n * Orchestrates: scan data files \u2192 parse \u2192 profile columns \u2192 persist rows to SQLite.\n * Supports incremental re-indexing via content hashes.\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport * as crypto from 'crypto';\nimport picomatch from 'picomatch';\nimport type { KiroGraphConfig } from '../config';\nimport type { DataSet, DataColumn, DataIndexResult, ParsedRow } from './types';\nimport { getDataParser } from './parsers/index';\nimport { ColumnProfiler } from './profiler';\n\n/**\n * Generate a dataset ID from a file path.\n * Slugifies the relative path: tests/fixtures/users.csv \u2192 tests-fixtures-users\n */\nfunction generateDatasetId(filePath: string): string {\n return filePath\n .replace(/\\.[^.]+$/, '') // remove extension\n .replace(/[/\\\\]/g, '-') // replace path separators\n .replace(/[^a-zA-Z0-9-_]/g, '-') // replace special chars\n .replace(/-+/g, '-') // collapse multiple dashes\n .replace(/^-|-$/g, '') // trim leading/trailing dashes\n .toLowerCase();\n}\n\nexport class DataIndexer {\n private readonly db: any;\n private readonly config: KiroGraphConfig;\n private readonly projectRoot: string;\n\n constructor(db: any, config: KiroGraphConfig, projectRoot: string) {\n this.db = db;\n this.config = config;\n this.projectRoot = projectRoot;\n }\n\n async indexAll(opts?: { force?: boolean; onProgress?: (msg: string) => void }): Promise<DataIndexResult> {\n const start = Date.now();\n const result: DataIndexResult = {\n datasetsIndexed: 0, rowsIndexed: 0, columnsProfiled: 0, errors: [], duration: 0,\n };\n\n const files = this.scanDataFiles();\n opts?.onProgress?.(`data: found ${files.length} data files`);\n\n for (const relPath of files) {\n try {\n const indexed = await this.indexFile(relPath, opts?.force ?? false);\n if (indexed) {\n result.datasetsIndexed++;\n result.rowsIndexed += indexed.rows;\n result.columnsProfiled += indexed.columns;\n }\n } catch (err) {\n result.errors.push(`${relPath}: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n // Remove datasets for files that no longer exist\n this.removeDeletedDatasets(files);\n\n // Link data files to code (if enabled)\n if ((this.config as any).dataLinkCode !== false && result.datasetsIndexed > 0) {\n try {\n const { DataCodeLinker } = await Promise.resolve().then(() => require('./linker.js'));\n const linker = new DataCodeLinker(this.db, this.projectRoot);\n const refsCreated = linker.linkAll();\n opts?.onProgress?.(`data: linked ${refsCreated} code references`);\n } catch {\n // Non-critical \u2014 linking failure shouldn't block indexing\n }\n }\n\n result.duration = Date.now() - start;\n return result;\n }\n\n async indexFile(relPath: string, force = false): Promise<{ rows: number; columns: number } | null> {\n const absPath = path.join(this.projectRoot, relPath);\n if (!fs.existsSync(absPath)) return null;\n\n const stat = fs.statSync(absPath);\n if (stat.size > (this.config as any).dataMaxFileSize) return null;\n\n // Check content hash for incremental\n const fileBuffer = fs.readFileSync(absPath);\n const contentHash = crypto.createHash('sha256').update(fileBuffer).digest('hex');\n\n const datasetId = generateDatasetId(relPath);\n\n if (!force) {\n const existing = this.db.get('SELECT content_hash FROM data_datasets WHERE id = ?', [datasetId]);\n if (existing?.content_hash === contentHash) return null; // unchanged\n }\n\n // Get parser\n const parser = getDataParser(relPath);\n if (!parser) return null;\n\n // Parse and profile\n const profiler = new ColumnProfiler();\n const allRows: ParsedRow[] = [];\n const maxRows = (this.config as any).dataMaxRows ?? 1_000_000;\n\n const { columns, totalRows } = await parser.parse(absPath, {\n maxRows,\n onBatch: (rows, cols) => {\n profiler.addBatch(rows, cols);\n allRows.push(...rows);\n },\n });\n\n if (columns.length === 0) return null;\n\n // Finalize profiles\n const columnProfiles = profiler.finalize(datasetId);\n\n // Persist in transaction\n this.db.run('BEGIN');\n try {\n // Delete old dataset data\n const rowTableName = `data_rows_${datasetId.replace(/[^a-zA-Z0-9_]/g, '_')}`;\n this.db.run(`DROP TABLE IF EXISTS \"${rowTableName}\"`);\n this.db.run('DELETE FROM data_columns WHERE dataset_id = ?', [datasetId]);\n this.db.run('DELETE FROM data_datasets WHERE id = ?', [datasetId]);\n\n // Insert dataset\n this.db.run(`\n INSERT INTO data_datasets (id, file_path, format, row_count, column_count, file_size, content_hash, summary, indexed_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\n `, [datasetId, relPath, parser.name, totalRows, columns.length, stat.size, contentHash, null, Date.now()]);\n\n // Insert column profiles\n for (const col of columnProfiles) {\n this.db.run(`\n INSERT INTO data_columns (id, dataset_id, name, position, inferred_type, nullable, null_count, null_pct, cardinality, min_value, max_value, mean_value, sample_values, summary, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `, [\n col.id, col.datasetId, col.name, col.position, col.inferredType,\n col.nullable ? 1 : 0, col.nullCount, col.nullPct, col.cardinality,\n col.minValue, col.maxValue, col.meanValue,\n JSON.stringify(col.sampleValues), col.summary, col.updatedAt,\n ]);\n }\n\n // Create row table with dynamic schema\n const colDefs = columns.map(c => `\"${c.replace(/\"/g, '\"\"')}\" TEXT`).join(', ');\n this.db.run(`CREATE TABLE \"${rowTableName}\" (rowid INTEGER PRIMARY KEY AUTOINCREMENT, ${colDefs})`);\n\n // Insert rows in batches\n const colNames = columns.map(c => `\"${c.replace(/\"/g, '\"\"')}\"`).join(', ');\n const placeholders = columns.map(() => '?').join(', ');\n const insertStmt = `INSERT INTO \"${rowTableName}\" (${colNames}) VALUES (${placeholders})`;\n\n for (const row of allRows) {\n const values = columns.map(c => {\n const v = row[c];\n if (v === null || v === undefined) return null;\n if (typeof v === 'object') return JSON.stringify(v);\n return v;\n });\n this.db.run(insertStmt, values);\n }\n\n // Save history snapshot for drift detection\n const historyColumns = columnProfiles.map(col => ({\n name: col.name,\n type: col.inferredType,\n cardinality: col.cardinality,\n nullPct: col.nullPct,\n }));\n this.db.run(`\n INSERT INTO data_dataset_history (dataset_id, snapshot_at, row_count, column_count, columns_json, content_hash)\n VALUES (?, ?, ?, ?, ?, ?)\n `, [datasetId, Date.now(), totalRows, columns.length, JSON.stringify(historyColumns), contentHash]);\n\n this.db.run('COMMIT');\n } catch (err) {\n this.db.run('ROLLBACK');\n throw err;\n }\n\n return { rows: totalRows, columns: columns.length };\n }\n\n // \u2500\u2500 Private \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n private scanDataFiles(): string[] {\n const includePatterns = (this.config as any).dataInclude ?? [];\n const excludePatterns = (this.config as any).dataExclude ?? [];\n const includeMatchers = includePatterns.map((p: string) => picomatch(p));\n const excludeMatchers = excludePatterns.map((p: string) => picomatch(p));\n const results: string[] = [];\n\n const walk = (dir: string) => {\n let entries: fs.Dirent[];\n try { entries = fs.readdirSync(dir, { withFileTypes: true }); } catch { return; }\n\n for (const entry of entries) {\n const full = path.join(dir, entry.name);\n const rel = path.relative(this.projectRoot, full).replace(/\\\\/g, '/');\n\n if (entry.isDirectory()) {\n if (excludeMatchers.some((m: any) => m(rel + '/'))) continue;\n walk(full);\n } else if (entry.isFile()) {\n if (excludeMatchers.some((m: any) => m(rel))) continue;\n if (includeMatchers.some((m: any) => m(rel))) {\n // Verify a parser exists for this format\n if (getDataParser(rel)) {\n results.push(rel);\n }\n }\n }\n }\n };\n\n walk(this.projectRoot);\n return results;\n }\n\n private removeDeletedDatasets(currentFiles: string[]): void {\n const currentSet = new Set(currentFiles.map(f => generateDatasetId(f)));\n const indexed = (this.db.all('SELECT id FROM data_datasets') as Array<{ id: string }>).map(r => r.id);\n\n for (const id of indexed) {\n if (!currentSet.has(id)) {\n const rowTableName = `data_rows_${id.replace(/[^a-zA-Z0-9_]/g, '_')}`;\n this.db.run(`DROP TABLE IF EXISTS \"${rowTableName}\"`);\n this.db.run('DELETE FROM data_columns WHERE dataset_id = ?', [id]);\n this.db.run('DELETE FROM data_code_refs WHERE dataset_id = ?', [id]);\n this.db.run('DELETE FROM data_datasets WHERE id = ?', [id]);\n }\n }\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * Data Indexer\n *\n * Orchestrates: scan data files \u2192 parse \u2192 profile columns \u2192 persist rows to SQLite.\n * Supports incremental re-indexing via content hashes.\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport * as crypto from 'crypto';\nimport picomatch from 'picomatch';\nimport type { KiroGraphConfig } from '../config';\nimport type { DataSet, DataColumn, DataIndexResult, ParsedRow } from './types';\nimport { getDataParser } from './parsers/index';\nimport { ColumnProfiler } from './profiler';\n\n/**\n * Generate a dataset ID from a file path.\n * Slugifies the relative path: tests/fixtures/users.csv \u2192 tests-fixtures-users\n */\nfunction generateDatasetId(filePath: string): string {\n return filePath\n .replace(/\\.[^.]+$/, '') // remove extension\n .replace(/[/\\\\]/g, '-') // replace path separators\n .replace(/[^a-zA-Z0-9-_]/g, '-') // replace special chars\n .replace(/-+/g, '-') // collapse multiple dashes\n .replace(/^-|-$/g, '') // trim leading/trailing dashes\n .toLowerCase();\n}\n\nexport class DataIndexer {\n private readonly db: any;\n private readonly config: KiroGraphConfig;\n private readonly projectRoot: string;\n\n constructor(db: any, config: KiroGraphConfig, projectRoot: string) {\n this.db = db;\n this.config = config;\n this.projectRoot = projectRoot;\n }\n\n async indexAll(opts?: { force?: boolean; onProgress?: (msg: string) => void }): Promise<DataIndexResult> {\n const start = Date.now();\n const result: DataIndexResult = {\n datasetsIndexed: 0, rowsIndexed: 0, columnsProfiled: 0, errors: [], duration: 0,\n };\n\n const files = this.scanDataFiles();\n opts?.onProgress?.(`data: found ${files.length} data files`);\n\n for (const relPath of files) {\n try {\n const indexed = await this.indexFile(relPath, opts?.force ?? false);\n if (indexed) {\n result.datasetsIndexed++;\n result.rowsIndexed += indexed.rows;\n result.columnsProfiled += indexed.columns;\n }\n } catch (err) {\n result.errors.push(`${relPath}: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n // Remove datasets for files that no longer exist\n this.removeDeletedDatasets(files);\n\n // Link data files to code (if enabled)\n if ((this.config as any).dataLinkCode !== false && result.datasetsIndexed > 0) {\n try {\n const { DataCodeLinker } = await Promise.resolve().then(() => require('./linker.js'));\n const linker = new DataCodeLinker(this.db, this.projectRoot);\n const refsCreated = linker.linkAll();\n opts?.onProgress?.(`data: linked ${refsCreated} code references`);\n } catch {\n // Non-critical \u2014 linking failure shouldn't block indexing\n }\n }\n\n result.duration = Date.now() - start;\n return result;\n }\n\n async indexFile(relPath: string, force = false): Promise<{ rows: number; columns: number } | null> {\n const absPath = path.join(this.projectRoot, relPath);\n if (!fs.existsSync(absPath)) return null;\n\n const stat = fs.statSync(absPath);\n if (stat.size > (this.config as any).dataMaxFileSize) return null;\n\n // Check content hash for incremental\n const fileBuffer = fs.readFileSync(absPath);\n const contentHash = crypto.createHash('sha256').update(fileBuffer).digest('hex');\n\n const datasetId = generateDatasetId(relPath);\n\n if (!force) {\n const existing = this.db.get('SELECT content_hash FROM data_datasets WHERE id = ?', [datasetId]);\n if (existing?.content_hash === contentHash) return null; // unchanged\n }\n\n // Get parser\n const parser = getDataParser(relPath);\n if (!parser) return null;\n\n // Parse and profile\n const profiler = new ColumnProfiler();\n const allRows: ParsedRow[] = [];\n const maxRows = (this.config as any).dataMaxRows ?? 1_000_000;\n\n const { columns, totalRows, metadataJson } = await parser.parse(absPath, {\n maxRows,\n onBatch: (rows, cols) => {\n profiler.addBatch(rows, cols);\n allRows.push(...rows);\n },\n });\n\n if (columns.length === 0) return null;\n\n // Finalize profiles\n const columnProfiles = profiler.finalize(datasetId);\n\n // Persist in transaction\n this.db.run('BEGIN');\n try {\n // Delete old dataset data\n const rowTableName = `data_rows_${datasetId.replace(/[^a-zA-Z0-9_]/g, '_')}`;\n this.db.run(`DROP TABLE IF EXISTS \"${rowTableName}\"`);\n this.db.run('DELETE FROM data_columns WHERE dataset_id = ?', [datasetId]);\n this.db.run('DELETE FROM data_datasets WHERE id = ?', [datasetId]);\n\n // Insert dataset\n this.db.run(`\n INSERT INTO data_datasets (id, file_path, format, row_count, column_count, file_size, content_hash, summary, indexed_at, metadata_json)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `, [datasetId, relPath, parser.name, totalRows, columns.length, stat.size, contentHash, null, Date.now(), metadataJson ?? null]);\n\n // Insert column profiles\n for (const col of columnProfiles) {\n this.db.run(`\n INSERT INTO data_columns (id, dataset_id, name, position, inferred_type, nullable, null_count, null_pct, cardinality, min_value, max_value, mean_value, sample_values, summary, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `, [\n col.id, col.datasetId, col.name, col.position, col.inferredType,\n col.nullable ? 1 : 0, col.nullCount, col.nullPct, col.cardinality,\n col.minValue, col.maxValue, col.meanValue,\n JSON.stringify(col.sampleValues), col.summary, col.updatedAt,\n ]);\n }\n\n // Create row table with dynamic schema\n const colDefs = columns.map(c => `\"${c.replace(/\"/g, '\"\"')}\" TEXT`).join(', ');\n this.db.run(`CREATE TABLE \"${rowTableName}\" (rowid INTEGER PRIMARY KEY AUTOINCREMENT, ${colDefs})`);\n\n // Insert rows in batches\n const colNames = columns.map(c => `\"${c.replace(/\"/g, '\"\"')}\"`).join(', ');\n const placeholders = columns.map(() => '?').join(', ');\n const insertStmt = `INSERT INTO \"${rowTableName}\" (${colNames}) VALUES (${placeholders})`;\n\n for (const row of allRows) {\n const values = columns.map(c => {\n const v = row[c];\n if (v === null || v === undefined) return null;\n if (typeof v === 'object') return JSON.stringify(v);\n return v;\n });\n this.db.run(insertStmt, values);\n }\n\n // Save history snapshot for drift detection\n const historyColumns = columnProfiles.map(col => ({\n name: col.name,\n type: col.inferredType,\n cardinality: col.cardinality,\n nullPct: col.nullPct,\n }));\n this.db.run(`\n INSERT INTO data_dataset_history (dataset_id, snapshot_at, row_count, column_count, columns_json, content_hash)\n VALUES (?, ?, ?, ?, ?, ?)\n `, [datasetId, Date.now(), totalRows, columns.length, JSON.stringify(historyColumns), contentHash]);\n\n this.db.run('COMMIT');\n } catch (err) {\n this.db.run('ROLLBACK');\n throw err;\n }\n\n return { rows: totalRows, columns: columns.length };\n }\n\n // \u2500\u2500 Private \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n private scanDataFiles(): string[] {\n const includePatterns = (this.config as any).dataInclude ?? [];\n const excludePatterns = (this.config as any).dataExclude ?? [];\n const includeMatchers = includePatterns.map((p: string) => picomatch(p));\n const excludeMatchers = excludePatterns.map((p: string) => picomatch(p));\n const results: string[] = [];\n\n const walk = (dir: string) => {\n let entries: fs.Dirent[];\n try { entries = fs.readdirSync(dir, { withFileTypes: true }); } catch { return; }\n\n for (const entry of entries) {\n const full = path.join(dir, entry.name);\n const rel = path.relative(this.projectRoot, full).replace(/\\\\/g, '/');\n\n if (entry.isDirectory()) {\n if (excludeMatchers.some((m: any) => m(rel + '/'))) continue;\n walk(full);\n } else if (entry.isFile()) {\n if (excludeMatchers.some((m: any) => m(rel))) continue;\n if (includeMatchers.some((m: any) => m(rel))) {\n // Verify a parser exists for this format\n if (getDataParser(rel)) {\n results.push(rel);\n }\n }\n }\n }\n };\n\n walk(this.projectRoot);\n return results;\n }\n\n private removeDeletedDatasets(currentFiles: string[]): void {\n const currentSet = new Set(currentFiles.map(f => generateDatasetId(f)));\n const indexed = (this.db.all('SELECT id FROM data_datasets') as Array<{ id: string }>).map(r => r.id);\n\n for (const id of indexed) {\n if (!currentSet.has(id)) {\n const rowTableName = `data_rows_${id.replace(/[^a-zA-Z0-9_]/g, '_')}`;\n this.db.run(`DROP TABLE IF EXISTS \"${rowTableName}\"`);\n this.db.run('DELETE FROM data_columns WHERE dataset_id = ?', [id]);\n this.db.run('DELETE FROM data_code_refs WHERE dataset_id = ?', [id]);\n this.db.run('DELETE FROM data_datasets WHERE id = ?', [id]);\n }\n }\n }\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAOA,SAAoB;AACpB,WAAsB;AACtB,aAAwB;AACxB,uBAAsB;AAGtB,qBAA8B;AAC9B,sBAA+B;AAM/B,SAAS,kBAAkB,UAA0B;AACnD,SAAO,SACJ,QAAQ,YAAY,EAAE,EACtB,QAAQ,UAAU,GAAG,EACrB,QAAQ,mBAAmB,GAAG,EAC9B,QAAQ,OAAO,GAAG,EAClB,QAAQ,UAAU,EAAE,EACpB,YAAY;AACjB;AAEO,MAAM,YAAY;AAAA,EAKvB,YAAY,IAAS,QAAyB,aAAqB;AACjE,SAAK,KAAK;AACV,SAAK,SAAS;AACd,SAAK,cAAc;AAAA,EACrB;AAAA,EAEA,MAAM,SAAS,MAA0F;AACvG,UAAM,QAAQ,KAAK,IAAI;AACvB,UAAM,SAA0B;AAAA,MAC9B,iBAAiB;AAAA,MAAG,aAAa;AAAA,MAAG,iBAAiB;AAAA,MAAG,QAAQ,CAAC;AAAA,MAAG,UAAU;AAAA,IAChF;AAEA,UAAM,QAAQ,KAAK,cAAc;AACjC,UAAM,aAAa,eAAe,MAAM,MAAM,aAAa;AAE3D,eAAW,WAAW,OAAO;AAC3B,UAAI;AACF,cAAM,UAAU,MAAM,KAAK,UAAU,SAAS,MAAM,SAAS,KAAK;AAClE,YAAI,SAAS;AACX,iBAAO;AACP,iBAAO,eAAe,QAAQ;AAC9B,iBAAO,mBAAmB,QAAQ;AAAA,QACpC;AAAA,MACF,SAAS,KAAK;AACZ,eAAO,OAAO,KAAK,GAAG,OAAO,KAAK,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,EAAE;AAAA,MACtF;AAAA,IACF;AAGA,SAAK,sBAAsB,KAAK;AAGhC,QAAK,KAAK,OAAe,iBAAiB,SAAS,OAAO,kBAAkB,GAAG;AAC7E,UAAI;AACF,cAAM,EAAE,eAAe,IAAI,MAAM,QAAQ,QAAQ,EAAE,KAAK,MAAM,QAAQ,aAAa,CAAC;AACpF,cAAM,SAAS,IAAI,eAAe,KAAK,IAAI,KAAK,WAAW;AAC3D,cAAM,cAAc,OAAO,QAAQ;AACnC,cAAM,aAAa,gBAAgB,WAAW,kBAAkB;AAAA,MAClE,QAAQ;AAAA,MAER;AAAA,IACF;AAEA,WAAO,WAAW,KAAK,IAAI,IAAI;AAC/B,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,UAAU,SAAiB,QAAQ,OAA0D;AACjG,UAAM,UAAU,KAAK,KAAK,KAAK,aAAa,OAAO;AACnD,QAAI,CAAC,GAAG,WAAW,OAAO,EAAG,QAAO;AAEpC,UAAM,OAAO,GAAG,SAAS,OAAO;AAChC,QAAI,KAAK,OAAQ,KAAK,OAAe,gBAAiB,QAAO;AAG7D,UAAM,aAAa,GAAG,aAAa,OAAO;AAC1C,UAAM,cAAc,OAAO,WAAW,QAAQ,EAAE,OAAO,UAAU,EAAE,OAAO,KAAK;AAE/E,UAAM,YAAY,kBAAkB,OAAO;AAE3C,QAAI,CAAC,OAAO;AACV,YAAM,WAAW,KAAK,GAAG,IAAI,uDAAuD,CAAC,SAAS,CAAC;AAC/F,UAAI,UAAU,iBAAiB,YAAa,QAAO;AAAA,IACrD;AAGA,UAAM,aAAS,8BAAc,OAAO;AACpC,QAAI,CAAC,OAAQ,QAAO;AAGpB,UAAM,WAAW,IAAI,+BAAe;AACpC,UAAM,UAAuB,CAAC;AAC9B,UAAM,UAAW,KAAK,OAAe,eAAe;AAEpD,UAAM,EAAE,SAAS,WAAW,aAAa,IAAI,MAAM,OAAO,MAAM,SAAS;AAAA,MACvE;AAAA,MACA,SAAS,CAAC,MAAM,SAAS;AACvB,iBAAS,SAAS,MAAM,IAAI;AAC5B,gBAAQ,KAAK,GAAG,IAAI;AAAA,MACtB;AAAA,IACF,CAAC;AAED,QAAI,QAAQ,WAAW,EAAG,QAAO;AAGjC,UAAM,iBAAiB,SAAS,SAAS,SAAS;AAGlD,SAAK,GAAG,IAAI,OAAO;AACnB,QAAI;AAEF,YAAM,eAAe,aAAa,UAAU,QAAQ,kBAAkB,GAAG,CAAC;AAC1E,WAAK,GAAG,IAAI,yBAAyB,YAAY,GAAG;AACpD,WAAK,GAAG,IAAI,iDAAiD,CAAC,SAAS,CAAC;AACxE,WAAK,GAAG,IAAI,0CAA0C,CAAC,SAAS,CAAC;AAGjE,WAAK,GAAG,IAAI;AAAA;AAAA;AAAA,SAGT,CAAC,WAAW,SAAS,OAAO,MAAM,WAAW,QAAQ,QAAQ,KAAK,MAAM,aAAa,MAAM,KAAK,IAAI,GAAG,gBAAgB,IAAI,CAAC;AAG/H,iBAAW,OAAO,gBAAgB;AAChC,aAAK,GAAG,IAAI;AAAA;AAAA;AAAA,WAGT;AAAA,UACD,IAAI;AAAA,UAAI,IAAI;AAAA,UAAW,IAAI;AAAA,UAAM,IAAI;AAAA,UAAU,IAAI;AAAA,UACnD,IAAI,WAAW,IAAI;AAAA,UAAG,IAAI;AAAA,UAAW,IAAI;AAAA,UAAS,IAAI;AAAA,UACtD,IAAI;AAAA,UAAU,IAAI;AAAA,UAAU,IAAI;AAAA,UAChC,KAAK,UAAU,IAAI,YAAY;AAAA,UAAG,IAAI;AAAA,UAAS,IAAI;AAAA,QACrD,CAAC;AAAA,MACH;AAGA,YAAM,UAAU,QAAQ,IAAI,OAAK,IAAI,EAAE,QAAQ,MAAM,IAAI,CAAC,QAAQ,EAAE,KAAK,IAAI;AAC7E,WAAK,GAAG,IAAI,iBAAiB,YAAY,+CAA+C,OAAO,GAAG;AAGlG,YAAM,WAAW,QAAQ,IAAI,OAAK,IAAI,EAAE,QAAQ,MAAM,IAAI,CAAC,GAAG,EAAE,KAAK,IAAI;AACzE,YAAM,eAAe,QAAQ,IAAI,MAAM,GAAG,EAAE,KAAK,IAAI;AACrD,YAAM,aAAa,gBAAgB,YAAY,MAAM,QAAQ,aAAa,YAAY;AAEtF,iBAAW,OAAO,SAAS;AACzB,cAAM,SAAS,QAAQ,IAAI,OAAK;AAC9B,gBAAM,IAAI,IAAI,CAAC;AACf,cAAI,MAAM,QAAQ,MAAM,OAAW,QAAO;AAC1C,cAAI,OAAO,MAAM,SAAU,QAAO,KAAK,UAAU,CAAC;AAClD,iBAAO;AAAA,QACT,CAAC;AACD,aAAK,GAAG,IAAI,YAAY,MAAM;AAAA,MAChC;AAGA,YAAM,iBAAiB,eAAe,IAAI,UAAQ;AAAA,QAChD,MAAM,IAAI;AAAA,QACV,MAAM,IAAI;AAAA,QACV,aAAa,IAAI;AAAA,QACjB,SAAS,IAAI;AAAA,MACf,EAAE;AACF,WAAK,GAAG,IAAI;AAAA;AAAA;AAAA,SAGT,CAAC,WAAW,KAAK,IAAI,GAAG,WAAW,QAAQ,QAAQ,KAAK,UAAU,cAAc,GAAG,WAAW,CAAC;AAElG,WAAK,GAAG,IAAI,QAAQ;AAAA,IACtB,SAAS,KAAK;AACZ,WAAK,GAAG,IAAI,UAAU;AACtB,YAAM;AAAA,IACR;AAEA,WAAO,EAAE,MAAM,WAAW,SAAS,QAAQ,OAAO;AAAA,EACpD;AAAA;AAAA,EAIQ,gBAA0B;AAChC,UAAM,kBAAmB,KAAK,OAAe,eAAe,CAAC;AAC7D,UAAM,kBAAmB,KAAK,OAAe,eAAe,CAAC;AAC7D,UAAM,kBAAkB,gBAAgB,IAAI,CAAC,UAAc,iBAAAA,SAAU,CAAC,CAAC;AACvE,UAAM,kBAAkB,gBAAgB,IAAI,CAAC,UAAc,iBAAAA,SAAU,CAAC,CAAC;AACvE,UAAM,UAAoB,CAAC;AAE3B,UAAM,OAAO,CAAC,QAAgB;AAC5B,UAAI;AACJ,UAAI;AAAE,kBAAU,GAAG,YAAY,KAAK,EAAE,eAAe,KAAK,CAAC;AAAA,MAAG,QAAQ;AAAE;AAAA,MAAQ;AAEhF,iBAAW,SAAS,SAAS;AAC3B,cAAM,OAAO,KAAK,KAAK,KAAK,MAAM,IAAI;AACtC,cAAM,MAAM,KAAK,SAAS,KAAK,aAAa,IAAI,EAAE,QAAQ,OAAO,GAAG;AAEpE,YAAI,MAAM,YAAY,GAAG;AACvB,cAAI,gBAAgB,KAAK,CAAC,MAAW,EAAE,MAAM,GAAG,CAAC,EAAG;AACpD,eAAK,IAAI;AAAA,QACX,WAAW,MAAM,OAAO,GAAG;AACzB,cAAI,gBAAgB,KAAK,CAAC,MAAW,EAAE,GAAG,CAAC,EAAG;AAC9C,cAAI,gBAAgB,KAAK,CAAC,MAAW,EAAE,GAAG,CAAC,GAAG;AAE5C,oBAAI,8BAAc,GAAG,GAAG;AACtB,sBAAQ,KAAK,GAAG;AAAA,YAClB;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,SAAK,KAAK,WAAW;AACrB,WAAO;AAAA,EACT;AAAA,EAEQ,sBAAsB,cAA8B;AAC1D,UAAM,aAAa,IAAI,IAAI,aAAa,IAAI,OAAK,kBAAkB,CAAC,CAAC,CAAC;AACtE,UAAM,UAAW,KAAK,GAAG,IAAI,8BAA8B,EAA4B,IAAI,OAAK,EAAE,EAAE;AAEpG,eAAW,MAAM,SAAS;AACxB,UAAI,CAAC,WAAW,IAAI,EAAE,GAAG;AACvB,cAAM,eAAe,aAAa,GAAG,QAAQ,kBAAkB,GAAG,CAAC;AACnE,aAAK,GAAG,IAAI,yBAAyB,YAAY,GAAG;AACpD,aAAK,GAAG,IAAI,iDAAiD,CAAC,EAAE,CAAC;AACjE,aAAK,GAAG,IAAI,mDAAmD,CAAC,EAAE,CAAC;AACnE,aAAK,GAAG,IAAI,0CAA0C,CAAC,EAAE,CAAC;AAAA,MAC5D;AAAA,IACF;AAAA,EACF;AACF;",
6
6
  "names": ["picomatch"]
7
7
  }
@@ -33,13 +33,17 @@ const READ_PATTERNS = [
33
33
  /read_json\s*\(\s*['"`]([^'"`]+)['"`]/g,
34
34
  /read_parquet\s*\(\s*['"`]([^'"`]+)['"`]/g,
35
35
  /read_table\s*\(\s*['"`]([^'"`]+)['"`]/g,
36
- // Python open
37
- /open\s*\(\s*['"`]([^'"`]+\.(?:csv|tsv|jsonl|ndjson|json|xlsx|xls|parquet))['"`]/g,
36
+ // Python open (includes PDF)
37
+ /open\s*\(\s*['"`]([^'"`]+\.(?:csv|tsv|jsonl|ndjson|json|xlsx|xls|parquet|pdf))['"`]/g,
38
+ // Python PDF libraries
39
+ /PdfReader\s*\(\s*['"`]([^'"`]+\.pdf)['"`]/g,
40
+ /pdfplumber\.open\s*\(\s*['"`]([^'"`]+\.pdf)['"`]/g,
41
+ /fitz\.open\s*\(\s*['"`]([^'"`]+\.pdf)['"`]/g,
38
42
  // SQL COPY
39
43
  /COPY\s+\w+\s+FROM\s+['"`]([^'"`]+)['"`]/gi,
40
44
  /\\copy\s+\w+\s+from\s+['"`]([^'"`]+)['"`]/gi,
41
45
  // Generic path references in strings (data file extensions)
42
- /['"`]((?:\.\.?\/)?(?:[\w\-./]+\/)?[\w\-]+\.(?:csv|tsv|jsonl|ndjson|xlsx|xls|parquet))['"`]/g
46
+ /['"`]((?:\.\.?\/)?(?:[\w\-./]+\/)?[\w\-]+\.(?:csv|tsv|jsonl|ndjson|xlsx|xls|parquet|pdf))['"`]/g
43
47
  ];
44
48
  const WRITE_PATTERNS = [
45
49
  /writeFileSync\s*\(\s*['"`]([^'"`]+\.(?:csv|tsv|jsonl|json|xlsx|parquet))['"`]/g,
@@ -92,7 +96,7 @@ function normalizePath(p) {
92
96
  function isDataFilePath(filePath, knownPaths) {
93
97
  if (knownPaths.has(filePath)) return true;
94
98
  const ext = filePath.split(".").pop()?.toLowerCase();
95
- return ["csv", "tsv", "jsonl", "ndjson", "json", "xlsx", "xls", "parquet"].includes(ext ?? "");
99
+ return ["csv", "tsv", "jsonl", "ndjson", "json", "xlsx", "xls", "parquet", "pdf"].includes(ext ?? "");
96
100
  }
97
101
  class DataCodeLinker {
98
102
  constructor(db, projectRoot) {
@@ -111,7 +115,7 @@ class DataCodeLinker {
111
115
  const knownPaths = new Set(datasets.map((d) => d.file_path));
112
116
  const pathToDatasetId = new Map(datasets.map((d) => [d.file_path, d.id]));
113
117
  const sourceFiles = this.db.all(
114
- `SELECT file_path FROM files WHERE file_path NOT LIKE '%.csv' AND file_path NOT LIKE '%.tsv' AND file_path NOT LIKE '%.jsonl' AND file_path NOT LIKE '%.ndjson' AND file_path NOT LIKE '%.xlsx' AND file_path NOT LIKE '%.parquet'`
118
+ `SELECT path AS file_path FROM files WHERE path NOT LIKE '%.csv' AND path NOT LIKE '%.tsv' AND path NOT LIKE '%.jsonl' AND path NOT LIKE '%.ndjson' AND path NOT LIKE '%.xlsx' AND path NOT LIKE '%.parquet' AND path NOT LIKE '%.pdf'`
115
119
  );
116
120
  this.db.run("DELETE FROM data_code_refs");
117
121
  let refsCreated = 0;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/data/linker.ts"],
4
- "sourcesContent": ["/**\n * Data \u2194 Code Linker\n *\n * Detects references to data files in source code and populates data_code_refs.\n * Patterns detected:\n * - readFileSync('data/users.csv'), readFile('path/to/file.csv')\n * - pd.read_csv('data/file.csv'), pd.read_excel(...)\n * - open('data/file.csv'), csv.reader(open(...))\n * - COPY FROM 'file.csv', \\copy ... from 'file.csv'\n * - require('./data/file.json'), import ... from './data/file.json'\n * - fs.createReadStream('data/file.csv')\n * - String literals matching known data file paths\n */\n\nimport type { DataCodeRef } from './types';\n\n/** Patterns that indicate a code symbol reads a data file */\nconst READ_PATTERNS = [\n // Node.js / TypeScript\n /readFileSync\\s*\\(\\s*['\"`]([^'\"`]+)['\"`]/g,\n /readFile\\s*\\(\\s*['\"`]([^'\"`]+)['\"`]/g,\n /createReadStream\\s*\\(\\s*['\"`]([^'\"`]+)['\"`]/g,\n // Python pandas\n /read_csv\\s*\\(\\s*['\"`]([^'\"`]+)['\"`]/g,\n /read_excel\\s*\\(\\s*['\"`]([^'\"`]+)['\"`]/g,\n /read_json\\s*\\(\\s*['\"`]([^'\"`]+)['\"`]/g,\n /read_parquet\\s*\\(\\s*['\"`]([^'\"`]+)['\"`]/g,\n /read_table\\s*\\(\\s*['\"`]([^'\"`]+)['\"`]/g,\n // Python open\n /open\\s*\\(\\s*['\"`]([^'\"`]+\\.(?:csv|tsv|jsonl|ndjson|json|xlsx|xls|parquet))['\"`]/g,\n // SQL COPY\n /COPY\\s+\\w+\\s+FROM\\s+['\"`]([^'\"`]+)['\"`]/gi,\n /\\\\copy\\s+\\w+\\s+from\\s+['\"`]([^'\"`]+)['\"`]/gi,\n // Generic path references in strings (data file extensions)\n /['\"`]((?:\\.\\.?\\/)?(?:[\\w\\-./]+\\/)?[\\w\\-]+\\.(?:csv|tsv|jsonl|ndjson|xlsx|xls|parquet))['\"`]/g,\n];\n\n/** Patterns that indicate a code symbol writes a data file */\nconst WRITE_PATTERNS = [\n /writeFileSync\\s*\\(\\s*['\"`]([^'\"`]+\\.(?:csv|tsv|jsonl|json|xlsx|parquet))['\"`]/g,\n /writeFile\\s*\\(\\s*['\"`]([^'\"`]+\\.(?:csv|tsv|jsonl|json|xlsx|parquet))['\"`]/g,\n /to_csv\\s*\\(\\s*['\"`]([^'\"`]+)['\"`]/g,\n /to_excel\\s*\\(\\s*['\"`]([^'\"`]+)['\"`]/g,\n /to_json\\s*\\(\\s*['\"`]([^'\"`]+)['\"`]/g,\n /to_parquet\\s*\\(\\s*['\"`]([^'\"`]+)['\"`]/g,\n /createWriteStream\\s*\\(\\s*['\"`]([^'\"`]+\\.(?:csv|tsv|jsonl|json|xlsx|parquet))['\"`]/g,\n /COPY\\s+\\w+\\s+TO\\s+['\"`]([^'\"`]+)['\"`]/gi,\n];\n\n/**\n * Scan source code content for references to data files.\n * Returns matched file paths with their reference type.\n */\nexport function detectDataReferences(\n sourceContent: string,\n knownDataPaths: Set<string>,\n): Array<{ filePath: string; refType: 'reads' | 'writes'; confidence: number }> {\n const refs = new Map<string, { refType: 'reads' | 'writes'; confidence: number }>();\n\n // Check read patterns\n for (const pattern of READ_PATTERNS) {\n pattern.lastIndex = 0;\n let match: RegExpExecArray | null;\n while ((match = pattern.exec(sourceContent)) !== null) {\n const filePath = normalizePath(match[1]!);\n if (isDataFilePath(filePath, knownDataPaths)) {\n const existing = refs.get(filePath);\n if (!existing || existing.confidence < 0.9) {\n const confidence = knownDataPaths.has(filePath) ? 1.0 : 0.7;\n refs.set(filePath, { refType: 'reads', confidence });\n }\n }\n }\n }\n\n // Check write patterns\n for (const pattern of WRITE_PATTERNS) {\n pattern.lastIndex = 0;\n let match: RegExpExecArray | null;\n while ((match = pattern.exec(sourceContent)) !== null) {\n const filePath = normalizePath(match[1]!);\n if (isDataFilePath(filePath, knownDataPaths)) {\n const confidence = knownDataPaths.has(filePath) ? 1.0 : 0.7;\n refs.set(filePath, { refType: 'writes', confidence });\n }\n }\n }\n\n return Array.from(refs.entries()).map(([filePath, info]) => ({\n filePath,\n ...info,\n }));\n}\n\n/**\n * Generate dataset ID from a file path (same logic as indexer).\n */\nfunction generateDatasetId(filePath: string): string {\n return filePath\n .replace(/\\.[^.]+$/, '')\n .replace(/[/\\\\]/g, '-')\n .replace(/[^a-zA-Z0-9-_]/g, '-')\n .replace(/-+/g, '-')\n .replace(/^-|-$/g, '')\n .toLowerCase();\n}\n\n/**\n * Normalize a path reference found in code.\n * Strips leading ./ and resolves simple relative paths.\n */\nfunction normalizePath(p: string): string {\n return p.replace(/^\\.\\//, '').replace(/\\\\/g, '/');\n}\n\n/**\n * Check if a path looks like a data file (by extension or known path match).\n */\nfunction isDataFilePath(filePath: string, knownPaths: Set<string>): boolean {\n if (knownPaths.has(filePath)) return true;\n // Check extension\n const ext = filePath.split('.').pop()?.toLowerCase();\n return ['csv', 'tsv', 'jsonl', 'ndjson', 'json', 'xlsx', 'xls', 'parquet'].includes(ext ?? '');\n}\n\n/**\n * Link data files to code symbols.\n * Scans all indexed source files for references to known data file paths.\n */\nexport class DataCodeLinker {\n private readonly db: any;\n private readonly projectRoot: string;\n\n constructor(db: any, projectRoot: string) {\n this.db = db;\n this.projectRoot = projectRoot;\n }\n\n /**\n * Populate data_code_refs by scanning source files for data file references.\n * Returns the number of refs created.\n */\n linkAll(): number {\n const fs = require('fs');\n const path = require('path');\n\n // Get all known data file paths\n const datasets = this.db.all('SELECT id, file_path FROM data_datasets') as Array<{ id: string; file_path: string }>;\n if (datasets.length === 0) return 0;\n\n const knownPaths = new Set(datasets.map(d => d.file_path));\n const pathToDatasetId = new Map(datasets.map(d => [d.file_path, d.id]));\n\n // Get all indexed source files (from the graph)\n const sourceFiles = this.db.all(\n `SELECT file_path FROM files WHERE file_path NOT LIKE '%.csv' AND file_path NOT LIKE '%.tsv' AND file_path NOT LIKE '%.jsonl' AND file_path NOT LIKE '%.ndjson' AND file_path NOT LIKE '%.xlsx' AND file_path NOT LIKE '%.parquet'`\n ) as Array<{ file_path: string }>;\n\n // Clear existing refs\n this.db.run('DELETE FROM data_code_refs');\n\n let refsCreated = 0;\n\n for (const file of sourceFiles) {\n const absPath = path.join(this.projectRoot, file.file_path);\n let content: string;\n try {\n content = fs.readFileSync(absPath, 'utf-8');\n } catch {\n continue;\n }\n\n const refs = detectDataReferences(content, knownPaths);\n if (refs.length === 0) continue;\n\n // Find the qualified_name of the containing symbol (file-level)\n // Use the file path as the qualified name for file-level refs\n const qualifiedName = file.file_path;\n\n for (const ref of refs) {\n const datasetId = pathToDatasetId.get(ref.filePath);\n if (!datasetId) continue;\n\n try {\n this.db.run(\n `INSERT OR REPLACE INTO data_code_refs (dataset_id, qualified_name, ref_type, confidence) VALUES (?, ?, ?, ?)`,\n [datasetId, qualifiedName, ref.refType, ref.confidence],\n );\n refsCreated++;\n } catch {\n // Ignore duplicates\n }\n }\n }\n\n return refsCreated;\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * Data \u2194 Code Linker\n *\n * Detects references to data files in source code and populates data_code_refs.\n * Patterns detected:\n * - readFileSync('data/users.csv'), readFile('path/to/file.csv')\n * - pd.read_csv('data/file.csv'), pd.read_excel(...)\n * - open('data/file.csv'), csv.reader(open(...))\n * - COPY FROM 'file.csv', \\copy ... from 'file.csv'\n * - require('./data/file.json'), import ... from './data/file.json'\n * - fs.createReadStream('data/file.csv')\n * - String literals matching known data file paths\n */\n\nimport type { DataCodeRef } from './types';\n\n/** Patterns that indicate a code symbol reads a data file */\nconst READ_PATTERNS = [\n // Node.js / TypeScript\n /readFileSync\\s*\\(\\s*['\"`]([^'\"`]+)['\"`]/g,\n /readFile\\s*\\(\\s*['\"`]([^'\"`]+)['\"`]/g,\n /createReadStream\\s*\\(\\s*['\"`]([^'\"`]+)['\"`]/g,\n // Python pandas\n /read_csv\\s*\\(\\s*['\"`]([^'\"`]+)['\"`]/g,\n /read_excel\\s*\\(\\s*['\"`]([^'\"`]+)['\"`]/g,\n /read_json\\s*\\(\\s*['\"`]([^'\"`]+)['\"`]/g,\n /read_parquet\\s*\\(\\s*['\"`]([^'\"`]+)['\"`]/g,\n /read_table\\s*\\(\\s*['\"`]([^'\"`]+)['\"`]/g,\n // Python open (includes PDF)\n /open\\s*\\(\\s*['\"`]([^'\"`]+\\.(?:csv|tsv|jsonl|ndjson|json|xlsx|xls|parquet|pdf))['\"`]/g,\n // Python PDF libraries\n /PdfReader\\s*\\(\\s*['\"`]([^'\"`]+\\.pdf)['\"`]/g,\n /pdfplumber\\.open\\s*\\(\\s*['\"`]([^'\"`]+\\.pdf)['\"`]/g,\n /fitz\\.open\\s*\\(\\s*['\"`]([^'\"`]+\\.pdf)['\"`]/g,\n // SQL COPY\n /COPY\\s+\\w+\\s+FROM\\s+['\"`]([^'\"`]+)['\"`]/gi,\n /\\\\copy\\s+\\w+\\s+from\\s+['\"`]([^'\"`]+)['\"`]/gi,\n // Generic path references in strings (data file extensions)\n /['\"`]((?:\\.\\.?\\/)?(?:[\\w\\-./]+\\/)?[\\w\\-]+\\.(?:csv|tsv|jsonl|ndjson|xlsx|xls|parquet|pdf))['\"`]/g,\n];\n\n/** Patterns that indicate a code symbol writes a data file */\nconst WRITE_PATTERNS = [\n /writeFileSync\\s*\\(\\s*['\"`]([^'\"`]+\\.(?:csv|tsv|jsonl|json|xlsx|parquet))['\"`]/g,\n /writeFile\\s*\\(\\s*['\"`]([^'\"`]+\\.(?:csv|tsv|jsonl|json|xlsx|parquet))['\"`]/g,\n /to_csv\\s*\\(\\s*['\"`]([^'\"`]+)['\"`]/g,\n /to_excel\\s*\\(\\s*['\"`]([^'\"`]+)['\"`]/g,\n /to_json\\s*\\(\\s*['\"`]([^'\"`]+)['\"`]/g,\n /to_parquet\\s*\\(\\s*['\"`]([^'\"`]+)['\"`]/g,\n /createWriteStream\\s*\\(\\s*['\"`]([^'\"`]+\\.(?:csv|tsv|jsonl|json|xlsx|parquet))['\"`]/g,\n /COPY\\s+\\w+\\s+TO\\s+['\"`]([^'\"`]+)['\"`]/gi,\n];\n\n/**\n * Scan source code content for references to data files.\n * Returns matched file paths with their reference type.\n */\nexport function detectDataReferences(\n sourceContent: string,\n knownDataPaths: Set<string>,\n): Array<{ filePath: string; refType: 'reads' | 'writes'; confidence: number }> {\n const refs = new Map<string, { refType: 'reads' | 'writes'; confidence: number }>();\n\n // Check read patterns\n for (const pattern of READ_PATTERNS) {\n pattern.lastIndex = 0;\n let match: RegExpExecArray | null;\n while ((match = pattern.exec(sourceContent)) !== null) {\n const filePath = normalizePath(match[1]!);\n if (isDataFilePath(filePath, knownDataPaths)) {\n const existing = refs.get(filePath);\n if (!existing || existing.confidence < 0.9) {\n const confidence = knownDataPaths.has(filePath) ? 1.0 : 0.7;\n refs.set(filePath, { refType: 'reads', confidence });\n }\n }\n }\n }\n\n // Check write patterns\n for (const pattern of WRITE_PATTERNS) {\n pattern.lastIndex = 0;\n let match: RegExpExecArray | null;\n while ((match = pattern.exec(sourceContent)) !== null) {\n const filePath = normalizePath(match[1]!);\n if (isDataFilePath(filePath, knownDataPaths)) {\n const confidence = knownDataPaths.has(filePath) ? 1.0 : 0.7;\n refs.set(filePath, { refType: 'writes', confidence });\n }\n }\n }\n\n return Array.from(refs.entries()).map(([filePath, info]) => ({\n filePath,\n ...info,\n }));\n}\n\n/**\n * Generate dataset ID from a file path (same logic as indexer).\n */\nfunction generateDatasetId(filePath: string): string {\n return filePath\n .replace(/\\.[^.]+$/, '')\n .replace(/[/\\\\]/g, '-')\n .replace(/[^a-zA-Z0-9-_]/g, '-')\n .replace(/-+/g, '-')\n .replace(/^-|-$/g, '')\n .toLowerCase();\n}\n\n/**\n * Normalize a path reference found in code.\n * Strips leading ./ and resolves simple relative paths.\n */\nfunction normalizePath(p: string): string {\n return p.replace(/^\\.\\//, '').replace(/\\\\/g, '/');\n}\n\n/**\n * Check if a path looks like a data file (by extension or known path match).\n */\nfunction isDataFilePath(filePath: string, knownPaths: Set<string>): boolean {\n if (knownPaths.has(filePath)) return true;\n // Check extension\n const ext = filePath.split('.').pop()?.toLowerCase();\n return ['csv', 'tsv', 'jsonl', 'ndjson', 'json', 'xlsx', 'xls', 'parquet', 'pdf'].includes(ext ?? '');\n}\n\n/**\n * Link data files to code symbols.\n * Scans all indexed source files for references to known data file paths.\n */\nexport class DataCodeLinker {\n private readonly db: any;\n private readonly projectRoot: string;\n\n constructor(db: any, projectRoot: string) {\n this.db = db;\n this.projectRoot = projectRoot;\n }\n\n /**\n * Populate data_code_refs by scanning source files for data file references.\n * Returns the number of refs created.\n */\n linkAll(): number {\n const fs = require('fs');\n const path = require('path');\n\n // Get all known data file paths\n const datasets = this.db.all('SELECT id, file_path FROM data_datasets') as Array<{ id: string; file_path: string }>;\n if (datasets.length === 0) return 0;\n\n const knownPaths = new Set(datasets.map(d => d.file_path));\n const pathToDatasetId = new Map(datasets.map(d => [d.file_path, d.id]));\n\n // Get all indexed source files (from the graph)\n // Note: files table uses 'path' as the column name, aliased to file_path for readability.\n const sourceFiles = this.db.all(\n `SELECT path AS file_path FROM files WHERE path NOT LIKE '%.csv' AND path NOT LIKE '%.tsv' AND path NOT LIKE '%.jsonl' AND path NOT LIKE '%.ndjson' AND path NOT LIKE '%.xlsx' AND path NOT LIKE '%.parquet' AND path NOT LIKE '%.pdf'`\n ) as Array<{ file_path: string }>;\n\n // Clear existing refs\n this.db.run('DELETE FROM data_code_refs');\n\n let refsCreated = 0;\n\n for (const file of sourceFiles) {\n const absPath = path.join(this.projectRoot, file.file_path);\n let content: string;\n try {\n content = fs.readFileSync(absPath, 'utf-8');\n } catch {\n continue;\n }\n\n const refs = detectDataReferences(content, knownPaths);\n if (refs.length === 0) continue;\n\n // Find the qualified_name of the containing symbol (file-level)\n // Use the file path as the qualified name for file-level refs\n const qualifiedName = file.file_path;\n\n for (const ref of refs) {\n const datasetId = pathToDatasetId.get(ref.filePath);\n if (!datasetId) continue;\n\n try {\n this.db.run(\n `INSERT OR REPLACE INTO data_code_refs (dataset_id, qualified_name, ref_type, confidence) VALUES (?, ?, ?, ?)`,\n [datasetId, qualifiedName, ref.refType, ref.confidence],\n );\n refsCreated++;\n } catch {\n // Ignore duplicates\n }\n }\n }\n\n return refsCreated;\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ var import_vitest = require("vitest");
3
+ var import_linker = require("./linker");
4
+ const KNOWN_PATHS = /* @__PURE__ */ new Set([
5
+ "data/report.pdf",
6
+ "docs/manual.pdf",
7
+ "data/users.csv"
8
+ ]);
9
+ (0, import_vitest.describe)("detectDataReferences \u2014 PDF patterns", () => {
10
+ (0, import_vitest.it)("detects readFileSync with .pdf path", () => {
11
+ const src = `const buf = readFileSync('data/report.pdf')`;
12
+ const refs = (0, import_linker.detectDataReferences)(src, KNOWN_PATHS);
13
+ (0, import_vitest.expect)(refs.some((r) => r.filePath === "data/report.pdf" && r.refType === "reads")).toBe(true);
14
+ });
15
+ (0, import_vitest.it)("detects createReadStream with .pdf path", () => {
16
+ const src = `fs.createReadStream('data/report.pdf')`;
17
+ const refs = (0, import_linker.detectDataReferences)(src, KNOWN_PATHS);
18
+ (0, import_vitest.expect)(refs.some((r) => r.filePath === "data/report.pdf")).toBe(true);
19
+ });
20
+ (0, import_vitest.it)("detects Python open() with .pdf extension", () => {
21
+ const src = `f = open('docs/manual.pdf', 'rb')`;
22
+ const refs = (0, import_linker.detectDataReferences)(src, KNOWN_PATHS);
23
+ (0, import_vitest.expect)(refs.some((r) => r.filePath === "docs/manual.pdf")).toBe(true);
24
+ });
25
+ (0, import_vitest.it)("detects PdfReader() call", () => {
26
+ const src = `reader = PdfReader('data/report.pdf')`;
27
+ const refs = (0, import_linker.detectDataReferences)(src, KNOWN_PATHS);
28
+ (0, import_vitest.expect)(refs.some((r) => r.filePath === "data/report.pdf")).toBe(true);
29
+ });
30
+ (0, import_vitest.it)("detects pdfplumber.open() call", () => {
31
+ const src = `with pdfplumber.open('data/report.pdf') as pdf:`;
32
+ const refs = (0, import_linker.detectDataReferences)(src, KNOWN_PATHS);
33
+ (0, import_vitest.expect)(refs.some((r) => r.filePath === "data/report.pdf")).toBe(true);
34
+ });
35
+ (0, import_vitest.it)("detects fitz.open() call", () => {
36
+ const src = `doc = fitz.open('docs/manual.pdf')`;
37
+ const refs = (0, import_linker.detectDataReferences)(src, KNOWN_PATHS);
38
+ (0, import_vitest.expect)(refs.some((r) => r.filePath === "docs/manual.pdf")).toBe(true);
39
+ });
40
+ (0, import_vitest.it)("detects generic string literal with .pdf extension", () => {
41
+ const src = `const path = 'data/report.pdf';`;
42
+ const refs = (0, import_linker.detectDataReferences)(src, KNOWN_PATHS);
43
+ (0, import_vitest.expect)(refs.some((r) => r.filePath === "data/report.pdf")).toBe(true);
44
+ });
45
+ (0, import_vitest.it)("gives confidence 1.0 for known paths, lower for unknown", () => {
46
+ const src = `readFileSync('data/report.pdf'); readFileSync('other/unknown.pdf')`;
47
+ const refs = (0, import_linker.detectDataReferences)(src, KNOWN_PATHS);
48
+ const known = refs.find((r) => r.filePath === "data/report.pdf");
49
+ const unknown = refs.find((r) => r.filePath === "other/unknown.pdf");
50
+ (0, import_vitest.expect)(known?.confidence).toBe(1);
51
+ (0, import_vitest.expect)(unknown?.confidence).toBeLessThan(1);
52
+ });
53
+ (0, import_vitest.it)("does not confuse .pdf with .csv patterns", () => {
54
+ const src = `readFileSync('data/users.csv')`;
55
+ const refs = (0, import_linker.detectDataReferences)(src, KNOWN_PATHS);
56
+ (0, import_vitest.expect)(refs.some((r) => r.filePath === "data/users.csv")).toBe(true);
57
+ (0, import_vitest.expect)(refs.some((r) => r.filePath?.endsWith(".pdf"))).toBe(false);
58
+ });
59
+ });
60
+ //# sourceMappingURL=linker.test.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/data/linker.test.ts"],
4
+ "sourcesContent": ["import { describe, it, expect } from 'vitest';\nimport { detectDataReferences } from './linker';\n\nconst KNOWN_PATHS = new Set([\n 'data/report.pdf',\n 'docs/manual.pdf',\n 'data/users.csv',\n]);\n\ndescribe('detectDataReferences \u2014 PDF patterns', () => {\n it('detects readFileSync with .pdf path', () => {\n const src = `const buf = readFileSync('data/report.pdf')`;\n const refs = detectDataReferences(src, KNOWN_PATHS);\n expect(refs.some(r => r.filePath === 'data/report.pdf' && r.refType === 'reads')).toBe(true);\n });\n\n it('detects createReadStream with .pdf path', () => {\n const src = `fs.createReadStream('data/report.pdf')`;\n const refs = detectDataReferences(src, KNOWN_PATHS);\n expect(refs.some(r => r.filePath === 'data/report.pdf')).toBe(true);\n });\n\n it('detects Python open() with .pdf extension', () => {\n const src = `f = open('docs/manual.pdf', 'rb')`;\n const refs = detectDataReferences(src, KNOWN_PATHS);\n expect(refs.some(r => r.filePath === 'docs/manual.pdf')).toBe(true);\n });\n\n it('detects PdfReader() call', () => {\n const src = `reader = PdfReader('data/report.pdf')`;\n const refs = detectDataReferences(src, KNOWN_PATHS);\n expect(refs.some(r => r.filePath === 'data/report.pdf')).toBe(true);\n });\n\n it('detects pdfplumber.open() call', () => {\n const src = `with pdfplumber.open('data/report.pdf') as pdf:`;\n const refs = detectDataReferences(src, KNOWN_PATHS);\n expect(refs.some(r => r.filePath === 'data/report.pdf')).toBe(true);\n });\n\n it('detects fitz.open() call', () => {\n const src = `doc = fitz.open('docs/manual.pdf')`;\n const refs = detectDataReferences(src, KNOWN_PATHS);\n expect(refs.some(r => r.filePath === 'docs/manual.pdf')).toBe(true);\n });\n\n it('detects generic string literal with .pdf extension', () => {\n const src = `const path = 'data/report.pdf';`;\n const refs = detectDataReferences(src, KNOWN_PATHS);\n expect(refs.some(r => r.filePath === 'data/report.pdf')).toBe(true);\n });\n\n it('gives confidence 1.0 for known paths, lower for unknown', () => {\n const src = `readFileSync('data/report.pdf'); readFileSync('other/unknown.pdf')`;\n const refs = detectDataReferences(src, KNOWN_PATHS);\n const known = refs.find(r => r.filePath === 'data/report.pdf');\n const unknown = refs.find(r => r.filePath === 'other/unknown.pdf');\n expect(known?.confidence).toBe(1.0);\n expect(unknown?.confidence).toBeLessThan(1.0);\n });\n\n it('does not confuse .pdf with .csv patterns', () => {\n const src = `readFileSync('data/users.csv')`;\n const refs = detectDataReferences(src, KNOWN_PATHS);\n expect(refs.some(r => r.filePath === 'data/users.csv')).toBe(true);\n expect(refs.some(r => r.filePath?.endsWith('.pdf'))).toBe(false);\n });\n});\n"],
5
+ "mappings": ";AAAA,oBAAqC;AACrC,oBAAqC;AAErC,MAAM,cAAc,oBAAI,IAAI;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAAA,IAED,wBAAS,4CAAuC,MAAM;AACpD,wBAAG,uCAAuC,MAAM;AAC9C,UAAM,MAAM;AACZ,UAAM,WAAO,oCAAqB,KAAK,WAAW;AAClD,8BAAO,KAAK,KAAK,OAAK,EAAE,aAAa,qBAAqB,EAAE,YAAY,OAAO,CAAC,EAAE,KAAK,IAAI;AAAA,EAC7F,CAAC;AAED,wBAAG,2CAA2C,MAAM;AAClD,UAAM,MAAM;AACZ,UAAM,WAAO,oCAAqB,KAAK,WAAW;AAClD,8BAAO,KAAK,KAAK,OAAK,EAAE,aAAa,iBAAiB,CAAC,EAAE,KAAK,IAAI;AAAA,EACpE,CAAC;AAED,wBAAG,6CAA6C,MAAM;AACpD,UAAM,MAAM;AACZ,UAAM,WAAO,oCAAqB,KAAK,WAAW;AAClD,8BAAO,KAAK,KAAK,OAAK,EAAE,aAAa,iBAAiB,CAAC,EAAE,KAAK,IAAI;AAAA,EACpE,CAAC;AAED,wBAAG,4BAA4B,MAAM;AACnC,UAAM,MAAM;AACZ,UAAM,WAAO,oCAAqB,KAAK,WAAW;AAClD,8BAAO,KAAK,KAAK,OAAK,EAAE,aAAa,iBAAiB,CAAC,EAAE,KAAK,IAAI;AAAA,EACpE,CAAC;AAED,wBAAG,kCAAkC,MAAM;AACzC,UAAM,MAAM;AACZ,UAAM,WAAO,oCAAqB,KAAK,WAAW;AAClD,8BAAO,KAAK,KAAK,OAAK,EAAE,aAAa,iBAAiB,CAAC,EAAE,KAAK,IAAI;AAAA,EACpE,CAAC;AAED,wBAAG,4BAA4B,MAAM;AACnC,UAAM,MAAM;AACZ,UAAM,WAAO,oCAAqB,KAAK,WAAW;AAClD,8BAAO,KAAK,KAAK,OAAK,EAAE,aAAa,iBAAiB,CAAC,EAAE,KAAK,IAAI;AAAA,EACpE,CAAC;AAED,wBAAG,sDAAsD,MAAM;AAC7D,UAAM,MAAM;AACZ,UAAM,WAAO,oCAAqB,KAAK,WAAW;AAClD,8BAAO,KAAK,KAAK,OAAK,EAAE,aAAa,iBAAiB,CAAC,EAAE,KAAK,IAAI;AAAA,EACpE,CAAC;AAED,wBAAG,2DAA2D,MAAM;AAClE,UAAM,MAAM;AACZ,UAAM,WAAO,oCAAqB,KAAK,WAAW;AAClD,UAAM,QAAQ,KAAK,KAAK,OAAK,EAAE,aAAa,iBAAiB;AAC7D,UAAM,UAAU,KAAK,KAAK,OAAK,EAAE,aAAa,mBAAmB;AACjE,8BAAO,OAAO,UAAU,EAAE,KAAK,CAAG;AAClC,8BAAO,SAAS,UAAU,EAAE,aAAa,CAAG;AAAA,EAC9C,CAAC;AAED,wBAAG,4CAA4C,MAAM;AACnD,UAAM,MAAM;AACZ,UAAM,WAAO,oCAAqB,KAAK,WAAW;AAClD,8BAAO,KAAK,KAAK,OAAK,EAAE,aAAa,gBAAgB,CAAC,EAAE,KAAK,IAAI;AACjE,8BAAO,KAAK,KAAK,OAAK,EAAE,UAAU,SAAS,MAAM,CAAC,CAAC,EAAE,KAAK,KAAK;AAAA,EACjE,CAAC;AACH,CAAC;",
6
+ "names": []
7
+ }
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var pdf_inspector_stub_exports = {};
20
+ __export(pdf_inspector_stub_exports, {
21
+ classifyPdf: () => classifyPdf,
22
+ extractPagesMarkdown: () => extractPagesMarkdown,
23
+ processPdf: () => processPdf
24
+ });
25
+ module.exports = __toCommonJS(pdf_inspector_stub_exports);
26
+ function extractPagesMarkdown(_buf) {
27
+ throw new Error("@firecrawl/pdf-inspector is not installed");
28
+ }
29
+ function processPdf(_buf) {
30
+ throw new Error("@firecrawl/pdf-inspector is not installed");
31
+ }
32
+ function classifyPdf(_buf) {
33
+ throw new Error("@firecrawl/pdf-inspector is not installed");
34
+ }
35
+ // Annotate the CommonJS export names for ESM import in node:
36
+ 0 && (module.exports = {
37
+ classifyPdf,
38
+ extractPagesMarkdown,
39
+ processPdf
40
+ });
41
+ //# sourceMappingURL=pdf-inspector-stub.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/data/parsers/__fixtures__/pdf-inspector-stub.ts"],
4
+ "sourcesContent": ["// Stub for @firecrawl/pdf-inspector used in tests.\n// Real package not installed \u2014 this stub allows require() to resolve.\n// vi.mock('@firecrawl/pdf-inspector', factory) overrides this in individual tests.\nexport function extractPagesMarkdown(_buf: Buffer): never {\n throw new Error('@firecrawl/pdf-inspector is not installed');\n}\nexport function processPdf(_buf: Buffer): never {\n throw new Error('@firecrawl/pdf-inspector is not installed');\n}\nexport function classifyPdf(_buf: Buffer): never {\n throw new Error('@firecrawl/pdf-inspector is not installed');\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGO,SAAS,qBAAqB,MAAqB;AACxD,QAAM,IAAI,MAAM,2CAA2C;AAC7D;AACO,SAAS,WAAW,MAAqB;AAC9C,QAAM,IAAI,MAAM,2CAA2C;AAC7D;AACO,SAAS,YAAY,MAAqB;AAC/C,QAAM,IAAI,MAAM,2CAA2C;AAC7D;",
6
+ "names": []
7
+ }
@@ -29,13 +29,15 @@ var import_jsonl = require("./jsonl");
29
29
  var import_json_array = require("./json-array");
30
30
  var import_excel = require("./excel");
31
31
  var import_parquet = require("./parquet");
32
+ var import_pdf = require("./pdf");
32
33
  const allParsers = [
33
34
  import_csv.csvParser,
34
35
  import_csv.tsvParser,
35
36
  import_jsonl.jsonlParser,
36
37
  import_json_array.jsonArrayParser,
37
38
  import_excel.excelParser,
38
- import_parquet.parquetParser
39
+ import_parquet.parquetParser,
40
+ import_pdf.pdfParser
39
41
  ];
40
42
  const extensionMap = /* @__PURE__ */ new Map();
41
43
  for (const parser of allParsers) {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/data/parsers/index.ts"],
4
- "sourcesContent": ["/**\n * Data Format Registry\n *\n * Maps file extensions to their appropriate parser.\n * Gracefully skips formats whose optional dependencies are not installed.\n */\n\nimport type { DataFormatParser } from '../types';\nimport { csvParser, tsvParser } from './csv';\nimport { jsonlParser } from './jsonl';\nimport { jsonArrayParser } from './json-array';\nimport { excelParser } from './excel';\nimport { parquetParser } from './parquet';\n\n// \u2500\u2500 Registry \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst allParsers: DataFormatParser[] = [\n csvParser,\n tsvParser,\n jsonlParser,\n jsonArrayParser,\n excelParser,\n parquetParser,\n];\n\n/** Extension \u2192 parser lookup */\nconst extensionMap = new Map<string, DataFormatParser>();\nfor (const parser of allParsers) {\n for (const ext of parser.extensions) {\n extensionMap.set(ext.toLowerCase(), parser);\n }\n}\n\n// \u2500\u2500 Public API \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Get the parser for a given file extension.\n * Returns null if no parser is registered or the optional dep is missing.\n */\nexport function getDataParser(filePath: string): DataFormatParser | null {\n const ext = filePath.slice(filePath.lastIndexOf('.')).toLowerCase();\n const parser = extensionMap.get(ext) ?? null;\n if (!parser) return null;\n if (!parser.isAvailable()) return null;\n return parser;\n}\n\n/**\n * Check if a file extension is supported for data parsing.\n */\nexport function isSupportedDataFormat(filePath: string): boolean {\n return getDataParser(filePath) !== null;\n}\n\n/**\n * Get all supported extensions (only those with available deps).\n */\nexport function getAvailableExtensions(): string[] {\n const available: string[] = [];\n for (const [ext, parser] of extensionMap) {\n if (parser.isAvailable()) available.push(ext);\n }\n return available;\n}\n\n/**\n * Get extensions that are registered but have missing optional deps.\n */\nexport function getUnavailableExtensions(): Array<{ ext: string; parser: string }> {\n const unavailable: Array<{ ext: string; parser: string }> = [];\n for (const [ext, parser] of extensionMap) {\n if (!parser.isAvailable()) {\n unavailable.push({ ext, parser: parser.name });\n }\n }\n return unavailable;\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA,iBAAqC;AACrC,mBAA4B;AAC5B,wBAAgC;AAChC,mBAA4B;AAC5B,qBAA8B;AAI9B,MAAM,aAAiC;AAAA,EACrC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAGA,MAAM,eAAe,oBAAI,IAA8B;AACvD,WAAW,UAAU,YAAY;AAC/B,aAAW,OAAO,OAAO,YAAY;AACnC,iBAAa,IAAI,IAAI,YAAY,GAAG,MAAM;AAAA,EAC5C;AACF;AAQO,SAAS,cAAc,UAA2C;AACvE,QAAM,MAAM,SAAS,MAAM,SAAS,YAAY,GAAG,CAAC,EAAE,YAAY;AAClE,QAAM,SAAS,aAAa,IAAI,GAAG,KAAK;AACxC,MAAI,CAAC,OAAQ,QAAO;AACpB,MAAI,CAAC,OAAO,YAAY,EAAG,QAAO;AAClC,SAAO;AACT;AAKO,SAAS,sBAAsB,UAA2B;AAC/D,SAAO,cAAc,QAAQ,MAAM;AACrC;AAKO,SAAS,yBAAmC;AACjD,QAAM,YAAsB,CAAC;AAC7B,aAAW,CAAC,KAAK,MAAM,KAAK,cAAc;AACxC,QAAI,OAAO,YAAY,EAAG,WAAU,KAAK,GAAG;AAAA,EAC9C;AACA,SAAO;AACT;AAKO,SAAS,2BAAmE;AACjF,QAAM,cAAsD,CAAC;AAC7D,aAAW,CAAC,KAAK,MAAM,KAAK,cAAc;AACxC,QAAI,CAAC,OAAO,YAAY,GAAG;AACzB,kBAAY,KAAK,EAAE,KAAK,QAAQ,OAAO,KAAK,CAAC;AAAA,IAC/C;AAAA,EACF;AACA,SAAO;AACT;",
4
+ "sourcesContent": ["/**\n * Data Format Registry\n *\n * Maps file extensions to their appropriate parser.\n * Gracefully skips formats whose optional dependencies are not installed.\n */\n\nimport type { DataFormatParser } from '../types';\nimport { csvParser, tsvParser } from './csv';\nimport { jsonlParser } from './jsonl';\nimport { jsonArrayParser } from './json-array';\nimport { excelParser } from './excel';\nimport { parquetParser } from './parquet';\nimport { pdfParser } from './pdf';\n\n// \u2500\u2500 Registry \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst allParsers: DataFormatParser[] = [\n csvParser,\n tsvParser,\n jsonlParser,\n jsonArrayParser,\n excelParser,\n parquetParser,\n pdfParser,\n];\n\n/** Extension \u2192 parser lookup */\nconst extensionMap = new Map<string, DataFormatParser>();\nfor (const parser of allParsers) {\n for (const ext of parser.extensions) {\n extensionMap.set(ext.toLowerCase(), parser);\n }\n}\n\n// \u2500\u2500 Public API \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Get the parser for a given file extension.\n * Returns null if no parser is registered or the optional dep is missing.\n */\nexport function getDataParser(filePath: string): DataFormatParser | null {\n const ext = filePath.slice(filePath.lastIndexOf('.')).toLowerCase();\n const parser = extensionMap.get(ext) ?? null;\n if (!parser) return null;\n if (!parser.isAvailable()) return null;\n return parser;\n}\n\n/**\n * Check if a file extension is supported for data parsing.\n */\nexport function isSupportedDataFormat(filePath: string): boolean {\n return getDataParser(filePath) !== null;\n}\n\n/**\n * Get all supported extensions (only those with available deps).\n */\nexport function getAvailableExtensions(): string[] {\n const available: string[] = [];\n for (const [ext, parser] of extensionMap) {\n if (parser.isAvailable()) available.push(ext);\n }\n return available;\n}\n\n/**\n * Get extensions that are registered but have missing optional deps.\n */\nexport function getUnavailableExtensions(): Array<{ ext: string; parser: string }> {\n const unavailable: Array<{ ext: string; parser: string }> = [];\n for (const [ext, parser] of extensionMap) {\n if (!parser.isAvailable()) {\n unavailable.push({ ext, parser: parser.name });\n }\n }\n return unavailable;\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA,iBAAqC;AACrC,mBAA4B;AAC5B,wBAAgC;AAChC,mBAA4B;AAC5B,qBAA8B;AAC9B,iBAA0B;AAI1B,MAAM,aAAiC;AAAA,EACrC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAGA,MAAM,eAAe,oBAAI,IAA8B;AACvD,WAAW,UAAU,YAAY;AAC/B,aAAW,OAAO,OAAO,YAAY;AACnC,iBAAa,IAAI,IAAI,YAAY,GAAG,MAAM;AAAA,EAC5C;AACF;AAQO,SAAS,cAAc,UAA2C;AACvE,QAAM,MAAM,SAAS,MAAM,SAAS,YAAY,GAAG,CAAC,EAAE,YAAY;AAClE,QAAM,SAAS,aAAa,IAAI,GAAG,KAAK;AACxC,MAAI,CAAC,OAAQ,QAAO;AACpB,MAAI,CAAC,OAAO,YAAY,EAAG,QAAO;AAClC,SAAO;AACT;AAKO,SAAS,sBAAsB,UAA2B;AAC/D,SAAO,cAAc,QAAQ,MAAM;AACrC;AAKO,SAAS,yBAAmC;AACjD,QAAM,YAAsB,CAAC;AAC7B,aAAW,CAAC,KAAK,MAAM,KAAK,cAAc;AACxC,QAAI,OAAO,YAAY,EAAG,WAAU,KAAK,GAAG;AAAA,EAC9C;AACA,SAAO;AACT;AAKO,SAAS,2BAAmE;AACjF,QAAM,cAAsD,CAAC;AAC7D,aAAW,CAAC,KAAK,MAAM,KAAK,cAAc;AACxC,QAAI,CAAC,OAAO,YAAY,GAAG;AACzB,kBAAY,KAAK,EAAE,KAAK,QAAQ,OAAO,KAAK,CAAC;AAAA,IAC/C;AAAA,EACF;AACA,SAAO;AACT;",
6
6
  "names": []
7
7
  }