brainbank 0.1.0-beta.1

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 (137) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +155 -0
  3. package/assets/architecture.png +0 -0
  4. package/bin/brainbank +18 -0
  5. package/bin/brainbank-mcp +19 -0
  6. package/dist/chunk-3YBCD6DI.js +117 -0
  7. package/dist/chunk-3YBCD6DI.js.map +1 -0
  8. package/dist/chunk-63GBCDS5.js +3249 -0
  9. package/dist/chunk-63GBCDS5.js.map +1 -0
  10. package/dist/chunk-DMFMTOHF.js +123 -0
  11. package/dist/chunk-DMFMTOHF.js.map +1 -0
  12. package/dist/chunk-FQYKWB2Q.js +136 -0
  13. package/dist/chunk-FQYKWB2Q.js.map +1 -0
  14. package/dist/chunk-IMJJ2VEM.js +74 -0
  15. package/dist/chunk-IMJJ2VEM.js.map +1 -0
  16. package/dist/chunk-M744PCJQ.js +43 -0
  17. package/dist/chunk-M744PCJQ.js.map +1 -0
  18. package/dist/chunk-O3J6ZIXK.js +82 -0
  19. package/dist/chunk-O3J6ZIXK.js.map +1 -0
  20. package/dist/chunk-OPH7GZ7U.js +124 -0
  21. package/dist/chunk-OPH7GZ7U.js.map +1 -0
  22. package/dist/chunk-PXEWQMN7.js +89 -0
  23. package/dist/chunk-PXEWQMN7.js.map +1 -0
  24. package/dist/chunk-RDQYDLYZ.js +69 -0
  25. package/dist/chunk-RDQYDLYZ.js.map +1 -0
  26. package/dist/chunk-VIIHPCC4.js +254 -0
  27. package/dist/chunk-VIIHPCC4.js.map +1 -0
  28. package/dist/chunk-WCQVDF3K.js +14 -0
  29. package/dist/chunk-WCQVDF3K.js.map +1 -0
  30. package/dist/cli.d.ts +1 -0
  31. package/dist/cli.js +3076 -0
  32. package/dist/cli.js.map +1 -0
  33. package/dist/haiku-expander-YRSIPGKP.js +8 -0
  34. package/dist/haiku-expander-YRSIPGKP.js.map +1 -0
  35. package/dist/haiku-pruner-SHAXUPY6.js +8 -0
  36. package/dist/haiku-pruner-SHAXUPY6.js.map +1 -0
  37. package/dist/http-server-QUXHLWUM.js +9 -0
  38. package/dist/http-server-QUXHLWUM.js.map +1 -0
  39. package/dist/index.d.ts +2161 -0
  40. package/dist/index.js +357 -0
  41. package/dist/index.js.map +1 -0
  42. package/dist/local-embedding-NZQTILGV.js +8 -0
  43. package/dist/local-embedding-NZQTILGV.js.map +1 -0
  44. package/dist/mcp.d.ts +2 -0
  45. package/dist/mcp.js +334 -0
  46. package/dist/mcp.js.map +1 -0
  47. package/dist/openai-embedding-ZP5TSUJG.js +8 -0
  48. package/dist/openai-embedding-ZP5TSUJG.js.map +1 -0
  49. package/dist/perplexity-context-embedding-GI5PHE6X.js +9 -0
  50. package/dist/perplexity-context-embedding-GI5PHE6X.js.map +1 -0
  51. package/dist/perplexity-embedding-KZRYGJRC.js +10 -0
  52. package/dist/perplexity-embedding-KZRYGJRC.js.map +1 -0
  53. package/dist/plugin-IKQ6IRSJ.js +32 -0
  54. package/dist/plugin-IKQ6IRSJ.js.map +1 -0
  55. package/dist/resolve-ASGLBNUC.js +10 -0
  56. package/dist/resolve-ASGLBNUC.js.map +1 -0
  57. package/dist/stats-tui-ZY2NQSEA.js +1904 -0
  58. package/dist/stats-tui-ZY2NQSEA.js.map +1 -0
  59. package/package.json +96 -0
  60. package/src/brainbank.ts +617 -0
  61. package/src/cli/commands/collection.ts +77 -0
  62. package/src/cli/commands/context.ts +179 -0
  63. package/src/cli/commands/daemon.ts +100 -0
  64. package/src/cli/commands/docs.ts +71 -0
  65. package/src/cli/commands/files.ts +69 -0
  66. package/src/cli/commands/help.ts +77 -0
  67. package/src/cli/commands/index.ts +482 -0
  68. package/src/cli/commands/kv.ts +140 -0
  69. package/src/cli/commands/mcp-export.ts +273 -0
  70. package/src/cli/commands/mcp.ts +6 -0
  71. package/src/cli/commands/reembed.ts +30 -0
  72. package/src/cli/commands/scan.ts +336 -0
  73. package/src/cli/commands/search.ts +203 -0
  74. package/src/cli/commands/stats.ts +68 -0
  75. package/src/cli/commands/status.ts +47 -0
  76. package/src/cli/commands/watch.ts +47 -0
  77. package/src/cli/factory/brain-context.ts +43 -0
  78. package/src/cli/factory/builtin-registration.ts +87 -0
  79. package/src/cli/factory/config-loader.ts +77 -0
  80. package/src/cli/factory/index.ts +69 -0
  81. package/src/cli/factory/plugin-loader.ts +325 -0
  82. package/src/cli/index.ts +71 -0
  83. package/src/cli/server-client.ts +178 -0
  84. package/src/cli/tui/index-tui.tsx +667 -0
  85. package/src/cli/tui/stats-data.ts +523 -0
  86. package/src/cli/tui/stats-search.ts +262 -0
  87. package/src/cli/tui/stats-tui.tsx +1465 -0
  88. package/src/cli/tui/tree-scanner.ts +650 -0
  89. package/src/cli/utils.ts +137 -0
  90. package/src/config.ts +49 -0
  91. package/src/constants.ts +21 -0
  92. package/src/db/adapter.ts +112 -0
  93. package/src/db/metadata.ts +130 -0
  94. package/src/db/migrations.ts +66 -0
  95. package/src/db/sqlite-adapter.ts +218 -0
  96. package/src/db/tracker.ts +91 -0
  97. package/src/engine/index-api.ts +81 -0
  98. package/src/engine/reembed.ts +206 -0
  99. package/src/engine/search-api.ts +218 -0
  100. package/src/index.ts +154 -0
  101. package/src/lib/fts.ts +57 -0
  102. package/src/lib/languages.ts +180 -0
  103. package/src/lib/logger.ts +126 -0
  104. package/src/lib/math.ts +87 -0
  105. package/src/lib/provider-key.ts +20 -0
  106. package/src/lib/prune.ts +71 -0
  107. package/src/lib/rrf.ts +133 -0
  108. package/src/lib/write-lock.ts +108 -0
  109. package/src/mcp/mcp-server.ts +195 -0
  110. package/src/mcp/workspace-factory.ts +68 -0
  111. package/src/mcp/workspace-pool.ts +224 -0
  112. package/src/plugin.ts +381 -0
  113. package/src/providers/embeddings/embedding-worker-thread.ts +95 -0
  114. package/src/providers/embeddings/embedding-worker.ts +141 -0
  115. package/src/providers/embeddings/local-embedding.ts +115 -0
  116. package/src/providers/embeddings/openai-embedding.ts +167 -0
  117. package/src/providers/embeddings/perplexity-context-embedding.ts +195 -0
  118. package/src/providers/embeddings/perplexity-embedding.ts +165 -0
  119. package/src/providers/embeddings/resolve.ts +34 -0
  120. package/src/providers/pruners/haiku-expander.ts +166 -0
  121. package/src/providers/pruners/haiku-pruner.ts +112 -0
  122. package/src/providers/vector/hnsw-index.ts +174 -0
  123. package/src/providers/vector/hnsw-loader.ts +129 -0
  124. package/src/search/bm25-boost.ts +69 -0
  125. package/src/search/context-builder.ts +251 -0
  126. package/src/search/keyword/composite-bm25-search.ts +47 -0
  127. package/src/search/types.ts +37 -0
  128. package/src/search/vector/composite-vector-search.ts +61 -0
  129. package/src/search/vector/mmr.ts +64 -0
  130. package/src/services/collection.ts +384 -0
  131. package/src/services/daemon.ts +87 -0
  132. package/src/services/http-server.ts +336 -0
  133. package/src/services/kv-service.ts +64 -0
  134. package/src/services/plugin-registry.ts +77 -0
  135. package/src/services/watch.ts +340 -0
  136. package/src/services/webhook-server.ts +100 -0
  137. package/src/types.ts +493 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/tui/stats-tui.tsx","../src/cli/tui/stats-data.ts","../src/cli/tui/stats-search.ts"],"sourcesContent":["/**\n * stats-tui.tsx — Interactive Ink TUI for `brainbank stats`.\n *\n * Split-panel layout with 5 views:\n * 1. Dashboard — overview, language bars, directory list\n * 2. File Explorer — drill into directory, file list + detail\n * 3. Chunk Viewer — browse chunks, preview content\n * 4. Call Graph — interactive call tree\n * 5. Semantic Search — full pipeline (vector → prune → expand)\n *\n * Reuses patterns & colors from index-tui.tsx.\n */\n\nimport React, { useState, useMemo, useEffect, useRef, useCallback } from 'react';\nimport { render, Box, Text, useApp, useInput, useStdout } from 'ink';\nimport {\n fetchOverview, fetchLanguageBreakdown, fetchDirectories,\n fetchFilesInDir, fetchFileDetail, fetchChunksForFile, fetchCallTree,\n searchSymbols,\n} from './stats-data.ts';\nimport type {\n StatsOverview, LanguageStat, DirectoryStat,\n FileStat, FileDetailInfo, ChunkInfo, CallTreeNode,\n} from './stats-data.ts';\nimport { BrainSearchSession } from './stats-search.ts';\nimport type { SearchPipelineResult, SourceOption } from './stats-search.ts';\nimport type { SearchResult } from '@/types.ts';\n\n\n// ── Colors (Aurora palette — same as index-tui) ───────\n\nconst C = {\n aurora: '#7AA2F7',\n success: '#9ECE6A',\n error: '#F7768E',\n warning: '#E0AF68',\n dim: '#565F89',\n text: '#C0CAF5',\n border: '#3B4261',\n cyan: '#7DCFFF',\n purple: '#BB9AF7',\n orange: '#FF9E64',\n dir: '#E0AF68',\n} as const;\n\n// Use 90% of terminal — cleared on launch for full-screen feel.\n\n// ── Language colors / badges ──────────────────────\n\nconst LANG_COLORS: Record<string, string> = {\n python: '#4B8BBE',\n typescript: '#519ABA',\n javascript: '#CBCB41',\n css: '#42A5F5',\n go: '#7FD5EA',\n rust: '#DEA584',\n ruby: '#CC3E44',\n java: '#CC3E44',\n c: '#599EFF',\n cpp: '#599EFF',\n};\n\nconst LANG_BADGES: Record<string, string> = {\n python: 'PY', typescript: 'TS', javascript: 'JS', css: 'CS',\n go: 'GO', rust: 'RS', ruby: 'RB', java: 'JV', c: 'C ', cpp: 'C+',\n};\n\nfunction langColor(lang: string): string { return LANG_COLORS[lang] ?? C.text; }\nfunction langBadge(lang: string): string { return LANG_BADGES[lang] ?? lang.slice(0, 2).toUpperCase(); }\n\n\n// ── Utilities ───────────────────────────────────────\n\nfunction centerScroll(cursor: number, total: number, viewH: number): number {\n if (total <= viewH) return 0;\n const half = Math.floor(viewH / 2);\n const offset = Math.max(0, cursor - half);\n return Math.min(offset, total - viewH);\n}\n\nfunction bar(percent: number, width: number): string {\n const filled = Math.round(percent / 100 * width);\n return '█'.repeat(filled) + '░'.repeat(Math.max(0, width - filled));\n}\n\nfunction truncate(str: string, max: number): string {\n return str.length > max ? str.slice(0, max - 1) + '…' : str;\n}\n\n// ── Syntax Highlighting ───────────────────────────\n\n/** A colored segment of a syntax-highlighted line. */\ninterface SyntaxSegment {\n text: string;\n color: string;\n}\n\n// Keyword sets for common languages\nconst KEYWORDS = new Set([\n // JS/TS\n 'async', 'await', 'break', 'case', 'catch', 'class', 'const', 'continue',\n 'default', 'delete', 'do', 'else', 'enum', 'export', 'extends', 'false',\n 'finally', 'for', 'from', 'function', 'if', 'implements', 'import', 'in',\n 'instanceof', 'interface', 'let', 'new', 'null', 'of', 'return', 'static',\n 'super', 'switch', 'this', 'throw', 'true', 'try', 'type', 'typeof',\n 'undefined', 'var', 'void', 'while', 'yield',\n // Python\n 'def', 'class', 'self', 'None', 'True', 'False', 'and', 'or', 'not',\n 'is', 'lambda', 'with', 'as', 'pass', 'raise', 'global', 'nonlocal',\n 'elif', 'except', 'assert',\n]);\n\nconst TYPE_WORDS = new Set([\n 'string', 'number', 'boolean', 'any', 'void', 'never', 'unknown',\n 'object', 'Promise', 'Array', 'Map', 'Set', 'Record', 'Partial',\n 'Readonly', 'Required', 'Pick', 'Omit', 'int', 'float', 'str',\n 'list', 'dict', 'tuple', 'bool', 'Optional',\n]);\n\n/** Tokenize a line of code into colored segments. Simple regex-based. */\nfunction highlightLine(line: string, maxW: number): SyntaxSegment[] {\n const trimmed = line.length > maxW ? line.slice(0, maxW - 1) + '…' : line;\n if (trimmed.length === 0) return [{ text: '', color: C.text }];\n\n const segments: SyntaxSegment[] = [];\n // Single-line comment check\n const commentIdx = findCommentStart(trimmed);\n const codePart = commentIdx >= 0 ? trimmed.slice(0, commentIdx) : trimmed;\n const commentPart = commentIdx >= 0 ? trimmed.slice(commentIdx) : '';\n\n // Tokenize code part\n if (codePart.length > 0) {\n // Match patterns: strings, numbers, keywords, decorators, rest\n const pattern = /(@\\w+)|(\"(?:[^\"\\\\]|\\\\.)*\"|'(?:[^'\\\\]|\\\\.)*'|`(?:[^`\\\\]|\\\\.)*`)|(\\b\\d+(?:\\.\\d+)?\\b)|(\\b[A-Za-z_]\\w*\\b)|([^A-Za-z_@'\"\\d`]+)/g;\n let m: RegExpExecArray | null;\n while ((m = pattern.exec(codePart)) !== null) {\n const [full, decorator, str, num, word, other] = m;\n if (decorator) {\n segments.push({ text: decorator, color: C.warning });\n } else if (str) {\n segments.push({ text: str, color: C.success });\n } else if (num) {\n segments.push({ text: num, color: C.orange });\n } else if (word) {\n if (KEYWORDS.has(word)) {\n segments.push({ text: word, color: C.purple });\n } else if (TYPE_WORDS.has(word)) {\n segments.push({ text: word, color: C.cyan });\n } else if (word[0] === word[0].toUpperCase() && word[0] !== word[0].toLowerCase()) {\n // PascalCase → likely a class/type\n segments.push({ text: word, color: C.cyan });\n } else {\n segments.push({ text: word, color: C.text });\n }\n } else if (other) {\n segments.push({ text: other, color: C.dim });\n } else {\n segments.push({ text: full, color: C.text });\n }\n }\n }\n\n // Comment part\n if (commentPart) {\n segments.push({ text: commentPart, color: C.dim });\n }\n\n return segments.length > 0 ? segments : [{ text: trimmed, color: C.text }];\n}\n\n/** Find the start of a single-line comment, avoiding matches inside strings. */\nfunction findCommentStart(line: string): number {\n let inString: string | null = null;\n for (let i = 0; i < line.length; i++) {\n const ch = line[i];\n if (inString) {\n if (ch === '\\\\') { i++; continue; }\n if (ch === inString) inString = null;\n } else {\n if (ch === '\"' || ch === \"'\" || ch === '`') { inString = ch; continue; }\n if (ch === '/' && line[i + 1] === '/') return i;\n if (ch === '#' && (i === 0 || /\\s/.test(line[i - 1]))) return i;\n }\n }\n return -1;\n}\n\n/** Render a syntax-highlighted code line as Ink <Text> elements. */\nfunction HighlightedLine({ segments }: { segments: SyntaxSegment[] }): React.ReactNode {\n return (\n <>\n {segments.map((seg, i) => (\n <Text key={i} color={seg.color}>{seg.text}</Text>\n ))}\n </>\n );\n}\n\ntype View = 'dashboard' | 'files' | 'chunks' | 'callgraph' | 'search';\n\n\n// ── Dashboard View ────────────────────────────────\n\nfunction DashboardView({ overview, languages, dirs, width, height, onDrillDir, onCallGraph, onSearch }: {\n overview: StatsOverview;\n languages: LanguageStat[];\n dirs: DirectoryStat[];\n width: number;\n height: number;\n onDrillDir: (dir: string) => void;\n onCallGraph: () => void;\n onSearch: () => void;\n}): React.ReactNode {\n const [cursor, setCursor] = useState(0);\n\n useInput((input, key) => {\n if (key.downArrow) setCursor(c => Math.min(c + 1, dirs.length - 1));\n if (key.upArrow) setCursor(c => Math.max(c - 1, 0));\n if (key.return && dirs[cursor]) onDrillDir(dirs[cursor].dir);\n if (input === 'g') onCallGraph();\n if (input === '/') onSearch();\n });\n\n const leftW = 30;\n const rightW = Math.max(40, width - leftW - 5);\n const barW = Math.max(10, rightW - 35);\n\n return (\n <Box flexDirection=\"row\" width={width} height={height - 4}>\n {/* Left: Overview */}\n <Box flexDirection=\"column\" width={leftW} paddingX={1}>\n <Box marginBottom={1}>\n <Text color={C.aurora} bold>Overview</Text>\n </Box>\n <Text color={C.text}> 📁 <Text bold>{overview.files}</Text> files</Text>\n <Text color={C.text}> 🧩 <Text bold>{overview.chunks}</Text> chunks</Text>\n <Text color={C.text}> 🔗 <Text bold>{overview.callEdges}</Text> call edges</Text>\n <Text color={C.text}> 📥 <Text bold>{overview.importEdges}</Text> imports</Text>\n <Text color={C.text}> 🏷 <Text bold>{overview.symbols}</Text> symbols</Text>\n <Text color={C.text}> 📊 <Text bold>{overview.dbSizeMB}</Text> MB db</Text>\n <Text color={C.text}> 🔍 <Text bold>{overview.hnswSize}</Text> vectors</Text>\n <Box marginTop={1}>\n <Text color={C.dim}>Embedding:</Text>\n </Box>\n <Text color={C.cyan}> {overview.embeddingModel}</Text>\n <Text color={C.dim}> Pruner: <Text color={C.text}>{overview.pruner}</Text></Text>\n <Text color={C.dim}> Expander: <Text color={C.text}>{overview.expander}</Text></Text>\n </Box>\n\n {/* Right: Languages + Directories */}\n <Box flexDirection=\"column\" width={rightW} paddingX={1}>\n <Box marginBottom={1}>\n <Text color={C.aurora} bold>Language Breakdown</Text>\n </Box>\n {languages.map(lang => (\n <Box key={lang.language} height={1}>\n <Text wrap=\"truncate\">\n <Text color={langColor(lang.language)} bold>{langBadge(lang.language)}</Text>\n <Text> </Text>\n <Text color={langColor(lang.language)}>{bar(lang.percent, barW)}</Text>\n <Text color={C.dim}> {String(lang.chunks).padStart(4)} </Text>\n <Text color={C.dim}>{lang.percent.toFixed(1).padStart(5)}%</Text>\n </Text>\n </Box>\n ))}\n\n <Box marginTop={1} marginBottom={1}>\n <Text color={C.aurora} bold>Directories</Text>\n <Text color={C.dim}> ─── files ── chunks</Text>\n </Box>\n {dirs.map((d, i) => {\n const isCursor = i === cursor;\n const ptr = isCursor ? '▸ ' : ' ';\n const dirBarW = Math.max(5, Math.min(15, Math.round(d.percent / 100 * 15)));\n return (\n <Box key={d.dir} height={1}>\n <Text wrap=\"truncate\">\n <Text color={isCursor ? C.aurora : C.dim}>{ptr}</Text>\n <Text color={isCursor ? C.aurora : C.dir} bold={isCursor}>\n {truncate(d.dir + '/', 20).padEnd(20)}\n </Text>\n <Text color={C.dim}>{String(d.files).padStart(5)} {String(d.chunks).padStart(5)} </Text>\n <Text color={isCursor ? C.aurora : C.success}>{bar(d.percent, dirBarW)}</Text>\n </Text>\n </Box>\n );\n })}\n </Box>\n </Box>\n );\n}\n\n\n// ── File Explorer View ────────────────────────────\n\nfunction FileExplorerView({ dbPath, dir, width, height, onDrillFile, onBack }: {\n dbPath: string;\n dir: string;\n width: number;\n height: number;\n onDrillFile: (filePath: string) => void;\n onBack: () => void;\n}): React.ReactNode {\n const files = useMemo(() => fetchFilesInDir(dbPath, dir), [dbPath, dir]);\n const [cursor, setCursor] = useState(0);\n const [sortMode, setSortMode] = useState<'chunks' | 'name' | 'symbols'>('chunks');\n\n // Filter mode\n const [filterText, setFilterText] = useState('');\n const isFilteringRef = useRef(false);\n const [isFiltering, setIsFiltering] = useState(false);\n\n const sorted = useMemo(() => {\n const s = [...files];\n if (sortMode === 'name') s.sort((a, b) => a.fileName.localeCompare(b.fileName));\n else if (sortMode === 'symbols') s.sort((a, b) => b.symbols - a.symbols);\n return s;\n }, [files, sortMode]);\n\n const filtered = useMemo(() => {\n if (!filterText) return sorted;\n const lower = filterText.toLowerCase();\n return sorted.filter(f => f.fileName.toLowerCase().includes(lower));\n }, [sorted, filterText]);\n\n const detail: FileDetailInfo | null = useMemo(() => {\n if (!filtered[cursor]) return null;\n return fetchFileDetail(dbPath, filtered[cursor].filePath);\n }, [dbPath, filtered, cursor]);\n\n const listH = Math.max(5, height - 6);\n const scrollOff = centerScroll(cursor, filtered.length, listH);\n\n useInput((input, key) => {\n const filtering = isFilteringRef.current;\n\n if (key.escape) {\n if (filtering || filterText) {\n isFilteringRef.current = false;\n setIsFiltering(false);\n setFilterText('');\n setCursor(0);\n return;\n }\n onBack();\n return;\n }\n\n // Filter mode typing\n if (filtering) {\n if (key.return) {\n isFilteringRef.current = false;\n setIsFiltering(false);\n return;\n }\n if (key.backspace || key.delete) {\n setFilterText(prev => prev.slice(0, -1));\n setCursor(0);\n return;\n }\n if (input && !key.upArrow && !key.downArrow) {\n setFilterText(prev => prev + input);\n setCursor(0);\n return;\n }\n }\n\n // '/' to start filtering\n if (input === '/' && !filtering) {\n isFilteringRef.current = true;\n setIsFiltering(true);\n setFilterText('');\n setCursor(0);\n return;\n }\n\n if (key.downArrow) setCursor(c => Math.min(c + 1, filtered.length - 1));\n if (key.upArrow) setCursor(c => Math.max(c - 1, 0));\n if (key.return && filtered[cursor]) onDrillFile(filtered[cursor].filePath);\n if (!filtering && input === 's') setSortMode(m => m === 'chunks' ? 'name' : m === 'name' ? 'symbols' : 'chunks');\n });\n\n const leftW = Math.min(40, Math.floor(width * 0.4));\n const rightW = width - leftW - 3;\n const visible = filtered.slice(scrollOff, scrollOff + listH);\n\n return (\n <Box flexDirection=\"row\" width={width} height={height - 4}>\n {/* Left: File list */}\n <Box flexDirection=\"column\" width={leftW} paddingX={1}>\n <Box marginBottom={1}>\n <Text color={C.aurora} bold>Files</Text>\n <Text color={C.dim}> ({filtered.length}{filterText ? `/${files.length}` : ''})</Text>\n <Text color={C.dim}> sort: </Text>\n <Text color={C.cyan}>{sortMode}</Text>\n </Box>\n {/* Filter bar */}\n {(isFiltering || filterText) && (\n <Box height={1} marginBottom={0}>\n <Text color={C.aurora} bold>/ </Text>\n <Text color={C.text}>{filterText}</Text>\n <Text color={C.aurora}>▎</Text>\n </Box>\n )}\n {visible.map((f, vi) => {\n const idx = scrollOff + vi;\n const isCursor = idx === cursor;\n const ptr = isCursor ? '▸ ' : ' ';\n return (\n <Box key={f.filePath} height={1}>\n <Text wrap=\"truncate\">\n <Text color={isCursor ? C.aurora : C.dim}>{ptr}</Text>\n <Text color={langColor(f.language)} bold>{langBadge(f.language)}</Text>\n <Text> </Text>\n <Text color={isCursor ? C.text : C.dim}>\n {truncate(f.fileName, leftW - 12)}\n </Text>\n <Text color={C.dim}> {String(f.chunks).padStart(3)}ch</Text>\n </Text>\n </Box>\n );\n })}\n </Box>\n\n {/* Right: File detail */}\n <Box flexDirection=\"column\" width={rightW} paddingX={1}>\n {detail && (\n <>\n <Box marginBottom={1}>\n <Text color={C.aurora} bold>File Detail</Text>\n </Box>\n <Text color={C.dim}>📄 <Text color={C.text}>{detail.filePath}</Text></Text>\n <Text color={C.dim}> Language: <Text color={langColor(detail.language)}>{detail.language}</Text></Text>\n <Text color={C.dim}> Chunks: <Text color={C.text}>{detail.chunks}</Text></Text>\n <Text color={C.dim}> Symbols: <Text color={C.text}>{detail.symbols.length}</Text></Text>\n <Text color={C.dim}> Imports: <Text color={C.success}>{detail.importsIn.length} in</Text>, <Text color={C.orange}>{detail.importsOut.length} out</Text></Text>\n <Text color={C.dim}> Call edges: <Text color={C.success}>{detail.callEdgesIn} in</Text>, <Text color={C.orange}>{detail.callEdgesOut} out</Text></Text>\n\n {detail.symbols.length > 0 && (\n <Box flexDirection=\"column\" marginTop={1}>\n <Text color={C.purple} bold>Symbols</Text>\n {detail.symbols.slice(0, Math.max(5, height - 15)).map((sym, i) => (\n <Box key={`${sym.name}-${i}`} height={1}>\n <Text wrap=\"truncate\">\n <Text color={C.dim}> {sym.kind === 'class' || sym.kind === 'Class' ? 'C' : 'ƒ'} </Text>\n <Text color={C.text}>{truncate(sym.name, rightW - 10)}</Text>\n <Text color={C.dim}> L{sym.line}</Text>\n </Text>\n </Box>\n ))}\n {detail.symbols.length > height - 15 && (\n <Text color={C.dim}> … {detail.symbols.length - (height - 15)} more</Text>\n )}\n </Box>\n )}\n\n {detail.importsIn.length > 0 && (\n <Box flexDirection=\"column\" marginTop={1}>\n <Text color={C.cyan} bold>Imported by</Text>\n {detail.importsIn.slice(0, 5).map((imp, i) => (\n <Text key={i} color={C.dim}> ← {truncate(imp, rightW - 6)}</Text>\n ))}\n </Box>\n )}\n </>\n )}\n </Box>\n </Box>\n );\n}\n\n\n// ── Chunk Viewer ──────────────────────────────────\n\nfunction ChunkViewerView({ dbPath, filePath, width, height, onBack }: {\n dbPath: string;\n filePath: string;\n width: number;\n height: number;\n onBack: () => void;\n}): React.ReactNode {\n const chunks = useMemo(() => fetchChunksForFile(dbPath, filePath), [dbPath, filePath]);\n const [cursor, setCursor] = useState(0);\n const [contentScroll, setContentScroll] = useState(0);\n const [focusPanel, setFocusPanel] = useState<'list' | 'content'>('list');\n\n const listH = Math.max(5, height - 6);\n const scrollOff = centerScroll(cursor, chunks.length, listH);\n\n const leftW = Math.min(26, Math.floor(width * 0.28));\n const rightW = width - leftW - 3;\n const activeChunk = chunks[cursor] ?? null;\n const visible = chunks.slice(scrollOff, scrollOff + listH);\n // Preview fills to footer: height - 4 (outer margin) - 2 (header) - 3 (calls+meta) = usable\n const previewH = Math.max(3, height - 9);\n const contentLines = useMemo(() => activeChunk?.content.split('\\n') ?? [], [activeChunk]);\n const maxContentScroll = Math.max(0, contentLines.length - previewH);\n\n // Reset content scroll when switching chunks\n useEffect(() => { setContentScroll(0); }, [cursor]);\n\n useInput((input, key) => {\n if (key.escape) {\n if (focusPanel === 'content') { setFocusPanel('list'); return; }\n onBack();\n }\n if (key.tab || (input === 'l' && focusPanel === 'list') || (input === 'h' && focusPanel === 'content')\n || (key.rightArrow && focusPanel === 'list') || (key.leftArrow && focusPanel === 'content')) {\n setFocusPanel(p => p === 'list' ? 'content' : 'list');\n return;\n }\n if (focusPanel === 'list') {\n if (key.downArrow) setCursor(c => Math.min(c + 1, chunks.length - 1));\n if (key.upArrow) setCursor(c => Math.max(c - 1, 0));\n if (input === '}') setCursor(c => Math.min(c + 10, chunks.length - 1));\n if (input === '{') setCursor(c => Math.max(c - 10, 0));\n if (key.return) setFocusPanel('content');\n } else {\n // Content panel scrolling\n if (key.downArrow) setContentScroll(s => Math.min(s + 1, maxContentScroll));\n if (key.upArrow) setContentScroll(s => Math.max(s - 1, 0));\n if (input === '}') setContentScroll(s => Math.min(s + 10, maxContentScroll));\n if (input === '{') setContentScroll(s => Math.max(s - 10, 0));\n if (input === 'd') setContentScroll(s => Math.min(s + 15, maxContentScroll));\n if (input === 'u') setContentScroll(s => Math.max(s - 15, 0));\n }\n });\n\n const visibleLines = contentLines.slice(contentScroll, contentScroll + previewH);\n const scrollPct = maxContentScroll > 0 ? Math.round(contentScroll / maxContentScroll * 100) : 100;\n\n return (\n <Box flexDirection=\"row\" width={width} height={height - 4}>\n {/* Left: Chunk list */}\n <Box flexDirection=\"column\" width={leftW} paddingX={1}>\n <Box marginBottom={1}>\n <Text color={focusPanel === 'list' ? C.aurora : C.dim} bold>Chunks</Text>\n <Text color={C.dim}> ({chunks.length})</Text>\n </Box>\n {visible.map((ch, vi) => {\n const idx = scrollOff + vi;\n const isCursor = idx === cursor;\n const ptr = isCursor ? '▸ ' : ' ';\n const hasSym = ch.name !== null && ch.name !== '';\n const active = focusPanel === 'list' && isCursor;\n return (\n <Box key={ch.id} height={1}>\n <Text wrap=\"truncate\">\n <Text color={active ? C.aurora : isCursor ? C.cyan : C.dim}>{ptr}</Text>\n <Text color={active ? C.text : isCursor ? C.cyan : C.dim}>\n #{String(idx + 1).padStart(2)} L{ch.startLine}-{ch.endLine}\n </Text>\n {hasSym && <Text color={C.warning}> ★</Text>}\n </Text>\n </Box>\n );\n })}\n <Box marginTop={1}>\n <Text color={C.dim}>★ = named symbol</Text>\n </Box>\n </Box>\n\n {/* Right: Chunk preview (scrollable with syntax highlighting) */}\n <Box flexDirection=\"column\" width={rightW} paddingX={1}>\n {activeChunk && (\n <>\n <Box marginBottom={0} justifyContent=\"space-between\">\n <Text>\n <Text color={focusPanel === 'content' ? C.aurora : C.dim} bold>Preview</Text>\n <Text color={C.dim}> #{cursor + 1} L{activeChunk.startLine}-{activeChunk.endLine}</Text>\n {activeChunk.name ? <Text color={C.purple}> {activeChunk.name}</Text> : null}\n </Text>\n <Text>\n {focusPanel === 'list' && <Text color={C.dim} italic>Enter to scroll </Text>}\n {contentLines.length > previewH && (\n <Text color={focusPanel === 'content' ? C.cyan : C.dim}>{scrollPct}%</Text>\n )}\n </Text>\n </Box>\n <Box flexDirection=\"column\">\n {visibleLines.map((line, i) => {\n const segs = highlightLine(line, rightW - 6);\n return (\n <Box key={contentScroll + i} height={1}>\n <Text wrap=\"truncate\">\n <Text color={C.dim}>{String(activeChunk.startLine + contentScroll + i).padStart(4)}│</Text>\n <HighlightedLine segments={segs} />\n </Text>\n </Box>\n );\n })}\n </Box>\n\n <Box marginTop={1} flexDirection=\"column\">\n {activeChunk.callsOut.length > 0 && (\n <Text color={C.dim}>→ <Text color={C.orange}>{activeChunk.callsOut.slice(0, 8).join(', ')}</Text></Text>\n )}\n {activeChunk.calledBy.length > 0 && (\n <Text color={C.dim}>← <Text color={C.success}>{activeChunk.calledBy.slice(0, 8).join(', ')}</Text></Text>\n )}\n </Box>\n </>\n )}\n </Box>\n </Box>\n );\n}\n\n\n// ── Semantic Search View ──────────────────────────\n\ntype SearchState = 'idle' | 'initializing' | 'searching' | 'done' | 'error';\ntype SearchFocus = 'input' | 'sources' | 'raw' | 'final' | 'preview' | 'fullpreview';\n\n/** Extract display info from a SearchResult. */\nfunction resultLabel(r: SearchResult): { name: string; path: string; score: number; line: number } {\n const meta = r.metadata as Record<string, unknown> | undefined;\n return {\n name: (meta?.name as string) ?? r.type,\n path: r.filePath ?? 'unknown',\n score: r.score,\n line: (meta?.startLine as number) ?? 0,\n };\n}\n\nfunction SemanticSearchView({ repoPath, width, height, onBack, session }: {\n repoPath: string;\n width: number;\n height: number;\n onBack: () => void;\n session: BrainSearchSession;\n}): React.ReactNode {\n // Session — owned by StatsApp, shared across view transitions\n const sessionRef = useRef<BrainSearchSession>(session);\n\n // State\n const [query, setQuery] = useState('');\n const [state, setState] = useState<SearchState>(() =>\n session.initialized ? 'idle' : 'initializing',\n );\n const [stateMsg, setStateMsg] = useState(() =>\n session.initialized ? '' : 'Loading search index...',\n );\n const [focus, setFocus] = useState<SearchFocus>('input');\n const [pipeline, setPipeline] = useState<SearchPipelineResult | null>(null);\n const [sourceOpts, setSourceOpts] = useState<SourceOption[]>(() =>\n session.initialized ? [...session.sources] : [],\n );\n const [rawCursor, setRawCursor] = useState(0);\n const [finalCursor, setFinalCursor] = useState(0);\n const [previewScroll, setPreviewScroll] = useState(0);\n const [errorMsg, setErrorMsg] = useState('');\n const [sourceCursor, setSourceCursor] = useState(0);\n const [usePruner, setUsePruner] = useState(true);\n const [useExpander, setUseExpander] = useState(true);\n\n // Init session on mount — skip if already initialized (re-entry)\n useEffect(() => {\n sessionRef.current = session;\n\n if (session.initialized) {\n setSourceOpts([...session.sources]);\n setState('idle');\n setStateMsg('');\n return;\n }\n\n setState('initializing');\n setStateMsg('Loading search index...');\n\n // Defer to next tick so React paints the loading modal before heavy sync work\n const timer = setTimeout(() => {\n session.init()\n .then(() => {\n setSourceOpts([...session.sources]);\n setState('idle');\n setStateMsg('');\n })\n .catch((err: unknown) => {\n setState('error');\n setErrorMsg(err instanceof Error ? err.message : String(err));\n });\n }, 50);\n\n return () => { clearTimeout(timer); };\n }, [session]);\n\n // Column sizing — preview gets most space for code readability\n const rawW = Math.max(20, Math.floor(width * 0.22));\n const prunedW = Math.max(20, Math.floor(width * 0.22));\n const previewW = width - rawW - prunedW - 4;\n const listH = Math.max(3, height - 12);\n const previewH = Math.max(3, height - 12);\n\n // Active result for preview — each column independently controls what's shown\n const activeResult = useMemo(() => {\n if (!pipeline) return null;\n if (focus === 'final') {\n const combined = [...pipeline.pruned, ...pipeline.expanded];\n return combined[finalCursor] ?? null;\n }\n // raw, input, sources, preview all show the raw cursor's item\n return pipeline.raw[rawCursor] ?? null;\n }, [focus, rawCursor, finalCursor, pipeline]);\n\n const previewLines = useMemo(() => activeResult?.content.split('\\n') ?? [], [activeResult]);\n const maxPreviewScroll = Math.max(0, previewLines.length - previewH);\n\n // Reset preview scroll when result changes\n useEffect(() => { setPreviewScroll(0); }, [activeResult]);\n\n // Toggle source\n const toggleSource = useCallback((key: string) => {\n setSourceOpts(prev => {\n const next = prev.map(s => ({ ...s }));\n const target = next.find(s => s.key === key);\n if (target) target.enabled = !target.enabled;\n return next;\n });\n }, []);\n\n // Run search\n const doSearch = useCallback(async () => {\n const session = sessionRef.current;\n if (!session?.initialized || !query.trim()) return;\n setState('searching');\n setStateMsg('Searching...');\n setRawCursor(0);\n setFinalCursor(0);\n try {\n const activeKeys = new Set(\n sourceOpts.filter(s => s.enabled).map(s => s.key),\n );\n const allEnabled = sourceOpts.every(s => s.enabled);\n const result = await session.search(query, allEnabled ? undefined : activeKeys, usePruner, useExpander);\n setPipeline(result);\n setState('done');\n setStateMsg('');\n setFocus('raw');\n } catch (err: unknown) {\n setState('error');\n setErrorMsg(err instanceof Error ? err.message : String(err));\n }\n }, [query, sourceOpts, usePruner, useExpander]);\n\n // Input handling\n useInput((input, key) => {\n // Esc — back out\n if (key.escape) {\n if (focus === 'fullpreview') { setFocus('final'); return; }\n if (focus !== 'input' && pipeline) { setFocus('input'); return; }\n onBack();\n return;\n }\n\n // Source toggles removed from input mode — now handled in 'sources' focus\n\n // Input mode — typing query\n if (focus === 'input') {\n if (key.return && query.trim()) {\n doSearch();\n return;\n }\n if (key.backspace || key.delete) {\n setQuery(q => q.slice(0, -1));\n return;\n }\n if (key.tab) {\n setFocus('sources');\n return;\n }\n if (input && input.length === 1 && !key.ctrl && !key.meta) {\n setQuery(q => q + input);\n }\n return;\n }\n\n // Sources mode — ←→ to move cursor, space to toggle\n // Combined list: [sources...] | [Pruner] [Expander]\n if (focus === 'sources') {\n const totalOpts = sourceOpts.length + 2; // +2 for pruner, expander\n if (key.rightArrow) setSourceCursor(c => Math.min(c + 1, totalOpts - 1));\n if (key.leftArrow) setSourceCursor(c => Math.max(c - 1, 0));\n if (input === ' ') {\n if (sourceCursor < sourceOpts.length) {\n toggleSource(sourceOpts[sourceCursor].key);\n } else if (sourceCursor === sourceOpts.length) {\n setUsePruner(p => !p);\n } else {\n setUseExpander(e => !e);\n }\n return;\n }\n // ↑↓ adjust K for the focused source\n if (key.upArrow && sourceCursor < sourceOpts.length) {\n setSourceOpts(prev => {\n const next = prev.map(s => ({ ...s }));\n const target = next[sourceCursor];\n if (target) target.k = Math.min(target.k + 5, 50);\n return next;\n });\n return;\n }\n if (key.downArrow && sourceCursor < sourceOpts.length) {\n setSourceOpts(prev => {\n const next = prev.map(s => ({ ...s }));\n const target = next[sourceCursor];\n if (target) target.k = Math.max(target.k - 5, 5);\n return next;\n });\n return;\n }\n if (key.tab) {\n setFocus(pipeline ? 'raw' : 'input');\n return;\n }\n if (key.return && query.trim()) {\n doSearch();\n return;\n }\n return;\n }\n\n // 'P' — toggle full context preview (what the agent sees)\n if (input === 'p' && focus !== 'input') {\n if (focus === 'fullpreview') { setFocus('final'); }\n else { setFocus('fullpreview'); setPreviewScroll(0); }\n return;\n }\n\n // Tab — cycle focus\n if (key.tab) {\n const order: SearchFocus[] = ['raw', 'final', 'preview', 'input'];\n const idx = order.indexOf(focus);\n setFocus(order[(idx + 1) % order.length]);\n return;\n }\n\n // Column navigation\n if (focus === 'raw') {\n if (key.downArrow) setRawCursor(c => Math.min(c + 1, (pipeline?.raw.length ?? 1) - 1));\n if (key.upArrow) setRawCursor(c => Math.max(c - 1, 0));\n if (input === '}') setRawCursor(c => Math.min(c + 10, (pipeline?.raw.length ?? 1) - 1));\n if (input === '{') setRawCursor(c => Math.max(c - 10, 0));\n if (input === 'h' || key.leftArrow) setFocus('sources');\n if (input === 'l' || key.rightArrow) setFocus('final');\n if (key.return) { setFocus('preview'); setPreviewScroll(0); }\n return;\n }\n\n if (focus === 'final') {\n const combined = pipeline ? [...pipeline.pruned, ...pipeline.expanded] : [];\n if (key.downArrow) setFinalCursor(c => Math.min(c + 1, combined.length - 1));\n if (key.upArrow) setFinalCursor(c => Math.max(c - 1, 0));\n if (input === '}') setFinalCursor(c => Math.min(c + 10, combined.length - 1));\n if (input === '{') setFinalCursor(c => Math.max(c - 10, 0));\n if (input === 'h' || key.leftArrow) setFocus('raw');\n if (input === 'l' || key.rightArrow) setFocus('preview');\n if (key.return) { setFocus('preview'); setPreviewScroll(0); }\n return;\n }\n\n if (focus === 'preview') {\n if (key.downArrow) setPreviewScroll(s => Math.min(s + 1, maxPreviewScroll));\n if (key.upArrow) setPreviewScroll(s => Math.max(s - 1, 0));\n if (input === '}') setPreviewScroll(s => Math.min(s + 10, maxPreviewScroll));\n if (input === '{') setPreviewScroll(s => Math.max(s - 10, 0));\n if (input === 'd') setPreviewScroll(s => Math.min(s + 15, maxPreviewScroll));\n if (input === 'u') setPreviewScroll(s => Math.max(s - 15, 0));\n if (input === 'h' || key.leftArrow) setFocus('final');\n return;\n }\n\n if (focus === 'fullpreview') {\n if (key.downArrow) setPreviewScroll(s => Math.min(s + 1, maxPreviewScroll));\n if (key.upArrow) setPreviewScroll(s => Math.max(s - 1, 0));\n if (input === '}') setPreviewScroll(s => Math.min(s + 10, maxPreviewScroll));\n if (input === '{') setPreviewScroll(s => Math.max(s - 10, 0));\n if (input === 'd') setPreviewScroll(s => Math.min(s + 15, maxPreviewScroll));\n if (input === 'u') setPreviewScroll(s => Math.max(s - 15, 0));\n return;\n }\n });\n\n // Combined pruned+expanded list\n const combinedResults = useMemo(() => {\n if (!pipeline) return [];\n return [\n ...pipeline.pruned.map(r => ({ r, type: 'kept' as const })),\n ...pipeline.expanded.map(r => ({ r, type: 'expanded' as const })),\n ];\n }, [pipeline]);\n\n // Set of dropped filePaths for dimming in raw column\n const droppedPaths = useMemo(() => {\n if (!pipeline) return new Set<string>();\n return new Set(pipeline.dropped.map(r => r.filePath ?? ''));\n }, [pipeline]);\n\n const rawScrollOff = centerScroll(rawCursor, pipeline?.raw.length ?? 0, listH);\n const finalScrollOff = centerScroll(finalCursor, combinedResults.length, listH);\n\n // Full context preview: all final results concatenated\n const fullContextLines = useMemo(() => {\n if (!pipeline) return [];\n const final = [...pipeline.pruned, ...pipeline.expanded];\n const lines: string[] = [];\n for (const r of final) {\n const info = resultLabel(r);\n lines.push(`━━━ ${info.path} L${info.line} ━━━`);\n lines.push(...r.content.split('\\n'));\n lines.push('');\n }\n return lines;\n }, [pipeline]);\n\n const currentPreviewLines = focus === 'fullpreview' ? fullContextLines : previewLines;\n const currentMaxScroll = Math.max(0, currentPreviewLines.length - previewH);\n const visiblePreview = currentPreviewLines.slice(previewScroll, previewScroll + previewH);\n const scrollPct = currentMaxScroll > 0 ? Math.round(previewScroll / currentMaxScroll * 100) : 100;\n // Clamp preview scroll to current max\n useEffect(() => {\n setPreviewScroll(s => Math.min(s, currentMaxScroll));\n }, [currentMaxScroll]);\n\n // Animated spinner during init\n const spinnerFrames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];\n const [spinIdx, setSpinIdx] = useState(0);\n useEffect(() => {\n if (state !== 'initializing') return;\n const timer = setInterval(() => setSpinIdx(i => (i + 1) % spinnerFrames.length), 80);\n return () => clearInterval(timer);\n }, [state]);\n\n // Show loading modal if still initializing\n if (state === 'initializing') {\n return (\n <Box flexDirection=\"column\" width={width} height={height - 4}\n justifyContent=\"center\" alignItems=\"center\">\n <Box flexDirection=\"column\" alignItems=\"center\" borderStyle=\"round\"\n borderColor={C.border} paddingX={6} paddingY={2}>\n <Text color={C.aurora} bold>\n {spinnerFrames[spinIdx]} Loading Search Engine\n </Text>\n <Text color={C.dim}> </Text>\n <Text color={C.dim}>Initializing HNSW indices and plugins...</Text>\n <Text color={C.dim}>This only happens once per session</Text>\n </Box>\n <Box marginTop={1}>\n <Text color={C.dim}>Esc to go back</Text>\n </Box>\n </Box>\n );\n }\n\n return (\n <Box flexDirection=\"column\" width={width} height={height - 4}>\n {/* Search bar */}\n <Box paddingX={1} flexDirection=\"column\" marginBottom={1}>\n <Box>\n <Text color={C.aurora} bold>🔍 </Text>\n <Text color={focus === 'input' ? C.text : C.dim}>\n {query}<Text color={focus === 'input' ? C.aurora : C.dim}>▎</Text>\n </Text>\n <Text color={C.dim}>\n {' '}{state === 'initializing' ? '⟳ ' + stateMsg\n : state === 'searching' ? '⟳ Searching...'\n : state === 'error' ? '✗ ' + errorMsg\n : state === 'done' ? `${pipeline?.raw.length ?? 0} results`\n : 'Enter to search'}\n </Text>\n </Box>\n {/* Source filter tabs + pipeline toggles */}\n <Box marginTop={1}>\n <Text color={focus === 'sources' ? C.aurora : C.dim}>Sources: </Text>\n {sourceOpts.map((s, i) => {\n const isFocused = focus === 'sources' && i === sourceCursor;\n return (\n <Text key={s.key}>\n <Text color={isFocused ? C.text : (s.enabled ? C.aurora : C.dim)}\n bold={isFocused}\n underline={isFocused}>\n [{s.enabled ? '■' : '□'}] {s.label}\n </Text>\n <Text color={isFocused ? C.cyan : C.dim}>:{s.k}</Text>\n <Text color={C.dim}> </Text>\n </Text>\n );\n })}\n <Text color={C.dim}>│ </Text>\n {/* Pruner toggle */}\n <Text color={focus === 'sources' && sourceCursor === sourceOpts.length\n ? C.text\n : (usePruner ? C.purple : C.dim)}\n bold={focus === 'sources' && sourceCursor === sourceOpts.length}\n underline={focus === 'sources' && sourceCursor === sourceOpts.length}>\n [{usePruner ? '■' : '□'}] Pruner\n </Text>\n <Text color={C.dim}> </Text>\n {/* Expander toggle */}\n <Text color={focus === 'sources' && sourceCursor === sourceOpts.length + 1\n ? C.text\n : (useExpander ? C.purple : C.dim)}\n bold={focus === 'sources' && sourceCursor === sourceOpts.length + 1}\n underline={focus === 'sources' && sourceCursor === sourceOpts.length + 1}>\n [{useExpander ? '■' : '□'}] Expander\n </Text>\n <Text color={C.dim}> (←→ move, Space toggle, ↑↓ adjust K)</Text>\n </Box>\n </Box>\n\n {/* Full context preview mode */}\n {focus === 'fullpreview' ? (\n <Box flexDirection=\"column\" width={width} height={listH + 2} marginTop={1} paddingX={1}>\n <Box marginBottom={0} justifyContent=\"space-between\">\n <Text color={C.aurora} bold>Full Context Preview</Text>\n <Text>\n <Text color={C.dim} italic>What the agent sees </Text>\n <Text color={C.cyan}>{scrollPct}%</Text>\n <Text color={C.dim}> P to close</Text>\n </Text>\n </Box>\n <Box flexDirection=\"column\">\n {visiblePreview.map((line, i) => {\n const isHeader = line.startsWith('━━━');\n if (isHeader) {\n return (\n <Box key={previewScroll + i} height={1}>\n <Text color={C.purple} bold wrap=\"truncate\">{truncate(line, width - 4)}</Text>\n </Box>\n );\n }\n const segs = highlightLine(line, width - 8);\n return (\n <Box key={previewScroll + i} height={1}>\n <Text wrap=\"truncate\">\n <Text color={C.dim}>{String(previewScroll + i + 1).padStart(4)}│</Text>\n <HighlightedLine segments={segs} />\n </Text>\n </Box>\n );\n })}\n </Box>\n </Box>\n ) : (\n /* Two result columns + wide preview */\n <Box flexDirection=\"row\" width={width} height={listH} marginTop={1}>\n {/* Column 1: Raw results */}\n <Box flexDirection=\"column\" width={rawW} paddingX={1}>\n <Box marginBottom={0}>\n <Text color={focus === 'raw' ? C.aurora : C.dim} bold>\n Raw ({pipeline?.raw.length ?? 0})\n </Text>\n </Box>\n {pipeline && pipeline.raw.slice(rawScrollOff, rawScrollOff + listH - 1).map((r, vi) => {\n const idx = rawScrollOff + vi;\n const isCursor = focus === 'raw' && idx === rawCursor;\n const info = resultLabel(r);\n const isDimmed = droppedPaths.has(r.filePath ?? '');\n const ptr = isCursor ? '▸' : ' ';\n const scorePct = Math.round(info.score * 100);\n return (\n <Box key={idx} height={1}>\n <Text wrap=\"truncate\">\n <Text color={isCursor ? C.aurora : C.dim}>{ptr} </Text>\n <Text color={isDimmed ? C.error : (isCursor ? C.text : C.dim)}\n strikethrough={isDimmed}>\n {truncate(info.name, rawW - 10)}\n </Text>\n <Text color={isDimmed ? C.error : C.dim}> {scorePct}%</Text>\n </Text>\n </Box>\n );\n })}\n </Box>\n\n {/* Column 2: Final = pruned survivors + expanded discoveries */}\n <Box flexDirection=\"column\" width={prunedW} paddingX={1}>\n <Box marginBottom={0}>\n <Text color={focus === 'final' ? C.aurora : C.dim} bold>\n Final ({combinedResults.length})\n </Text>\n {(pipeline?.expanded.length ?? 0) > 0 && (\n <Text color={C.success}> +{pipeline?.expanded.length}◆</Text>\n )}\n {pipeline && pipeline.dropped.length > 0 && (\n <Text color={C.error}> -{pipeline.dropped.length}</Text>\n )}\n </Box>\n {combinedResults.slice(finalScrollOff, finalScrollOff + listH - 1).map((item, vi) => {\n const idx = finalScrollOff + vi;\n const isCursor = focus === 'final' && idx === finalCursor;\n const info = resultLabel(item.r);\n const isExpanded = item.type === 'expanded';\n const ptr = isCursor ? '▸' : (isExpanded ? '◆' : ' ');\n // Show rerank position# + shortened file path (visually distinct from raw column)\n const shortFile = info.path.split('/').pop() ?? info.path;\n return (\n <Box key={idx} height={1}>\n <Text wrap=\"truncate\">\n <Text color={isCursor ? C.aurora : (isExpanded ? C.success : C.dim)}>\n {ptr}\n </Text>\n <Text color={C.dim}>{String(idx + 1).padStart(2)} </Text>\n <Text color={isCursor ? C.text : (isExpanded ? C.success : C.dim)}>\n {truncate(shortFile, prunedW - 8)}\n </Text>\n </Text>\n </Box>\n );\n })}\n </Box>\n\n {/* Column 3: Preview */}\n <Box flexDirection=\"column\" width={previewW} paddingX={1}>\n <Box marginBottom={0} justifyContent=\"space-between\">\n <Text color={focus === 'preview' ? C.aurora : C.dim} bold>Preview</Text>\n <Text>\n {focus !== 'preview' && <Text color={C.dim} italic>Enter/→ to scroll </Text>}\n {currentPreviewLines.length > previewH && (\n <Text color={focus === 'preview' ? C.cyan : C.dim}>{scrollPct}%</Text>\n )}\n </Text>\n </Box>\n {activeResult && (\n <Box flexDirection=\"column\">\n <Text color={C.dim} wrap=\"truncate\">\n {truncate(resultLabel(activeResult).path, previewW - 4)} L{resultLabel(activeResult).line}\n </Text>\n {visiblePreview.map((line, i) => {\n const segs = highlightLine(line, previewW - 5);\n return (\n <Box key={previewScroll + i} height={1}>\n <Text wrap=\"truncate\">\n <Text color={C.dim}>{String(previewScroll + i + 1).padStart(3)}│</Text>\n <HighlightedLine segments={segs} />\n </Text>\n </Box>\n );\n })}\n </Box>\n )}\n </Box>\n </Box>\n )}\n\n {/* Timings bar */}\n {pipeline && (\n <Box paddingX={1} marginTop={0}>\n <Text color={C.dim}>\n ⏱ search: {pipeline.timings.search}ms\n {pipeline.prunerName && (\n <Text>{' '}prune: {pipeline.timings.prune}ms ({pipeline.prunerName}, -{pipeline.dropped.length})</Text>\n )}\n {pipeline.expanderName && pipeline.expanded.length > 0 && (\n <Text>{' '}expand: {pipeline.timings.expand}ms ({pipeline.expanderName}, +{pipeline.expanded.length})</Text>\n )}\n {' '}total: {pipeline.timings.total}ms\n </Text>\n </Box>\n )}\n </Box>\n );\n}\n\n\n// ── Call Graph View ───────────────────────────────\n\nfunction CallGraphView({ dbPath, width, height, onBack }: {\n dbPath: string;\n width: number;\n height: number;\n onBack: () => void;\n}): React.ReactNode {\n // Start with a top-level symbol search\n const [searchQuery, setSearchQuery] = useState('');\n const [rootNodes, setRootNodes] = useState<CallTreeNode[]>([]);\n const [cursor, setCursor] = useState(0);\n\n // Flatten tree for display\n const flatNodes = useMemo(() => {\n interface FlatNode { node: CallTreeNode; depth: number }\n const flat: FlatNode[] = [];\n function walk(nodes: CallTreeNode[], d: number): void {\n for (const n of nodes) {\n flat.push({ node: n, depth: d });\n walk(n.children, d + 1);\n }\n }\n walk(rootNodes, 0);\n return flat;\n }, [rootNodes]);\n\n useInput((input, key) => {\n if (key.escape) {\n if (rootNodes.length > 0) { setRootNodes([]); setSearchQuery(''); }\n else onBack();\n }\n if (key.downArrow) setCursor(c => Math.min(c + 1, flatNodes.length - 1));\n if (key.upArrow) setCursor(c => Math.max(c - 1, 0));\n if (key.return && flatNodes[cursor]) {\n // Drill into this node\n const tree = fetchCallTree(dbPath, flatNodes[cursor].node.chunkId, 3);\n if (tree.children.length > 0) {\n setRootNodes([tree]);\n setCursor(0);\n }\n }\n if (key.backspace || key.delete) {\n setSearchQuery(q => q.slice(0, -1));\n }\n if (input && input.length === 1 && !key.ctrl && !key.meta) {\n setSearchQuery(q => q + input);\n }\n });\n\n // Search for matching chunks when query changes\n useEffect(() => {\n if (searchQuery.length < 2) { setRootNodes([]); return; }\n try {\n const rows = searchSymbols(dbPath, searchQuery, 10);\n const trees = rows.map(r => fetchCallTree(dbPath, r.id, 2));\n setRootNodes(trees);\n setCursor(0);\n } catch { /* ignore */ }\n }, [searchQuery, dbPath]);\n\n const listH = Math.max(5, height - 8);\n const scrollOff = centerScroll(cursor, flatNodes.length, listH);\n const visible = flatNodes.slice(scrollOff, scrollOff + listH);\n\n return (\n <Box flexDirection=\"column\" width={width} height={height - 4} paddingX={1}>\n <Box marginBottom={1}>\n <Text color={C.aurora} bold>Call Graph</Text>\n </Box>\n <Box marginBottom={1}>\n <Text color={C.dim}>🔍 Search: </Text>\n <Text color={C.text}>{searchQuery || '(type to search symbols…)'}</Text>\n </Box>\n\n {flatNodes.length === 0 && searchQuery.length >= 2 && (\n <Text color={C.dim}>No matching symbols found.</Text>\n )}\n\n {visible.map((item, vi) => {\n const idx = scrollOff + vi;\n const isCursor = idx === cursor;\n const indent = ' '.repeat(item.depth);\n const prefix = item.depth > 0 ? '├── ' : '';\n return (\n <Box key={`${item.node.chunkId}-${vi}`} height={1}>\n <Text wrap=\"truncate\">\n <Text color={isCursor ? C.aurora : C.dim}>{isCursor ? '▸ ' : ' '}</Text>\n <Text color={C.dim}>{indent}{prefix}</Text>\n <Text color={isCursor ? C.aurora : C.purple} bold={isCursor}>{item.node.symbol}</Text>\n <Text color={C.dim}> </Text>\n <Text color={C.dim}>{truncate(item.node.filePath, width - indent.length * 2 - item.node.symbol.length - 12)}</Text>\n {item.node.children.length > 0 && (\n <Text color={C.dim}> ({item.node.children.length})</Text>\n )}\n </Text>\n </Box>\n );\n })}\n </Box>\n );\n}\n\n\n// ── Header / Footer ───────────────────────────────\n\nfunction Header({ repoPath, dbSizeMB, view, breadcrumb, width }: {\n repoPath: string; dbSizeMB: number; view: View; breadcrumb: string[];\n width: number;\n}): React.ReactNode {\n const crumb = breadcrumb.length > 0 ? ' ▸ ' + breadcrumb.join(' ▸ ') : '';\n const right = `${repoPath} ${dbSizeMB}MB`;\n return (\n <Box width={width} height={2} paddingX={1} flexDirection=\"column\">\n <Box justifyContent=\"space-between\">\n <Text>\n <Text color={C.aurora} bold>⚡ BrainBank Explorer</Text>\n <Text color={C.dim}>{crumb}</Text>\n </Text>\n <Text color={C.dim}>{truncate(right, Math.max(10, width - 40))}</Text>\n </Box>\n <Text color={C.border}>{'─'.repeat(width - 2)}</Text>\n </Box>\n );\n}\n\nfunction Footer({ view, width }: { view: View; width: number }): React.ReactNode {\n const hints: Record<View, string> = {\n dashboard: '↑↓ navigate Enter drill in / search g call graph q quit',\n files: '↑↓ navigate Enter view chunks s sort / filter Esc back q quit',\n chunks: 'Tab focus ↑↓ scroll {/} jump 10 u/d page Enter preview Esc back',\n callgraph: 'type to search ↑↓ navigate Enter expand Esc back q quit',\n search: 'type query → Enter ←→ panels {/} jump 10 P full context Tab sources Space toggle Esc back',\n };\n\n return (\n <Box width={width} height={2} paddingX={1} flexDirection=\"column\">\n <Text color={C.border}>{'─'.repeat(width - 2)}</Text>\n <Text color={C.dim}>\n {hints[view].split(/(\\S+:)/).map((part, i) =>\n part.endsWith(':') ? (\n <Text key={i} color={C.aurora}>{part} </Text>\n ) : (\n <Text key={i}>{part}</Text>\n )\n )}\n </Text>\n </Box>\n );\n}\n\n\n// ── App Root ──────────────────────────────────────\n\nfunction StatsApp({ dbPath, repoPath, configPath }: {\n dbPath: string;\n repoPath: string;\n configPath: string;\n}): React.ReactNode {\n const { exit } = useApp();\n const { stdout } = useStdout();\n const [rawW, setRawW] = useState(stdout?.columns || 100);\n const [rawH, setRawH] = useState(stdout?.rows || 30);\n const [view, setView] = useState<View>('dashboard');\n const [breadcrumb, setBreadcrumb] = useState<string[]>([]);\n const [currentDir, setCurrentDir] = useState('');\n const [currentFile, setCurrentFile] = useState('');\n\n // Persistent search session — survives view transitions\n const searchSessionRef = useRef<BrainSearchSession | null>(null);\n const getSearchSession = useCallback(() => {\n if (!searchSessionRef.current) {\n searchSessionRef.current = new BrainSearchSession(repoPath);\n }\n return searchSessionRef.current;\n }, [repoPath]);\n // Clean up on unmount\n useEffect(() => {\n return () => { searchSessionRef.current?.close(); };\n }, []);\n\n const width = Math.floor(rawW * 0.9);\n const height = Math.floor(rawH * 0.9);\n\n useEffect(() => {\n if (!stdout) return;\n const onResize = () => { setRawW(stdout.columns); setRawH(stdout.rows); };\n stdout.on('resize', onResize);\n return () => { stdout.off('resize', onResize); };\n }, [stdout]);\n\n // Global quit — skip in text-input views (search, callgraph)\n useInput((input) => {\n if (input === 'q' && view !== 'search' && view !== 'callgraph') { exit(); }\n });\n\n // Fetch data\n const overview = useMemo(() => fetchOverview(dbPath, repoPath, configPath), [dbPath, repoPath, configPath]);\n const languages = useMemo(() => fetchLanguageBreakdown(dbPath), [dbPath]);\n const dirs = useMemo(() => fetchDirectories(dbPath), [dbPath]);\n\n // Navigation handlers\n const drillDir = (dir: string) => {\n setCurrentDir(dir);\n setBreadcrumb([dir + '/']);\n setView('files');\n };\n\n const drillFile = (filePath: string) => {\n setCurrentFile(filePath);\n const fileName = filePath.split('/').pop() || filePath;\n setBreadcrumb([currentDir + '/', fileName]);\n setView('chunks');\n };\n\n const goBack = () => {\n if (view === 'chunks') {\n setBreadcrumb([currentDir + '/']);\n setView('files');\n } else if (view === 'files') {\n setBreadcrumb([]);\n setView('dashboard');\n } else if (view === 'callgraph' || view === 'search') {\n setBreadcrumb([]);\n setView('dashboard');\n }\n };\n\n const goCallGraph = () => {\n setBreadcrumb(['Call Graph']);\n setView('callgraph');\n };\n\n const goSearch = () => {\n setBreadcrumb(['Search']);\n setView('search');\n };\n\n return (\n <Box flexDirection=\"column\" width={width} height={height}>\n <Header repoPath={overview.repoPath} dbSizeMB={overview.dbSizeMB} view={view} breadcrumb={breadcrumb} width={width} />\n\n {view === 'dashboard' && (\n <DashboardView\n overview={overview} languages={languages} dirs={dirs}\n width={width} height={height}\n onDrillDir={drillDir} onCallGraph={goCallGraph} onSearch={goSearch}\n />\n )}\n {view === 'files' && (\n <FileExplorerView\n dbPath={dbPath} dir={currentDir}\n width={width} height={height}\n onDrillFile={drillFile} onBack={goBack}\n />\n )}\n {view === 'chunks' && (\n <ChunkViewerView\n dbPath={dbPath} filePath={currentFile}\n width={width} height={height}\n onBack={goBack}\n />\n )}\n {view === 'callgraph' && (\n <CallGraphView\n dbPath={dbPath}\n width={width} height={height}\n onBack={goBack}\n />\n )}\n {view === 'search' && (\n <SemanticSearchView\n repoPath={repoPath}\n width={width} height={height}\n onBack={goBack}\n session={getSearchSession()}\n />\n )}\n\n <Footer view={view} width={width} />\n </Box>\n );\n}\n\n\n// ── Public API ────────────────────────────────────\n\nexport async function runStatsTui(dbPath: string, repoPath: string, configPath: string): Promise<void> {\n // Clear screen + hide cursor for full-screen feel\n process.stdout.write('\\x1b[2J\\x1b[H\\x1b[?25l');\n\n const instance = render(\n <StatsApp dbPath={dbPath} repoPath={repoPath} configPath={configPath} />\n );\n await instance.waitUntilExit();\n\n // Restore: show cursor + clear screen\n process.stdout.write('\\x1b[?25h\\x1b[2J\\x1b[H');\n}\n","/**\n * stats-data.ts — Pure data-fetching functions for the Stats TUI.\n *\n * Opens a read-only `node:sqlite` DatabaseSync connection and queries\n * code_chunks, code_imports, code_call_edges, code_symbols, embedding_meta.\n * Zero state, zero React — just data.\n */\n\nimport { DatabaseSync } from 'node:sqlite';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\n\n// ── Types ─────────────────────────────────────────────\n\nexport interface StatsOverview {\n files: number;\n chunks: number;\n symbols: number;\n callEdges: number;\n importEdges: number;\n hnswSize: number;\n dbSizeMB: number;\n embeddingModel: string;\n repoPath: string;\n plugins: string[];\n pruner: string;\n expander: string;\n}\n\nexport interface LanguageStat {\n language: string;\n chunks: number;\n files: number;\n percent: number;\n}\n\nexport interface DirectoryStat {\n dir: string;\n files: number;\n chunks: number;\n percent: number;\n}\n\nexport interface FileStat {\n filePath: string;\n fileName: string;\n language: string;\n chunks: number;\n symbols: number;\n startLine: number;\n endLine: number;\n}\n\nexport interface FileDetailInfo {\n filePath: string;\n language: string;\n chunks: number;\n symbols: SymbolInfo[];\n importsOut: string[];\n importsIn: string[];\n callEdgesOut: number;\n callEdgesIn: number;\n}\n\nexport interface SymbolInfo {\n name: string;\n kind: string;\n line: number;\n}\n\nexport interface ChunkInfo {\n id: number;\n chunkType: string;\n name: string | null;\n startLine: number;\n endLine: number;\n content: string;\n language: string;\n callsOut: string[];\n calledBy: string[];\n}\n\nexport interface CallTreeNode {\n chunkId: number;\n symbol: string;\n filePath: string;\n children: CallTreeNode[];\n}\n\n\n// ── Data Access ───────────────────────────────────\n\n/** Open a read-only node:sqlite connection. */\nfunction openDb(dbPath: string): DatabaseSync {\n return new DatabaseSync(dbPath, { readOnly: true } as ConstructorParameters<typeof DatabaseSync>[1]);\n}\n\n/** Check if a table exists. */\nfunction tableExists(db: DatabaseSync, name: string): boolean {\n const row = db.prepare(\n `SELECT 1 as found FROM sqlite_master WHERE type='table' AND name=?`\n ).get(name) as Record<string, unknown> | undefined;\n return !!row;\n}\n\n/** Safe count query. */\nfunction countQuery(db: DatabaseSync, sql: string, ...params: (string | number | bigint | null | Uint8Array)[]): number {\n const row = db.prepare(sql).get(...params) as { c: number } | undefined;\n return row?.c ?? 0;\n}\n\n\n// ── Public API ────────────────────────────────────\n\nexport function fetchOverview(dbPath: string, repoPath: string, configPath: string): StatsOverview {\n const db = openDb(dbPath);\n try {\n const hasChunks = tableExists(db, 'code_chunks');\n\n const files = hasChunks ? countQuery(db, 'SELECT COUNT(DISTINCT file_path) as c FROM code_chunks') : 0;\n const chunks = hasChunks ? countQuery(db, 'SELECT COUNT(*) as c FROM code_chunks') : 0;\n const symbols = hasChunks ? countQuery(db, \"SELECT COUNT(*) as c FROM code_chunks WHERE name IS NOT NULL AND name != ''\") : 0;\n const callEdges = tableExists(db, 'code_call_edges') ? countQuery(db, 'SELECT COUNT(*) as c FROM code_call_edges') : 0;\n const importEdges = tableExists(db, 'code_imports') ? countQuery(db, 'SELECT COUNT(*) as c FROM code_imports') : 0;\n const hnswSize = tableExists(db, 'code_vectors') ? countQuery(db, 'SELECT COUNT(*) as c FROM code_vectors') : 0;\n\n // DB file size\n const stat = fs.statSync(dbPath);\n const dbSizeMB = Math.round(stat.size / 1048576 * 10) / 10;\n\n // Embedding model\n let embeddingModel = 'unknown';\n if (tableExists(db, 'embedding_meta')) {\n for (const key of ['provider_key', 'provider', 'model']) {\n const row = db.prepare(`SELECT value FROM embedding_meta WHERE key = ?`).get(key) as { value: string } | undefined;\n if (row) { embeddingModel = row.value; break; }\n }\n }\n\n // Config\n let plugins: string[] = ['code'];\n let pruner = 'none';\n let expander = 'none';\n try {\n const raw = fs.readFileSync(configPath, 'utf-8');\n const config = JSON.parse(raw) as Record<string, unknown>;\n if (Array.isArray(config.plugins)) plugins = config.plugins as string[];\n if (typeof config.pruner === 'string') pruner = config.pruner;\n if (typeof config.expander === 'string') expander = config.expander;\n } catch { /* no config */ }\n\n return { files, chunks, symbols, callEdges, importEdges, hnswSize, dbSizeMB, embeddingModel, repoPath, plugins, pruner, expander };\n } finally {\n db.close();\n }\n}\n\nexport function fetchLanguageBreakdown(dbPath: string): LanguageStat[] {\n const db = openDb(dbPath);\n try {\n if (!tableExists(db, 'code_chunks')) return [];\n\n const rows = db.prepare(`\n SELECT language, COUNT(*) as chunks, COUNT(DISTINCT file_path) as files\n FROM code_chunks\n GROUP BY language\n ORDER BY chunks DESC\n `).all() as { language: string; chunks: number; files: number }[];\n\n const total = rows.reduce((sum, r) => sum + r.chunks, 0);\n return rows.map(r => ({\n language: r.language,\n chunks: r.chunks,\n files: r.files,\n percent: total > 0 ? Math.round(r.chunks / total * 1000) / 10 : 0,\n }));\n } finally {\n db.close();\n }\n}\n\nexport function fetchDirectories(dbPath: string): DirectoryStat[] {\n const db = openDb(dbPath);\n try {\n if (!tableExists(db, 'code_chunks')) return [];\n\n const rows = db.prepare(`\n SELECT\n CASE\n WHEN INSTR(file_path, '/') > 0 THEN SUBSTR(file_path, 1, INSTR(file_path, '/') - 1)\n ELSE file_path\n END as dir,\n COUNT(DISTINCT file_path) as files,\n COUNT(*) as chunks\n FROM code_chunks\n GROUP BY dir\n ORDER BY chunks DESC\n `).all() as { dir: string; files: number; chunks: number }[];\n\n const total = rows.reduce((sum, r) => sum + r.chunks, 0);\n return rows.map(r => ({\n dir: r.dir,\n files: r.files,\n chunks: r.chunks,\n percent: total > 0 ? Math.round(r.chunks / total * 1000) / 10 : 0,\n }));\n } finally {\n db.close();\n }\n}\n\nexport function fetchFilesInDir(dbPath: string, dir: string): FileStat[] {\n const db = openDb(dbPath);\n try {\n if (!tableExists(db, 'code_chunks')) return [];\n\n const rows = db.prepare(`\n SELECT\n file_path,\n language,\n COUNT(*) as chunks,\n COUNT(CASE WHEN name IS NOT NULL AND name != '' THEN 1 END) as symbols,\n MIN(start_line) as min_line,\n MAX(end_line) as max_line\n FROM code_chunks\n WHERE file_path LIKE ? || '%'\n GROUP BY file_path\n ORDER BY chunks DESC, file_path\n `).all(`${dir}/`) as { file_path: string; language: string; chunks: number; symbols: number; min_line: number; max_line: number }[];\n\n return rows.map(r => ({\n filePath: r.file_path,\n fileName: path.basename(r.file_path),\n language: r.language,\n chunks: r.chunks,\n symbols: r.symbols,\n startLine: r.min_line,\n endLine: r.max_line,\n }));\n } finally {\n db.close();\n }\n}\n\nexport function fetchFileDetail(dbPath: string, filePath: string): FileDetailInfo {\n const db = openDb(dbPath);\n try {\n // Language + chunk count\n const meta = db.prepare(`\n SELECT language, COUNT(*) as chunks\n FROM code_chunks WHERE file_path = ?\n `).get(filePath) as { language: string; chunks: number } | undefined;\n\n // Symbols — extract named chunks as symbols\n const symbols = db.prepare(`\n SELECT name, chunk_type as kind, start_line as line\n FROM code_chunks\n WHERE file_path = ? AND name IS NOT NULL AND name != ''\n ORDER BY start_line\n `).all(filePath) as unknown as SymbolInfo[];\n\n // Imports out (this file imports...)\n let importsOut: string[] = [];\n if (tableExists(db, 'code_imports')) {\n importsOut = (db.prepare(`\n SELECT imports_path FROM code_imports WHERE file_path = ?\n `).all(filePath) as { imports_path: string }[]).map(r => r.imports_path);\n }\n\n // Imports in (who imports this file)\n let importsIn: string[] = [];\n if (tableExists(db, 'code_imports')) {\n const base = path.basename(filePath, path.extname(filePath));\n importsIn = (db.prepare(`\n SELECT file_path FROM code_imports WHERE imports_path LIKE ?\n `).all(`%${base}%`) as { file_path: string }[]).map(r => r.file_path);\n }\n\n // Call edges\n let callEdgesOut = 0;\n let callEdgesIn = 0;\n if (tableExists(db, 'code_call_edges')) {\n const chunkIds = (db.prepare(\n `SELECT id FROM code_chunks WHERE file_path = ?`\n ).all(filePath) as { id: number }[]).map(r => r.id);\n\n if (chunkIds.length > 0) {\n const ph = chunkIds.map(() => '?').join(',');\n callEdgesOut = countQuery(db, `SELECT COUNT(*) as c FROM code_call_edges WHERE caller_chunk_id IN (${ph})`, ...chunkIds);\n callEdgesIn = countQuery(db, `SELECT COUNT(*) as c FROM code_call_edges WHERE callee_chunk_id IN (${ph})`, ...chunkIds);\n }\n }\n\n return {\n filePath,\n language: meta?.language ?? 'unknown',\n chunks: meta?.chunks ?? 0,\n symbols,\n importsOut,\n importsIn,\n callEdgesOut,\n callEdgesIn,\n };\n } finally {\n db.close();\n }\n}\n\nexport function fetchChunksForFile(dbPath: string, filePath: string): ChunkInfo[] {\n const db = openDb(dbPath);\n try {\n if (!tableExists(db, 'code_chunks')) return [];\n\n const rows = db.prepare(`\n SELECT id, chunk_type, name, start_line, end_line, content, language\n FROM code_chunks\n WHERE file_path = ?\n ORDER BY start_line\n `).all(filePath) as { id: number; chunk_type: string; name: string | null; start_line: number; end_line: number; content: string; language: string }[];\n\n const hasCallEdges = tableExists(db, 'code_call_edges');\n\n return rows.map(r => {\n let callsOut: string[] = [];\n let calledBy: string[] = [];\n\n if (hasCallEdges) {\n callsOut = (db.prepare(`\n SELECT DISTINCT symbol_name FROM code_call_edges WHERE caller_chunk_id = ?\n `).all(r.id) as { symbol_name: string }[]).map(row => row.symbol_name);\n\n calledBy = (db.prepare(`\n SELECT DISTINCT symbol_name FROM code_call_edges WHERE callee_chunk_id = ?\n `).all(r.id) as { symbol_name: string }[]).map(row => row.symbol_name);\n }\n\n return {\n id: r.id,\n chunkType: r.chunk_type,\n name: r.name,\n startLine: r.start_line,\n endLine: r.end_line,\n content: r.content,\n language: r.language,\n callsOut,\n calledBy,\n };\n });\n } finally {\n db.close();\n }\n}\n\nexport function fetchCallTree(dbPath: string, chunkId: number, depth: number = 3): CallTreeNode {\n const db = openDb(dbPath);\n try {\n const chunk = db.prepare(`\n SELECT id, name, file_path FROM code_chunks WHERE id = ?\n `).get(chunkId) as { id: number; name: string | null; file_path: string } | undefined;\n\n if (!chunk) return { chunkId, symbol: '?', filePath: '?', children: [] };\n\n function expand(id: number, d: number, visited: Set<number>): CallTreeNode[] {\n if (d <= 0 || !tableExists(db, 'code_call_edges')) return [];\n\n const edges = db.prepare(`\n SELECT DISTINCT ce.callee_chunk_id, ce.symbol_name, cc.file_path\n FROM code_call_edges ce\n JOIN code_chunks cc ON cc.id = ce.callee_chunk_id\n WHERE ce.caller_chunk_id = ?\n ORDER BY ce.symbol_name\n `).all(id) as { callee_chunk_id: number; symbol_name: string; file_path: string }[];\n\n return edges\n .filter(e => !visited.has(e.callee_chunk_id))\n .map(e => {\n visited.add(e.callee_chunk_id);\n return {\n chunkId: e.callee_chunk_id,\n symbol: e.symbol_name,\n filePath: e.file_path,\n children: expand(e.callee_chunk_id, d - 1, visited),\n };\n });\n }\n\n const visited = new Set([chunkId]);\n return {\n chunkId,\n symbol: chunk.name ?? 'anonymous',\n filePath: chunk.file_path,\n children: expand(chunkId, depth, visited),\n };\n } finally {\n db.close();\n }\n}\n\n/** Search for chunks by symbol name — used by call graph view. */\nexport function searchSymbols(dbPath: string, query: string, limit: number = 10): { id: number; name: string; filePath: string }[] {\n const db = openDb(dbPath);\n try {\n if (!tableExists(db, 'code_chunks')) return [];\n return (db.prepare(`\n SELECT id, name, file_path as filePath FROM code_chunks\n WHERE name LIKE ? AND name IS NOT NULL AND name != ''\n ORDER BY name LIMIT ?\n `).all(`%${query}%`, limit) as { id: number; name: string; filePath: string }[]);\n } finally {\n db.close();\n }\n}\n\n/** Search result for full-text search. */\nexport interface SearchResultItem {\n id: number;\n filePath: string;\n name: string | null;\n chunkType: string;\n startLine: number;\n endLine: number;\n language: string;\n matchContext: string;\n}\n\n/** Full-text search across chunk content, names, file paths. Returns matching chunks with context. */\nexport function searchChunks(dbPath: string, query: string, limit: number = 30): SearchResultItem[] {\n const db = openDb(dbPath);\n try {\n if (!tableExists(db, 'code_chunks')) return [];\n\n // Try FTS first (if fts_code exists)\n if (tableExists(db, 'fts_code')) {\n try {\n const rows = db.prepare(`\n SELECT cc.id, cc.file_path, cc.name, cc.chunk_type, cc.start_line, cc.end_line, cc.language,\n snippet(fts_code, 0, '>>>', '<<<', '...', 40) as match_ctx\n FROM fts_code ft\n JOIN code_chunks cc ON cc.id = ft.rowid\n WHERE fts_code MATCH ?\n ORDER BY rank\n LIMIT ?\n `).all(query, limit) as unknown as { id: number; file_path: string; name: string | null; chunk_type: string; start_line: number; end_line: number; language: string; match_ctx: string }[];\n\n return rows.map(r => ({\n id: r.id,\n filePath: r.file_path,\n name: r.name,\n chunkType: r.chunk_type,\n startLine: r.start_line,\n endLine: r.end_line,\n language: r.language,\n matchContext: r.match_ctx,\n }));\n } catch {\n // FTS query parse error — fall through to LIKE\n }\n }\n\n // Fallback: LIKE search across name, file_path, content\n const rows = db.prepare(`\n SELECT id, file_path, name, chunk_type, start_line, end_line, language,\n SUBSTR(content, MAX(1, INSTR(LOWER(content), LOWER(?)) - 40), 100) as match_ctx\n FROM code_chunks\n WHERE chunk_type != 'synopsis'\n AND (LOWER(name) LIKE LOWER(?) OR LOWER(file_path) LIKE LOWER(?) OR LOWER(content) LIKE LOWER(?))\n ORDER BY\n CASE WHEN LOWER(name) LIKE LOWER(?) THEN 0\n WHEN LOWER(file_path) LIKE LOWER(?) THEN 1\n ELSE 2 END,\n file_path, start_line\n LIMIT ?\n `).all(query, `%${query}%`, `%${query}%`, `%${query}%`, `%${query}%`, `%${query}%`, limit) as unknown as { id: number; file_path: string; name: string | null; chunk_type: string; start_line: number; end_line: number; language: string; match_ctx: string }[];\n\n return rows.map(r => ({\n id: r.id,\n filePath: r.file_path,\n name: r.name,\n chunkType: r.chunk_type,\n startLine: r.start_line,\n endLine: r.end_line,\n language: r.language,\n matchContext: r.match_ctx || '',\n }));\n } finally {\n db.close();\n }\n}\n\n/** Fetch a single chunk by ID. */\nexport function fetchChunkById(dbPath: string, chunkId: number): ChunkInfo | null {\n const db = openDb(dbPath);\n try {\n const r = db.prepare(`\n SELECT id, chunk_type, name, start_line, end_line, content, language\n FROM code_chunks WHERE id = ?\n `).get(chunkId) as { id: number; chunk_type: string; name: string | null; start_line: number; end_line: number; content: string; language: string } | undefined;\n\n if (!r) return null;\n\n let callsOut: string[] = [];\n let calledBy: string[] = [];\n if (tableExists(db, 'code_call_edges')) {\n callsOut = (db.prepare(`SELECT DISTINCT symbol_name FROM code_call_edges WHERE caller_chunk_id = ?`).all(r.id) as { symbol_name: string }[]).map(row => row.symbol_name);\n calledBy = (db.prepare(`SELECT DISTINCT symbol_name FROM code_call_edges WHERE callee_chunk_id = ?`).all(r.id) as { symbol_name: string }[]).map(row => row.symbol_name);\n }\n\n return {\n id: r.id,\n chunkType: r.chunk_type,\n name: r.name,\n startLine: r.start_line,\n endLine: r.end_line,\n content: r.content,\n language: r.language,\n callsOut,\n calledBy,\n };\n } finally {\n db.close();\n }\n}\n\n","/**\n * BrainBank — Stats TUI Search Session\n *\n * Wraps a BrainBank instance to provide staged search pipeline results\n * for the interactive TUI. Captures each stage (raw → pruned → expanded)\n * separately so the UI can display them side-by-side.\n *\n * Lazy initialization: the brain is created on first search.\n */\n\nimport type { SearchResult, Pruner, Expander, ExpanderManifestItem } from '@/types.ts';\nimport type { BrainBank } from '@/brainbank.ts';\n\nimport { createBrain } from '@/cli/factory/index.ts';\nimport { pruneResults } from '@/lib/prune.ts';\nimport { isExpandablePlugin } from '@/plugin.ts';\n\n// ── Types ─────────────────────────────────────────\n\n/** Timings for each pipeline stage (ms). */\nexport interface PipelineTimings {\n init: number;\n search: number;\n prune: number;\n expand: number;\n total: number;\n}\n\n/** Full result of a staged search pipeline run. */\nexport interface SearchPipelineResult {\n /** All results from vector search (before pruning). */\n raw: SearchResult[];\n /** Results after LLM pruner filtered noise. Same order as pruner returned. */\n pruned: SearchResult[];\n /** Results dropped by pruner (raw minus pruned). */\n dropped: SearchResult[];\n /** Additional results discovered by LLM expander. */\n expanded: SearchResult[];\n /** Pipeline stage timings. */\n timings: PipelineTimings;\n /** Name of the active pruner (or null if none). */\n prunerName: string | null;\n /** Name of the active expander (or null if none). */\n expanderName: string | null;\n}\n\n/** Source filter option — discovered from registered plugins. */\nexport interface SourceOption {\n /** Source key: 'code', 'git', 'docs', etc. */\n key: string;\n /** Display label. */\n label: string;\n /** Whether this source is enabled for the current search. */\n enabled: boolean;\n /** Max results for this source (default: 20). */\n k: number;\n}\n\n// ── Session ───────────────────────────────────────\n\nexport class BrainSearchSession {\n private _brain: BrainBank | null = null;\n private _repoPath: string;\n private _initPromise: Promise<void> | null = null;\n private _sources: SourceOption[] = [];\n\n constructor(repoPath: string) {\n this._repoPath = repoPath;\n }\n\n /** Whether the brain has been initialized. */\n get initialized(): boolean {\n return this._brain !== null;\n }\n\n /** Available source filters (populated after init). */\n get sources(): readonly SourceOption[] {\n return this._sources;\n }\n\n /** Pruner name (or null). */\n get prunerName(): string | null {\n return this._brain?.config.pruner?.constructor?.name ?? null;\n }\n\n /** Expander name (or null). */\n get expanderName(): string | null {\n return this._brain?.config.expander?.constructor?.name ?? null;\n }\n\n /**\n * Initialize the BrainBank instance (lazy, idempotent).\n * Creates the brain, loads HNSW + FTS indices.\n */\n async init(): Promise<void> {\n if (this._brain) return;\n if (this._initPromise) return this._initPromise;\n\n this._initPromise = this._doInit();\n return this._initPromise;\n }\n\n private async _doInit(): Promise<void> {\n this._brain = await createBrain(this._repoPath);\n await this._brain.initialize();\n\n // Discover installed sources from plugin names (no 'all' — user selects individually)\n this._sources = [];\n const seen = new Set<string>();\n for (const name of this._brain.plugins) {\n const base = name.split(':')[0];\n if (seen.has(base)) continue;\n seen.add(base);\n this._sources.push({\n key: base,\n label: base.charAt(0).toUpperCase() + base.slice(1),\n enabled: true,\n k: 20,\n });\n }\n }\n\n /**\n * Run the full search pipeline and return staged results.\n *\n * @param query - Search query\n * @param activeSourceKeys - Set of active source keys (e.g. {'code', 'git'})\n * @param usePruner - Whether to run the pruner stage\n * @param useExpander - Whether to run the expander stage\n */\n async search(\n query: string,\n activeSourceKeys?: Set<string>,\n usePruner = true,\n useExpander = true,\n ): Promise<SearchPipelineResult> {\n if (!this._brain) throw new Error('BrainSearchSession not initialized');\n\n const tTotal = Date.now();\n const pruner = usePruner ? (this._brain.config.pruner as Pruner | undefined) : undefined;\n const expander = useExpander ? (this._brain.config.expander as Expander | undefined) : undefined;\n\n // Build sources filter — always pass K values so we don't fall back to DEFAULT_K=6\n const sources: Record<string, number> = {};\n for (const src of this._sources) {\n const enabled = activeSourceKeys ? activeSourceKeys.has(src.key) : src.enabled;\n sources[src.key] = enabled ? src.k : 0;\n }\n\n // Stage 1: Vector search\n const tSearch0 = Date.now();\n const raw = await this._brain.search(query, {\n sources,\n source: 'cli',\n });\n const tSearch = Date.now() - tSearch0;\n\n // Stage 2: Prune\n let pruned = raw;\n let dropped: SearchResult[] = [];\n let tPrune = 0;\n if (pruner && raw.length > 1) {\n const pt0 = Date.now();\n pruned = await pruneResults(query, raw, pruner);\n tPrune = Date.now() - pt0;\n const prunedSet = new Set(pruned);\n dropped = raw.filter(r => !prunedSet.has(r));\n }\n\n // Stage 3: Expand — filter results to only include active sources\n let expanded: SearchResult[] = [];\n let tExpand = 0;\n if (expander && pruned.length > 0) {\n const et0 = Date.now();\n let expandedRaw = await this._runExpansion(query, pruned, expander);\n // Filter expanded results by active sources\n if (activeSourceKeys) {\n expandedRaw = expandedRaw.filter(r => activeSourceKeys.has(r.type));\n }\n expanded = expandedRaw;\n tExpand = Date.now() - et0;\n }\n\n return {\n raw,\n pruned,\n dropped,\n expanded,\n timings: {\n init: 0,\n search: tSearch,\n prune: tPrune,\n expand: tExpand,\n total: Date.now() - tTotal,\n },\n prunerName: usePruner ? (pruner?.constructor?.name ?? null) : null,\n expanderName: useExpander ? (expander?.constructor?.name ?? null) : null,\n };\n }\n\n /** Run LLM expansion — mirrors ContextBuilder._expand logic. */\n private async _runExpansion(\n query: string,\n results: SearchResult[],\n expander: Expander,\n ): Promise<SearchResult[]> {\n if (!this._brain) return [];\n\n // Collect file paths and IDs already in results\n const excludeFilePaths = [...new Set(\n results.filter(r => r.filePath).map(r => r.filePath as string),\n )];\n const excludeIds: number[] = [];\n for (const r of results) {\n const meta = r.metadata as Record<string, unknown> | undefined;\n const id = meta?.id as number | undefined;\n if (id !== undefined) excludeIds.push(id);\n }\n\n // Build manifest from ExpandablePlugins\n const manifest: ExpanderManifestItem[] = [];\n let resolver: ((ids: number[]) => SearchResult[]) | undefined;\n\n // Access plugins via the brain's plugin list\n // We need the registry... which is private. Use a workaround:\n // BrainBank exposes `plugins` (names) but not instances.\n // However, we can access it through the search functionality.\n // The cleanest approach: use the brain's internal registry via\n // a property we know exists on the class.\n const registry = (this._brain as unknown as { _registry: { all: unknown[] } })._registry;\n if (registry) {\n for (const mod of registry.all) {\n if (!isExpandablePlugin(mod as never)) continue;\n const plugin = mod as { buildManifest: (fp: string[], ids: number[], rfp?: string[]) => ExpanderManifestItem[]; resolveChunks: (ids: number[]) => SearchResult[] };\n manifest.push(...plugin.buildManifest(excludeFilePaths, excludeIds, excludeFilePaths));\n if (!resolver) {\n resolver = (ids: number[]) => plugin.resolveChunks(ids);\n }\n }\n }\n\n if (manifest.length === 0 || !resolver) return [];\n\n try {\n const expandResult = await expander.expand(query, excludeIds, manifest);\n if (expandResult.ids.length === 0) return [];\n return resolver(expandResult.ids);\n } catch {\n // Fail-open: expansion errors are non-fatal\n return [];\n }\n }\n\n /** Cleanup. */\n close(): void {\n if (this._brain) {\n this._brain.close();\n this._brain = null;\n }\n this._initPromise = null;\n }\n}\n"],"mappings":"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","names":["expand","visited","session"]}
package/package.json ADDED
@@ -0,0 +1,96 @@
1
+ {
2
+ "name": "brainbank",
3
+ "version": "0.1.0-beta.1",
4
+ "description": "Pluggable semantic memory for AI agents — hybrid search (vector + BM25) in a single SQLite file. Built-in code, git, and docs indexers. Bring your own.",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "bin": {
8
+ "brainbank": "./bin/brainbank",
9
+ "brainbank-mcp": "./bin/brainbank-mcp"
10
+ },
11
+ "exports": {
12
+ ".": {
13
+ "import": "./dist/index.js",
14
+ "default": "./dist/index.js"
15
+ },
16
+ "./src/*": "./src/*",
17
+ "./dist/*": "./dist/*"
18
+ },
19
+ "files": [
20
+ "dist/",
21
+ "src/",
22
+ "bin/",
23
+ "LICENSE",
24
+ "README.md",
25
+ "assets/"
26
+ ],
27
+ "scripts": {
28
+ "start": "bin/brainbank",
29
+ "build": "rm -rf dist && tsup && npm run build --workspaces --if-present",
30
+ "build:core": "rm -rf dist && tsup",
31
+ "prepublishOnly": "npm run build:core",
32
+ "test": "node --import tsx test/run.ts",
33
+ "link": "npm link",
34
+ "unlink": "npm unlink -g brainbank",
35
+ "link:all": "npm link && npm link --workspaces && npm link brainbank --legacy-peer-deps",
36
+ "unlink:all": "npm unlink -g brainbank && npm unlink --workspaces -g"
37
+ },
38
+ "workspaces": [
39
+ "packages/*"
40
+ ],
41
+ "engines": {
42
+ "node": ">=22"
43
+ },
44
+ "repository": {
45
+ "type": "git",
46
+ "url": "git+https://github.com/pinecall/brainbank.git"
47
+ },
48
+ "homepage": "https://github.com/pinecall/brainbank#readme",
49
+ "bugs": {
50
+ "url": "https://github.com/pinecall/brainbank/issues"
51
+ },
52
+ "keywords": [
53
+ "ai",
54
+ "agent",
55
+ "semantic-memory",
56
+ "vector-search",
57
+ "knowledge-base",
58
+ "embeddings",
59
+ "hnsw",
60
+ "typescript"
61
+ ],
62
+ "author": "Bernardo Castro <bernardo@pinecall.io>",
63
+ "license": "MIT",
64
+ "dependencies": {
65
+ "@huggingface/transformers": "^4.0.1",
66
+ "@inquirer/prompts": "^8.3.2",
67
+ "@modelcontextprotocol/sdk": "^1.27.1",
68
+ "hnswlib-node": "^3.0.0",
69
+ "ink": "^5.2.1",
70
+ "picomatch": "^4.0.4",
71
+ "react": "^18.3.1",
72
+ "zod": "^4.3.6"
73
+ },
74
+ "optionalDependencies": {
75
+ "@brainbank/code": "^0.1.1",
76
+ "@brainbank/docs": "^0.1.1",
77
+ "@brainbank/git": "^0.1.1",
78
+ "@xenova/transformers": "^2.17.2",
79
+ "node-llama-cpp": "^3.18.1"
80
+ },
81
+ "devDependencies": {
82
+ "@ai-sdk/openai": "^3.0.47",
83
+ "@langchain/core": "^1.1.35",
84
+ "@langchain/openai": "^1.3.0",
85
+ "@types/node": "^22.0.0",
86
+ "@types/picomatch": "^4.0.2",
87
+ "@types/react": "^18.3.28",
88
+ "ai": "^6.0.134",
89
+ "tsup": "^8.4.0",
90
+ "tsx": "^4.19.0",
91
+ "typescript": "^5.7.0"
92
+ },
93
+ "overrides": {
94
+ "brainbank": "$brainbank"
95
+ }
96
+ }