brainbank 0.1.1 → 0.2.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 (50) hide show
  1. package/README.md +149 -16
  2. package/dist/{types-Da_zLLOl.d.ts → base-9vfWRHCV.d.ts} +131 -31
  3. package/dist/{chunk-YGSEUWLV.js → chunk-6MFTQV3O.js} +911 -674
  4. package/dist/chunk-6MFTQV3O.js.map +1 -0
  5. package/dist/chunk-7JCEW7LT.js +266 -0
  6. package/dist/chunk-7JCEW7LT.js.map +1 -0
  7. package/dist/{chunk-GOUBW7UA.js → chunk-F6SJ3U4H.js} +98 -34
  8. package/dist/chunk-F6SJ3U4H.js.map +1 -0
  9. package/dist/{chunk-MJ3Y24H6.js → chunk-FJJY4H2Y.js} +11 -11
  10. package/dist/chunk-FJJY4H2Y.js.map +1 -0
  11. package/dist/{chunk-3GAIDXRW.js → chunk-GUT5MSJT.js} +5 -11
  12. package/dist/chunk-GUT5MSJT.js.map +1 -0
  13. package/dist/{chunk-2P3EGY6S.js → chunk-QNHBCOKB.js} +2 -2
  14. package/dist/chunk-QNHBCOKB.js.map +1 -0
  15. package/dist/{chunk-4ZKBQ33J.js → chunk-V4UJKXPK.js} +23 -5
  16. package/dist/chunk-V4UJKXPK.js.map +1 -0
  17. package/dist/chunk-WR4WXKJT.js +723 -0
  18. package/dist/chunk-WR4WXKJT.js.map +1 -0
  19. package/dist/{chunk-Z5SU54HP.js → chunk-X6645UVR.js} +3 -3
  20. package/dist/chunk-X6645UVR.js.map +1 -0
  21. package/dist/cli.js +150 -100
  22. package/dist/cli.js.map +1 -1
  23. package/dist/code.d.ts +5 -5
  24. package/dist/code.js +1 -1
  25. package/dist/docs.d.ts +4 -6
  26. package/dist/docs.js +1 -1
  27. package/dist/git.d.ts +5 -5
  28. package/dist/git.js +1 -1
  29. package/dist/index.d.ts +95 -104
  30. package/dist/index.js +13 -13
  31. package/dist/memory.d.ts +5 -7
  32. package/dist/memory.js +9 -12
  33. package/dist/memory.js.map +1 -1
  34. package/dist/notes.d.ts +4 -6
  35. package/dist/notes.js +7 -10
  36. package/dist/notes.js.map +1 -1
  37. package/dist/{openai-PCTYLOWI.js → openai-CYDMYX7X.js} +2 -2
  38. package/package.json +24 -4
  39. package/dist/chunk-2P3EGY6S.js.map +0 -1
  40. package/dist/chunk-3GAIDXRW.js.map +0 -1
  41. package/dist/chunk-4ZKBQ33J.js.map +0 -1
  42. package/dist/chunk-EDKSKLX4.js +0 -490
  43. package/dist/chunk-EDKSKLX4.js.map +0 -1
  44. package/dist/chunk-GOUBW7UA.js.map +0 -1
  45. package/dist/chunk-MJ3Y24H6.js.map +0 -1
  46. package/dist/chunk-N6ZMBFDE.js +0 -224
  47. package/dist/chunk-N6ZMBFDE.js.map +0 -1
  48. package/dist/chunk-YGSEUWLV.js.map +0 -1
  49. package/dist/chunk-Z5SU54HP.js.map +0 -1
  50. /package/dist/{openai-PCTYLOWI.js.map → openai-CYDMYX7X.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/indexers/code/code-indexer.ts","../src/indexers/code/code-chunker.ts","../src/indexers/code/grammars.ts","../src/indexers/languages.ts","../src/indexers/code/code-plugin.ts"],"sourcesContent":["/**\n * BrainBank — Code Indexer\n * \n * Walks a repository, chunks source files semantically,\n * embeds each chunk, and stores in SQLite + HNSW.\n * Incremental: only re-indexes files that changed (by content hash).\n */\n\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { CodeChunker } from './code-chunker.ts';\nimport { SUPPORTED_EXTENSIONS, IGNORE_DIRS, isIgnoredDir, isIgnoredFile } from '../languages.ts';\nimport type { Database } from '../../db/database.ts';\nimport type { EmbeddingProvider, ProgressCallback, IndexResult } from '../../types.ts';\nimport type { HNSWIndex } from '../../providers/vector/hnsw.ts';\n\nexport interface CodeIndexerDeps {\n db: Database;\n hnsw: HNSWIndex;\n vectorCache: Map<number, Float32Array>;\n embedding: EmbeddingProvider;\n}\n\nexport interface CodeIndexOptions {\n forceReindex?: boolean;\n onProgress?: ProgressCallback;\n}\n\nexport class CodeIndexer {\n private _chunker = new CodeChunker();\n private _deps: CodeIndexerDeps;\n private _repoPath: string;\n private _maxFileSize: number;\n\n constructor(repoPath: string, deps: CodeIndexerDeps, maxFileSize: number = 512_000) {\n this._deps = deps;\n this._repoPath = repoPath;\n this._maxFileSize = maxFileSize;\n }\n\n /**\n * Index all supported files in the repository.\n * Skips unchanged files (same content hash).\n */\n async index(options: CodeIndexOptions = {}): Promise<IndexResult> {\n const { forceReindex = false, onProgress } = options;\n const files = this._walkRepo(this._repoPath);\n let indexed = 0, skipped = 0, totalChunks = 0;\n\n for (let i = 0; i < files.length; i++) {\n const filePath = files[i];\n const rel = path.relative(this._repoPath, filePath);\n onProgress?.(rel, i + 1, files.length);\n\n let content: string;\n try { content = fs.readFileSync(filePath, 'utf-8'); }\n catch { continue; }\n\n const hash = this._hash(content);\n const existing = this._deps.db.prepare(\n 'SELECT file_hash FROM indexed_files WHERE file_path = ?'\n ).get(rel) as any;\n\n if (!forceReindex && existing?.file_hash === hash) {\n skipped++;\n continue;\n }\n\n // Always clean up old chunks for this file (catches orphaned chunks from interrupted first-run)\n const oldChunks = this._deps.db.prepare(\n 'SELECT id FROM code_chunks WHERE file_path = ?'\n ).all(rel) as any[];\n if (oldChunks.length > 0) {\n for (const { id } of oldChunks) {\n this._deps.hnsw.remove(id);\n this._deps.vectorCache.delete(id);\n }\n this._deps.db.prepare('DELETE FROM code_chunks WHERE file_path = ?').run(rel);\n }\n\n const ext = path.extname(filePath).toLowerCase();\n const language = SUPPORTED_EXTENSIONS[ext] ?? 'text';\n const chunks = await this._chunker.chunk(rel, content, language);\n\n // Build embedding texts for all chunks and batch embed (10-50x faster)\n const embeddingTexts = chunks.map(chunk => [\n `File: ${rel}`,\n chunk.name ? `${chunk.chunkType}: ${chunk.name}` : chunk.chunkType,\n chunk.content,\n ].join('\\n'));\n\n const vecs = await this._deps.embedding.embedBatch(embeddingTexts);\n\n // Insert chunks + vectors individually (preserves auto-increment ID ordering)\n for (let ci = 0; ci < chunks.length; ci++) {\n const chunk = chunks[ci];\n const result = this._deps.db.prepare(\n `INSERT INTO code_chunks (file_path, chunk_type, name, start_line, end_line, content, language, file_hash)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?)`\n ).run(rel, chunk.chunkType, chunk.name ?? null, chunk.startLine, chunk.endLine, chunk.content, language, hash);\n\n const id = Number(result.lastInsertRowid);\n this._deps.db.prepare(\n 'INSERT INTO code_vectors (chunk_id, embedding) VALUES (?, ?)'\n ).run(id, Buffer.from(vecs[ci].buffer));\n\n this._deps.hnsw.add(vecs[ci], id);\n this._deps.vectorCache.set(id, vecs[ci]);\n totalChunks++;\n }\n\n // Mark file as indexed\n this._deps.db.prepare(\n 'INSERT OR REPLACE INTO indexed_files (file_path, file_hash) VALUES (?, ?)'\n ).run(rel, hash);\n indexed++;\n }\n\n return { indexed, skipped, chunks: totalChunks };\n }\n\n // ── File Walker ─────────────────────────────────\n\n private _walkRepo(dir: string, files: string[] = []): string[] {\n let entries: fs.Dirent[];\n try { entries = fs.readdirSync(dir, { withFileTypes: true }); }\n catch { return files; }\n\n for (const entry of entries) {\n if (entry.isDirectory()) {\n if (isIgnoredDir(entry.name)) continue;\n this._walkRepo(path.join(dir, entry.name), files);\n } else if (entry.isFile()) {\n if (isIgnoredFile(entry.name)) continue;\n const ext = path.extname(entry.name).toLowerCase();\n if (!(ext in SUPPORTED_EXTENSIONS)) continue;\n\n const full = path.join(dir, entry.name);\n try {\n if (fs.statSync(full).size <= this._maxFileSize) {\n files.push(full);\n }\n } catch {}\n }\n }\n return files;\n }\n\n // ── FNV-1a Hash ─────────────────────────────────\n\n private _hash(content: string): string {\n let h = 2166136261;\n for (let i = 0; i < content.length; i++) {\n h ^= content.charCodeAt(i);\n h = (h * 16777619) >>> 0;\n }\n return h.toString(16);\n }\n}\n","/**\n * BrainBank — Tree-Sitter Code Chunker\n * \n * AST-aware code splitting using native tree-sitter bindings.\n * Extracts semantic blocks (functions, classes, methods, interfaces)\n * from the AST. Falls back to sliding window for unsupported languages.\n */\n\nimport { createRequire } from 'node:module';\nimport type { CodeChunk } from '../../types.ts';\nimport { GRAMMARS, type LangGrammar } from './grammars.ts';\n\nconst require = createRequire(import.meta.url);\n\n// ── Configuration ───────────────────────────────────\n\nexport interface ChunkerConfig {\n /** Max lines per chunk. Default: 80 */\n maxLines?: number;\n /** Min lines for a detected block to be a chunk. Default: 3 */\n minLines?: number;\n /** Overlap between adjacent generic chunks. Default: 5 */\n overlap?: number;\n}\n\n// ── CodeChunker ─────────────────────────────────────\n\nexport class CodeChunker {\n private MAX: number;\n private MIN: number;\n private OVERLAP: number;\n private _parser: any = null;\n private _langCache = new Map<string, LangGrammar | null>();\n\n constructor(config: ChunkerConfig = {}) {\n this.MAX = config.maxLines ?? 80;\n this.MIN = config.minLines ?? 3;\n this.OVERLAP = config.overlap ?? 5;\n }\n\n /** Lazy-init tree-sitter parser. */\n private _ensureParser(): any {\n if (!this._parser) {\n try {\n const Parser = require('tree-sitter');\n this._parser = new Parser();\n } catch {\n this._parser = false; // Mark as unavailable\n }\n }\n return this._parser || null;\n }\n\n /** Load a language grammar (cached). */\n private _loadGrammar(language: string): LangGrammar | null {\n if (this._langCache.has(language)) return this._langCache.get(language)!;\n\n const factory = GRAMMARS[language];\n const grammar = factory ? factory() : null;\n this._langCache.set(language, grammar);\n return grammar;\n }\n\n /**\n * Split file content into semantic chunks using tree-sitter AST.\n * Falls back to sliding window if grammar isn't available.\n */\n async chunk(filePath: string, content: string, language: string): Promise<CodeChunk[]> {\n const lines = content.split('\\n');\n\n // Small file → single chunk\n if (lines.length <= this.MAX) {\n return [{\n filePath,\n chunkType: 'file',\n startLine: 1,\n endLine: lines.length,\n content: content.trim(),\n language,\n }];\n }\n\n // Try tree-sitter AST chunking\n const parser = this._ensureParser();\n const langConfig = this._loadGrammar(language);\n\n if (parser && langConfig) {\n try {\n parser.setLanguage(langConfig.grammar);\n const tree = parser.parse(content);\n const chunks = this._extractChunks(filePath, lines, tree.rootNode, langConfig, language);\n\n if (chunks.length > 0) {\n return chunks.filter(c => c.content.length > 20);\n }\n } catch {\n // Tree-sitter failed — fall through to generic\n }\n }\n\n // Fallback to sliding window\n return this._chunkGeneric(filePath, lines, language);\n }\n\n /** Walk AST and extract top-level semantic blocks. */\n private _extractChunks(\n filePath: string, lines: string[],\n rootNode: any, langConfig: LangGrammar, language: string,\n ): CodeChunk[] {\n const chunks: CodeChunk[] = [];\n const seen = new Set<string>();\n\n for (let i = 0; i < rootNode.childCount; i++) {\n const child = rootNode.child(i);\n this._processNode(filePath, lines, child, langConfig, language, chunks, seen);\n }\n\n return chunks;\n }\n\n /** Classify and process a single AST node. */\n private _processNode(\n filePath: string, lines: string[], node: any,\n langConfig: LangGrammar, language: string,\n chunks: CodeChunk[], seen: Set<string>,\n ): void {\n const type = node.type;\n\n // Handle export_statement: process what it wraps\n if (type === 'export_statement') {\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n const category = this._categorize(child.type, langConfig);\n if (category) {\n this._processDeclaration(filePath, lines, node, child, category, langConfig, language, chunks, seen);\n return;\n }\n }\n // Export with no recognized declaration — chunk the whole thing if big enough\n const nodeLines = node.endPosition.row - node.startPosition.row + 1;\n if (nodeLines >= this.MIN) {\n this._addChunk(filePath, lines, node, 'function', this._extractName(node), language, chunks, seen);\n }\n return;\n }\n\n // Python decorated definitions (@decorator + class/def)\n if (type === 'decorated_definition') {\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i);\n const category = this._categorize(child.type, langConfig);\n if (category) {\n this._processDeclaration(filePath, lines, node, child, category, langConfig, language, chunks, seen);\n return;\n }\n }\n }\n\n // Direct match\n const category = this._categorize(type, langConfig);\n if (category) {\n this._processDeclaration(filePath, lines, node, node, category, langConfig, language, chunks, seen);\n }\n }\n\n /** Check which category a node type belongs to. */\n private _categorize(nodeType: string, langConfig: LangGrammar): string | null {\n for (const [category, types] of Object.entries(langConfig.nodeTypes)) {\n if (types && types.includes(nodeType)) return category;\n }\n return null;\n }\n\n /** Process a matched declaration: class → split by methods, else → chunk directly. */\n private _processDeclaration(\n filePath: string, lines: string[],\n outerNode: any, innerNode: any, category: string,\n langConfig: LangGrammar, language: string,\n chunks: CodeChunk[], seen: Set<string>,\n ): void {\n const nodeLines = outerNode.endPosition.row - outerNode.startPosition.row + 1;\n const name = this._extractName(innerNode);\n const chunkType = this._toChunkType(category);\n\n // Large class → split into methods\n if ((category === 'class' || category === 'struct' || category === 'impl') && nodeLines > this.MAX) {\n this._splitClassIntoMethods(filePath, lines, outerNode, innerNode, name, langConfig, language, chunks, seen);\n return;\n }\n\n // Large non-class → split with overlap\n if (nodeLines > this.MAX) {\n chunks.push(...this._splitLargeBlock(filePath, lines,\n outerNode.startPosition.row, outerNode.endPosition.row,\n name, chunkType, language));\n return;\n }\n\n // Normal-sized node\n if (nodeLines >= this.MIN) {\n this._addChunk(filePath, lines, outerNode, chunkType, name, language, chunks, seen);\n }\n }\n\n /** Split a large class into individual method chunks. */\n private _splitClassIntoMethods(\n filePath: string, lines: string[],\n outerNode: any, classNode: any, className: string,\n langConfig: LangGrammar, language: string,\n chunks: CodeChunk[], seen: Set<string>,\n ): void {\n // Find class body\n const body = this._findClassBody(classNode);\n if (!body) {\n chunks.push(...this._splitLargeBlock(filePath, lines,\n outerNode.startPosition.row, outerNode.endPosition.row,\n className, 'class', language));\n return;\n }\n\n // Get method node types\n const methodTypes = new Set([\n ...(langConfig.nodeTypes.function || []),\n ...(langConfig.nodeTypes.method || []),\n ]);\n\n let methodsFound = false;\n for (let i = 0; i < body.childCount; i++) {\n const child = body.child(i);\n let methodNode = child;\n\n // Decorated methods\n if (child.type === 'decorated_definition') {\n for (let j = 0; j < child.childCount; j++) {\n if (methodTypes.has(child.child(j).type)) {\n methodNode = child.child(j);\n break;\n }\n }\n }\n\n if (methodTypes.has(methodNode.type) || methodTypes.has(child.type)) {\n const methodName = this._extractName(methodNode);\n const nodeToChunk = child.type === 'decorated_definition' ? child : methodNode;\n const methodLineCount = nodeToChunk.endPosition.row - nodeToChunk.startPosition.row + 1;\n\n if (methodLineCount >= this.MIN) {\n methodsFound = true;\n const fullName = `${className}.${methodName}`;\n\n if (methodLineCount > this.MAX) {\n chunks.push(...this._splitLargeBlock(filePath, lines,\n nodeToChunk.startPosition.row, nodeToChunk.endPosition.row,\n fullName, 'method', language));\n } else {\n this._addChunk(filePath, lines, nodeToChunk, 'method', fullName, language, chunks, seen);\n }\n }\n }\n }\n\n // Fallback: no methods found → split the whole class\n if (!methodsFound) {\n chunks.push(...this._splitLargeBlock(filePath, lines,\n outerNode.startPosition.row, outerNode.endPosition.row,\n className, 'class', language));\n }\n }\n\n /** Find the class body node. */\n private _findClassBody(classNode: any): any | null {\n const bodyTypes = ['class_body', 'block', 'declaration_list', 'body'];\n for (let i = 0; i < classNode.childCount; i++) {\n const child = classNode.child(i);\n if (bodyTypes.includes(child.type)) return child;\n }\n return null;\n }\n\n /** Extract name from an AST node. */\n private _extractName(node: any): string {\n // Try childForFieldName('name')\n if (typeof node.childForFieldName === 'function') {\n const nameNode = node.childForFieldName('name');\n if (nameNode) return nameNode.text;\n }\n // Try identifier children\n for (let i = 0; i < node.namedChildCount; i++) {\n const child = node.namedChild(i);\n if (['identifier', 'type_identifier', 'property_identifier'].includes(child.type)) {\n return child.text;\n }\n }\n // For variable declarations, dig into declarators\n if (node.type === 'lexical_declaration' || node.type === 'variable_declaration') {\n for (let i = 0; i < node.namedChildCount; i++) {\n const child = node.namedChild(i);\n if (child.type === 'variable_declarator') {\n const nameNode = child.childForFieldName('name');\n if (nameNode) return nameNode.text;\n }\n }\n }\n return 'anonymous';\n }\n\n /** Map category to chunk type. */\n private _toChunkType(category: string): string {\n if (category === 'class' || category === 'struct' || category === 'impl') return 'class';\n if (category === 'interface') return 'interface';\n if (category === 'variable') return 'function';\n return category;\n }\n\n /** Add a node as a chunk, avoiding duplicates. */\n private _addChunk(\n filePath: string, lines: string[], node: any,\n chunkType: string, name: string, language: string,\n chunks: CodeChunk[], seen: Set<string>,\n ): void {\n const start = node.startPosition.row;\n const end = node.endPosition.row;\n const key = `${start}-${end}`;\n if (seen.has(key)) return;\n seen.add(key);\n\n const content = lines.slice(start, end + 1).join('\\n').trim();\n if (content.length <= 20) return;\n\n chunks.push({\n filePath,\n chunkType,\n name,\n startLine: start + 1,\n endLine: end + 1,\n content,\n language,\n });\n }\n\n // ── Fallback: Generic sliding window ────────────\n\n private _chunkGeneric(filePath: string, lines: string[], language: string): CodeChunk[] {\n const chunks: CodeChunk[] = [];\n const step = Math.max(this.MAX - this.OVERLAP, 1);\n\n for (let s = 0; s < lines.length; s += step) {\n const e = Math.min(s + this.MAX, lines.length);\n const content = lines.slice(s, e).join('\\n').trim();\n if (content.length > 20) {\n chunks.push({\n filePath,\n chunkType: 'block',\n startLine: s + 1,\n endLine: e,\n content,\n language,\n });\n }\n if (e >= lines.length) break;\n }\n\n return chunks;\n }\n\n /** Split a large block into overlapping sub-chunks. */\n private _splitLargeBlock(\n filePath: string, lines: string[],\n start: number, end: number,\n name: string, type: string, language: string,\n ): CodeChunk[] {\n const chunks: CodeChunk[] = [];\n const step = Math.max(this.MAX - this.OVERLAP, 1);\n let part = 1;\n\n for (let s = start; s <= end; s += step) {\n const e = Math.min(s + this.MAX, end + 1);\n const content = lines.slice(s, e).join('\\n').trim();\n if (content.length > 20) {\n chunks.push({\n filePath,\n chunkType: type,\n name: `${name} (part ${part++})`,\n startLine: s + 1,\n endLine: e,\n content,\n language,\n });\n }\n if (e > end) break;\n }\n\n return chunks;\n }\n}\n","/**\n * BrainBank — Tree-Sitter Grammar Registry\n *\n * Maps language names to their tree-sitter grammar packages\n * and the AST node types that represent semantic blocks.\n */\n\nimport { createRequire } from 'node:module';\n\nconst require = createRequire(import.meta.url);\n\n// ── Types ───────────────────────────────────────────\n\nexport interface LangGrammar {\n grammar: any;\n nodeTypes: {\n class?: string[];\n function?: string[];\n interface?: string[];\n variable?: string[];\n method?: string[];\n struct?: string[];\n impl?: string[];\n };\n}\n\n// ── Loader ──────────────────────────────────────────\n\n/** Try to require a grammar, return null if not installed. */\nfunction tryGrammar(pkg: string, nodeTypes: LangGrammar['nodeTypes'], accessor?: string): () => LangGrammar | null {\n return () => {\n try {\n const mod = require(pkg);\n return { grammar: accessor ? mod[accessor] : mod, nodeTypes };\n } catch { return null; }\n };\n}\n\n// ── Grammar Table ───────────────────────────────────\n\nexport const GRAMMARS: Record<string, () => LangGrammar | null> = {\n // ── Web ──────────────────────────────────────────\n typescript: tryGrammar('tree-sitter-typescript', {\n class: ['class_declaration'],\n interface: ['interface_declaration', 'type_alias_declaration'],\n function: ['function_declaration', 'method_definition'],\n variable: ['lexical_declaration'],\n }, 'typescript'),\n javascript: tryGrammar('tree-sitter-javascript', {\n class: ['class_declaration'],\n function: ['function_declaration', 'method_definition'],\n variable: ['lexical_declaration'],\n }),\n html: tryGrammar('tree-sitter-html', {}),\n css: tryGrammar('tree-sitter-css', {}),\n\n // ── Systems ──────────────────────────────────────\n go: tryGrammar('tree-sitter-go', {\n function: ['function_declaration', 'method_declaration'],\n struct: ['type_declaration'],\n }),\n rust: tryGrammar('tree-sitter-rust', {\n function: ['function_item'],\n struct: ['struct_item'],\n impl: ['impl_item'],\n }),\n c: tryGrammar('tree-sitter-c', {\n function: ['function_definition'],\n struct: ['struct_specifier'],\n }),\n cpp: tryGrammar('tree-sitter-cpp', {\n class: ['class_specifier'],\n function: ['function_definition'],\n }),\n swift: tryGrammar('tree-sitter-swift', {\n class: ['class_declaration'],\n function: ['function_declaration'],\n struct: ['struct_declaration'],\n }),\n\n // ── JVM ──────────────────────────────────────────\n java: tryGrammar('tree-sitter-java', {\n class: ['class_declaration'],\n interface: ['interface_declaration'],\n method: ['method_declaration'],\n }),\n kotlin: tryGrammar('tree-sitter-kotlin', {\n class: ['class_declaration'],\n function: ['function_declaration'],\n }),\n scala: tryGrammar('tree-sitter-scala', {\n class: ['class_definition'],\n function: ['function_definition'],\n }),\n\n // ── Scripting ────────────────────────────────────\n python: tryGrammar('tree-sitter-python', {\n class: ['class_definition'],\n function: ['function_definition'],\n }),\n ruby: tryGrammar('tree-sitter-ruby', {\n class: ['class'],\n method: ['method', 'singleton_method'],\n }),\n php: tryGrammar('tree-sitter-php', {\n class: ['class_declaration'],\n function: ['function_definition', 'method_declaration'],\n }, 'php'),\n lua: tryGrammar('tree-sitter-lua', {\n function: ['function_declaration'],\n }),\n bash: tryGrammar('tree-sitter-bash', {\n function: ['function_definition'],\n }),\n elixir: tryGrammar('tree-sitter-elixir', {\n function: ['call'], // defmodule, def, defp\n }),\n\n // ── .NET ─────────────────────────────────────────\n c_sharp: tryGrammar('tree-sitter-c-sharp', {\n class: ['class_declaration'],\n interface: ['interface_declaration'],\n method: ['method_declaration'],\n }),\n};\n","/**\n * BrainBank — Language Registry\n * \n * Supported file extensions, language mappings, and ignore lists.\n * Controls which files get indexed and how they're chunked.\n */\n\n// ── Supported Extensions ────────────────────────────\n\nexport const SUPPORTED_EXTENSIONS: Record<string, string> = {\n // TypeScript / JavaScript\n '.ts': 'typescript',\n '.tsx': 'typescript',\n '.js': 'javascript',\n '.jsx': 'javascript',\n '.mjs': 'javascript',\n '.cjs': 'javascript',\n\n // Systems\n '.go': 'go',\n '.rs': 'rust',\n '.cpp': 'cpp',\n '.cc': 'cpp',\n '.c': 'c',\n '.h': 'c',\n '.hpp': 'cpp',\n\n // JVM\n '.java': 'java',\n '.kt': 'kotlin',\n '.scala': 'scala',\n\n // Scripting\n '.py': 'python',\n '.rb': 'ruby',\n '.php': 'php',\n '.lua': 'lua',\n '.sh': 'bash',\n '.bash': 'bash',\n '.zsh': 'bash',\n\n // Web\n '.html': 'html',\n '.css': 'css',\n '.scss': 'scss',\n '.less': 'less',\n '.svelte': 'svelte',\n '.vue': 'vue',\n\n // Data / Config\n '.json': 'json',\n '.yaml': 'yaml',\n '.yml': 'yaml',\n '.toml': 'toml',\n '.xml': 'xml',\n '.graphql': 'graphql',\n '.gql': 'graphql',\n\n // Docs\n '.md': 'markdown',\n '.mdx': 'markdown',\n\n // Database\n '.sql': 'sql',\n '.prisma': 'prisma',\n\n // Other\n '.swift': 'swift',\n '.dart': 'dart',\n '.r': 'r',\n '.ex': 'elixir',\n '.exs': 'elixir',\n '.erl': 'erlang',\n '.zig': 'zig',\n};\n\n// ── Ignore Directories ──────────────────────────────\n\nexport const IGNORE_DIRS = new Set([\n // Package managers\n 'node_modules',\n 'bower_components',\n '.pnpm',\n\n // Build output\n 'dist',\n 'build',\n 'out',\n '.next',\n '.nuxt',\n '.output',\n '.svelte-kit',\n\n // Version control\n '.git',\n '.hg',\n '.svn',\n\n // IDE / Editor\n '.idea',\n '.vscode',\n\n // Runtime / Cache\n '__pycache__',\n '.pytest_cache',\n 'venv',\n '.venv',\n '.env',\n '.tox',\n\n // Coverage / Test artifacts\n 'coverage',\n '.nyc_output',\n 'htmlcov',\n\n // Compiled\n 'target', // Rust, Java\n '.cargo',\n 'vendor', // Go, PHP\n\n // AI / Model cache\n '.model-cache',\n '.brainbank',\n\n // OS\n '.DS_Store',\n]);\n\n// ── Ignore Files ────────────────────────────────────\n\nexport const IGNORE_FILES = new Set([\n 'package-lock.json',\n 'yarn.lock',\n 'pnpm-lock.yaml',\n 'bun.lockb',\n 'Cargo.lock',\n 'Gemfile.lock',\n 'poetry.lock',\n 'composer.lock',\n 'go.sum',\n]);\n\n// ── Helpers ─────────────────────────────────────────\n\nimport path from 'node:path';\n\n/** Check if a file extension is supported for indexing. */\nexport function isSupported(filePath: string): boolean {\n const ext = path.extname(filePath).toLowerCase();\n return ext in SUPPORTED_EXTENSIONS;\n}\n\n/** Get the language name for a file. Returns undefined if not supported. */\nexport function getLanguage(filePath: string): string | undefined {\n const ext = path.extname(filePath).toLowerCase();\n return SUPPORTED_EXTENSIONS[ext];\n}\n\n/** Check if a directory name should be ignored. */\nexport function isIgnoredDir(dirName: string): boolean {\n return IGNORE_DIRS.has(dirName);\n}\n\n/** Check if a filename should be ignored. */\nexport function isIgnoredFile(fileName: string): boolean {\n return IGNORE_FILES.has(fileName);\n}\n","/**\n * BrainBank — Code Module\n * \n * Language-aware code indexing for 30+ languages.\n * \n * import { BrainBank } from 'brainbank';\n * import { code } from 'brainbank/code';\n * \n * const brain = new BrainBank().use(code({ repoPath: '.' }));\n * \n * // Multi-repo: namespace to avoid key collisions\n * brain\n * .use(code({ repoPath: './frontend', name: 'code:frontend' }))\n * .use(code({ repoPath: './backend', name: 'code:backend' }));\n */\n\nimport type { Indexer, IndexerContext } from '../base.ts';\nimport type { HNSWIndex } from '../../providers/vector/hnsw.ts';\nimport { CodeIndexer } from './code-indexer.ts';\nimport type { IndexResult, ProgressCallback } from '../../types.ts';\n\nexport interface CodePluginOptions {\n /** Repository path to index. Default: '.' */\n repoPath?: string;\n /** Maximum file size in bytes. Default: from config */\n maxFileSize?: number;\n /** Custom indexer name for multi-repo (e.g. 'code:frontend'). Default: 'code' */\n name?: string;\n}\n\nclass CodePlugin implements Indexer {\n readonly name: string;\n hnsw!: HNSWIndex;\n indexer!: CodeIndexer;\n vecCache = new Map<number, Float32Array>();\n\n constructor(private opts: CodePluginOptions = {}) {\n this.name = opts.name ?? 'code';\n }\n\n async initialize(ctx: IndexerContext): Promise<void> {\n // Use shared HNSW so all code indexers (code, code:frontend, etc.) share one index\n const shared = await ctx.getOrCreateSharedHnsw('code');\n this.hnsw = shared.hnsw;\n this.vecCache = shared.vecCache;\n\n // Only load vectors once (first code indexer to initialize)\n if (shared.isNew) {\n ctx.loadVectors('code_vectors', 'chunk_id', this.hnsw, this.vecCache);\n }\n\n const repoPath = this.opts.repoPath ?? ctx.config.repoPath;\n this.indexer = new CodeIndexer(repoPath, {\n db: ctx.db,\n hnsw: this.hnsw,\n vectorCache: this.vecCache,\n embedding: ctx.embedding,\n }, this.opts.maxFileSize ?? ctx.config.maxFileSize);\n }\n\n async index(options: {\n forceReindex?: boolean;\n onProgress?: ProgressCallback;\n } = {}): Promise<IndexResult> {\n return this.indexer.index(options);\n }\n\n stats(): Record<string, any> {\n return { hnswSize: this.hnsw.size };\n }\n}\n\n/** Create a code indexing plugin. */\nexport function code(opts?: CodePluginOptions): Indexer {\n return new CodePlugin(opts);\n}\n"],"mappings":"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","names":["path","createRequire","require","require","createRequire","category","path"]}
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  cosineSimilarity
3
- } from "./chunk-2P3EGY6S.js";
3
+ } from "./chunk-QNHBCOKB.js";
4
4
  import {
5
5
  __name
6
6
  } from "./chunk-7QVYU63E.js";
7
7
 
8
- // src/memory/pattern-store.ts
8
+ // src/memory/store.ts
9
9
  var PatternStore = class {
10
10
  static {
11
11
  __name(this, "PatternStore");
@@ -168,4 +168,4 @@ export {
168
168
  PatternStore,
169
169
  Consolidator
170
170
  };
171
- //# sourceMappingURL=chunk-Z5SU54HP.js.map
171
+ //# sourceMappingURL=chunk-X6645UVR.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/memory/store.ts","../src/memory/consolidator.ts"],"sourcesContent":["/**\n * BrainBank — Pattern Store (Agent Memory)\n * \n * Stores what the agent learned from past tasks.\n * Each pattern records task, approach, and success rate.\n * Searchable by semantic similarity via HNSW.\n */\n\nimport type { Database } from '../db/database.ts';\nimport type { EmbeddingProvider, LearningPattern } from '../types.ts';\nimport type { HNSWIndex } from '../providers/vector/hnsw.ts';\n\nexport interface PatternStoreDeps {\n db: Database;\n hnsw: HNSWIndex;\n vectorCache: Map<number, Float32Array>;\n embedding: EmbeddingProvider;\n}\n\nexport class PatternStore {\n private _deps: PatternStoreDeps;\n\n constructor(deps: PatternStoreDeps) {\n this._deps = deps;\n }\n\n /**\n * Store a learned pattern.\n * Returns the pattern ID.\n */\n async learn(pattern: LearningPattern): Promise<number> {\n const result = this._deps.db.prepare(`\n INSERT INTO memory_patterns (task_type, task, approach, outcome, success_rate, critique, tokens_used, latency_ms)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?)\n `).run(\n pattern.taskType,\n pattern.task,\n pattern.approach,\n pattern.outcome ?? null,\n pattern.successRate,\n pattern.critique ?? null,\n pattern.tokensUsed ?? null,\n pattern.latencyMs ?? null,\n );\n\n const id = Number(result.lastInsertRowid);\n\n // Embed and store vector\n const text = `${pattern.taskType} ${pattern.task} ${pattern.approach}`;\n const vec = await this._deps.embedding.embed(text);\n\n this._deps.db.prepare(\n 'INSERT INTO memory_vectors (pattern_id, embedding) VALUES (?, ?)'\n ).run(id, Buffer.from(vec.buffer));\n\n this._deps.hnsw.add(vec, id);\n this._deps.vectorCache.set(id, vec);\n\n return id;\n }\n\n /**\n * Search for similar successful patterns.\n * Filters by minimum success rate.\n */\n async search(query: string, k: number = 4, minSuccess: number = 0.5): Promise<(LearningPattern & { score: number })[]> {\n if (this._deps.hnsw.size === 0) return [];\n\n const vec = await this._deps.embedding.embed(query);\n const hits = this._deps.hnsw.search(vec, k * 2);\n\n if (hits.length === 0) return [];\n\n const ids = hits.map(h => h.id);\n const scoreMap = new Map(hits.map(h => [h.id, h.score]));\n\n const placeholders = ids.map(() => '?').join(',');\n const rows = this._deps.db.prepare(\n `SELECT * FROM memory_patterns WHERE id IN (${placeholders}) AND success_rate >= ?`\n ).all(...ids, minSuccess) as any[];\n\n return rows\n .map(r => ({\n id: r.id,\n taskType: r.task_type,\n task: r.task,\n approach: r.approach,\n outcome: r.outcome,\n successRate: r.success_rate,\n critique: r.critique,\n tokensUsed: r.tokens_used,\n latencyMs: r.latency_ms,\n score: scoreMap.get(r.id) ?? 0,\n }))\n .sort((a, b) => b.score - a.score)\n .slice(0, k);\n }\n\n /**\n * Get all patterns for a specific task type.\n */\n getByTaskType(taskType: string, limit: number = 20): LearningPattern[] {\n const rows = this._deps.db.prepare(\n `SELECT * FROM memory_patterns WHERE task_type = ? ORDER BY success_rate DESC LIMIT ?`\n ).all(taskType, limit) as any[];\n\n return rows.map(r => ({\n id: r.id,\n taskType: r.task_type,\n task: r.task,\n approach: r.approach,\n outcome: r.outcome,\n successRate: r.success_rate,\n critique: r.critique,\n tokensUsed: r.tokens_used,\n latencyMs: r.latency_ms,\n }));\n }\n\n /** Total number of stored patterns. */\n get count(): number {\n return (this._deps.db.prepare('SELECT COUNT(*) as c FROM memory_patterns').get() as any).c;\n }\n}\n","/**\n * BrainBank — Consolidator\n * \n * Maintenance operations for the agent memory:\n * - prune: remove old failed patterns\n * - dedup: merge near-duplicate patterns (cosine > 0.95)\n * - consolidate: run both\n */\n\nimport type { Database } from '../db/database.ts';\nimport { cosineSimilarity } from '../lib/math.ts';\n\nexport class Consolidator {\n constructor(\n private _db: Database,\n private _vectorCache: Map<number, Float32Array>,\n ) {}\n\n /**\n * Remove old failed patterns.\n * Criteria: success_rate < 0.3 AND created > 90 days ago.\n */\n prune(maxAgeDays: number = 90, minSuccess: number = 0.3): number {\n const cutoff = Math.floor(Date.now() / 1000) - maxAgeDays * 86400;\n const result = this._db.prepare(\n 'DELETE FROM memory_patterns WHERE success_rate < ? AND created_at < ?'\n ).run(minSuccess, cutoff);\n return result.changes;\n }\n\n /**\n * Merge near-duplicate patterns.\n * Keeps the one with higher success_rate.\n * Threshold: cosine similarity > 0.95.\n */\n dedup(threshold: number = 0.95): number {\n const entries = Array.from(this._vectorCache.entries());\n const toDelete = new Set<number>();\n\n for (let i = 0; i < entries.length; i++) {\n if (toDelete.has(entries[i][0])) continue;\n\n for (let j = i + 1; j < entries.length; j++) {\n if (toDelete.has(entries[j][0])) continue;\n\n const sim = cosineSimilarity(entries[i][1], entries[j][1]);\n if (sim > threshold) {\n // Keep the one with higher success rate\n const pi = this._db.prepare(\n 'SELECT success_rate FROM memory_patterns WHERE id = ?'\n ).get(entries[i][0]) as any;\n const pj = this._db.prepare(\n 'SELECT success_rate FROM memory_patterns WHERE id = ?'\n ).get(entries[j][0]) as any;\n\n if (pi && pj) {\n const deleteId = pi.success_rate >= pj.success_rate\n ? entries[j][0]\n : entries[i][0];\n toDelete.add(deleteId);\n }\n }\n }\n }\n\n if (toDelete.size > 0) {\n const ids = Array.from(toDelete);\n const placeholders = ids.map(() => '?').join(',');\n this._db.prepare(\n `DELETE FROM memory_patterns WHERE id IN (${placeholders})`\n ).run(...ids);\n\n // Clean vector cache\n for (const id of ids) {\n this._vectorCache.delete(id);\n }\n }\n\n return toDelete.size;\n }\n\n /**\n * Run full consolidation: prune + dedup.\n */\n consolidate(): { pruned: number; deduped: number } {\n const pruned = this.prune();\n const deduped = this.dedup();\n return { pruned, deduped };\n }\n}\n"],"mappings":"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","names":[]}
package/dist/cli.js CHANGED
@@ -1,25 +1,23 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  BrainBank
4
- } from "./chunk-YGSEUWLV.js";
4
+ } from "./chunk-6MFTQV3O.js";
5
5
  import {
6
6
  code
7
- } from "./chunk-EDKSKLX4.js";
7
+ } from "./chunk-WR4WXKJT.js";
8
8
  import {
9
9
  git
10
- } from "./chunk-N6ZMBFDE.js";
10
+ } from "./chunk-7JCEW7LT.js";
11
11
  import {
12
12
  docs
13
- } from "./chunk-GOUBW7UA.js";
14
- import "./chunk-4ZKBQ33J.js";
15
- import "./chunk-2P3EGY6S.js";
13
+ } from "./chunk-F6SJ3U4H.js";
14
+ import "./chunk-V4UJKXPK.js";
15
+ import "./chunk-QNHBCOKB.js";
16
16
  import {
17
17
  __name
18
18
  } from "./chunk-7QVYU63E.js";
19
19
 
20
- // src/integrations/cli.ts
21
- import * as path from "path";
22
- import * as fs from "fs";
20
+ // src/cli/utils.ts
23
21
  var c = {
24
22
  green: /* @__PURE__ */ __name((s) => `\x1B[32m${s}\x1B[0m`, "green"),
25
23
  red: /* @__PURE__ */ __name((s) => `\x1B[31m${s}\x1B[0m`, "red"),
@@ -30,8 +28,6 @@ var c = {
30
28
  magenta: /* @__PURE__ */ __name((s) => `\x1B[35m${s}\x1B[0m`, "magenta")
31
29
  };
32
30
  var args = process.argv.slice(2);
33
- var command = args[0];
34
- var subcommand = args[1];
35
31
  function getFlag(name) {
36
32
  const idx = args.indexOf(`--${name}`);
37
33
  return idx >= 0 ? args[idx + 1] : void 0;
@@ -41,11 +37,46 @@ function hasFlag(name) {
41
37
  return args.includes(`--${name}`);
42
38
  }
43
39
  __name(hasFlag, "hasFlag");
44
- var CONFIG_NAMES = [
45
- "config.ts",
46
- "config.js",
47
- "config.mjs"
48
- ];
40
+ function printResults(results) {
41
+ if (results.length === 0) {
42
+ console.log(c.yellow(" No results found."));
43
+ return;
44
+ }
45
+ for (const r of results) {
46
+ const score = Math.round(r.score * 100);
47
+ if (r.type === "code") {
48
+ const m = r.metadata;
49
+ console.log(
50
+ `${c.green(`[CODE ${score}%]`)} ${c.bold(r.filePath)} \u2014 ${m.name || m.chunkType} ${c.dim(`L${m.startLine}-${m.endLine}`)}`
51
+ );
52
+ console.log(c.dim(r.content.split("\n").slice(0, 5).join("\n")));
53
+ console.log("");
54
+ } else if (r.type === "commit") {
55
+ const m = r.metadata;
56
+ console.log(
57
+ `${c.cyan(`[COMMIT ${score}%]`)} ${c.bold(m.shortHash)} ${r.content} ${c.dim(`(${m.author})`)}`
58
+ );
59
+ if (m.files?.length) console.log(c.dim(` Files: ${m.files.slice(0, 4).join(", ")}`));
60
+ console.log("");
61
+ } else if (r.type === "document") {
62
+ const ctx = r.context ? ` \u2014 ${c.dim(r.context)}` : "";
63
+ console.log(
64
+ `${c.magenta(`[DOC ${score}%]`)} ${c.bold(r.filePath)} [${r.metadata.collection}]${ctx}`
65
+ );
66
+ console.log(c.dim(r.content.split("\n").slice(0, 4).join("\n")));
67
+ console.log("");
68
+ }
69
+ }
70
+ }
71
+ __name(printResults, "printResults");
72
+
73
+ // src/cli/commands/index-cmd.ts
74
+ import * as path2 from "path";
75
+
76
+ // src/cli/factory.ts
77
+ import * as path from "path";
78
+ import * as fs from "fs";
79
+ var CONFIG_NAMES = ["config.ts", "config.js", "config.mjs"];
49
80
  var INDEXER_EXTENSIONS = [".ts", ".js", ".mjs"];
50
81
  var _configCache = void 0;
51
82
  var _folderIndexersCache = void 0;
@@ -98,6 +129,17 @@ async function discoverFolderIndexers() {
98
129
  return indexers;
99
130
  }
100
131
  __name(discoverFolderIndexers, "discoverFolderIndexers");
132
+ function detectGitSubdirs(parentPath) {
133
+ try {
134
+ const entries = fs.readdirSync(parentPath, { withFileTypes: true });
135
+ return entries.filter(
136
+ (e) => e.isDirectory() && !e.name.startsWith(".") && !e.name.startsWith("node_modules") && fs.existsSync(path.join(parentPath, e.name, ".git"))
137
+ ).map((e) => ({ name: e.name, path: path.join(parentPath, e.name) }));
138
+ } catch {
139
+ return [];
140
+ }
141
+ }
142
+ __name(detectGitSubdirs, "detectGitSubdirs");
101
143
  async function createBrain(repoPath) {
102
144
  const rp = repoPath ?? getFlag("repo") ?? ".";
103
145
  const config = await loadConfig();
@@ -110,7 +152,7 @@ async function createBrain(repoPath) {
110
152
  }
111
153
  const embeddingEnv = process.env.BRAINBANK_EMBEDDING;
112
154
  if (embeddingEnv === "openai") {
113
- const { OpenAIEmbedding } = await import("./openai-PCTYLOWI.js");
155
+ const { OpenAIEmbedding } = await import("./openai-CYDMYX7X.js");
114
156
  const provider = new OpenAIEmbedding();
115
157
  brainOpts.embeddingProvider = provider;
116
158
  brainOpts.embeddingDims = provider.dims;
@@ -146,27 +188,42 @@ async function createBrain(repoPath) {
146
188
  return brain;
147
189
  }
148
190
  __name(createBrain, "createBrain");
149
- function detectGitSubdirs(parentPath) {
150
- try {
151
- const entries = fs.readdirSync(parentPath, { withFileTypes: true });
152
- return entries.filter(
153
- (e) => e.isDirectory() && !e.name.startsWith(".") && !e.name.startsWith("node_modules") && fs.existsSync(path.join(parentPath, e.name, ".git"))
154
- ).map((e) => ({ name: e.name, path: path.join(parentPath, e.name) }));
155
- } catch {
156
- return [];
157
- }
158
- }
159
- __name(detectGitSubdirs, "detectGitSubdirs");
191
+
192
+ // src/cli/commands/index-cmd.ts
160
193
  async function cmdIndex() {
161
194
  const repoPath = args[1] || ".";
162
195
  const force = hasFlag("force");
163
196
  const depth = parseInt(getFlag("depth") || "500", 10);
197
+ const onlyRaw = getFlag("only");
198
+ const docsPath = getFlag("docs");
199
+ const modules = onlyRaw ? onlyRaw.split(",").map((s) => s.trim()) : void 0;
200
+ if (docsPath && modules && !modules.includes("docs")) {
201
+ modules.push("docs");
202
+ }
164
203
  console.log(c.bold("\n\u2501\u2501\u2501 BrainBank Index \u2501\u2501\u2501"));
165
204
  console.log(c.dim(` Repo: ${repoPath}`));
166
205
  console.log(c.dim(` Force: ${force}`));
167
206
  console.log(c.dim(` Git depth: ${depth}`));
207
+ if (modules) console.log(c.dim(` Modules: ${modules.join(", ")}`));
208
+ if (docsPath) console.log(c.dim(` Docs path: ${docsPath}`));
168
209
  const brain = await createBrain(repoPath);
210
+ if (docsPath) {
211
+ const absDocsPath = path2.resolve(docsPath);
212
+ const collName = path2.basename(absDocsPath);
213
+ try {
214
+ await brain.addCollection({
215
+ name: collName,
216
+ path: absDocsPath,
217
+ pattern: "**/*.md",
218
+ ignore: ["deprecated/**", "node_modules/**"]
219
+ });
220
+ console.log(c.dim(` Registered docs collection: ${collName}`));
221
+ } catch {
222
+ console.log(c.yellow(` Warning: docs module not loaded, skipping --docs`));
223
+ }
224
+ }
169
225
  const result = await brain.index({
226
+ modules,
170
227
  forceReindex: force,
171
228
  gitDepth: depth,
172
229
  onProgress: /* @__PURE__ */ __name((stage, msg) => {
@@ -180,36 +237,44 @@ async function cmdIndex() {
180
237
  if (result.git) {
181
238
  console.log(` ${c.green("Git")}: ${result.git.indexed} indexed, ${result.git.skipped} skipped`);
182
239
  }
240
+ if (result.docs) {
241
+ for (const [name, stat] of Object.entries(result.docs)) {
242
+ console.log(` ${c.green("Docs")}: [${name}] ${stat.indexed} indexed, ${stat.skipped} skipped, ${stat.chunks} chunks`);
243
+ }
244
+ }
183
245
  const stats = brain.stats();
184
246
  console.log(`
185
247
  ${c.bold("Totals")}:`);
186
248
  if (stats.code) console.log(` Code chunks: ${stats.code.chunks}`);
187
249
  if (stats.git) console.log(` Git commits: ${stats.git.commits}`);
188
250
  if (stats.git) console.log(` Co-edit pairs: ${stats.git.coEdits}`);
251
+ if (stats.documents) console.log(` Documents: ${stats.documents.documents}`);
189
252
  brain.close();
190
253
  }
191
254
  __name(cmdIndex, "cmdIndex");
255
+
256
+ // src/cli/commands/collection.ts
192
257
  async function cmdCollection() {
193
258
  const sub = args[1];
194
259
  if (sub === "add") {
195
- const path2 = args[2];
260
+ const path3 = args[2];
196
261
  const name = getFlag("name");
197
262
  const pattern = getFlag("pattern") ?? "**/*.md";
198
263
  const context = getFlag("context");
199
264
  const ignoreRaw = getFlag("ignore");
200
- if (!path2 || !name) {
265
+ if (!path3 || !name) {
201
266
  console.log(c.red('Usage: brainbank collection add <path> --name <name> [--pattern "**/*.md"] [--ignore "glob"] [--context "description"]'));
202
267
  process.exit(1);
203
268
  }
204
269
  const brain = await createBrain();
205
270
  await brain.addCollection({
206
271
  name,
207
- path: path2,
272
+ path: path3,
208
273
  pattern,
209
274
  ignore: ignoreRaw ? ignoreRaw.split(",") : [],
210
275
  context: context ?? void 0
211
276
  });
212
- console.log(c.green(`\u2713 Collection '${name}' added: ${path2} (${pattern})`));
277
+ console.log(c.green(`\u2713 Collection '${name}' added: ${path3} (${pattern})`));
213
278
  if (context) console.log(c.dim(` Context: ${context}`));
214
279
  brain.close();
215
280
  return;
@@ -247,6 +312,8 @@ async function cmdCollection() {
247
312
  process.exit(1);
248
313
  }
249
314
  __name(cmdCollection, "cmdCollection");
315
+
316
+ // src/cli/commands/kv.ts
250
317
  async function cmdKv() {
251
318
  const sub = args[1];
252
319
  if (sub === "add") {
@@ -367,6 +434,8 @@ async function cmdKv() {
367
434
  process.exit(1);
368
435
  }
369
436
  __name(cmdKv, "cmdKv");
437
+
438
+ // src/cli/commands/docs.ts
370
439
  async function cmdDocs() {
371
440
  const collection = getFlag("collection");
372
441
  const brain = await createBrain();
@@ -413,51 +482,8 @@ async function cmdDocSearch() {
413
482
  brain.close();
414
483
  }
415
484
  __name(cmdDocSearch, "cmdDocSearch");
416
- async function cmdContext() {
417
- const sub = args[1];
418
- if (sub === "add") {
419
- const collection = args[2];
420
- const path2 = args[3];
421
- const desc = args.slice(4).join(" ");
422
- if (!collection || !path2 || !desc) {
423
- console.log(c.red("Usage: brainbank context add <collection> <path> <description>"));
424
- process.exit(1);
425
- }
426
- const brain2 = await createBrain();
427
- await brain2.initialize();
428
- brain2.addContext(collection, path2, desc);
429
- console.log(c.green(`\u2713 Context added: ${collection}:${path2} \u2192 "${desc}"`));
430
- brain2.close();
431
- return;
432
- }
433
- if (sub === "list") {
434
- const brain2 = await createBrain();
435
- await brain2.initialize();
436
- const contexts = brain2.listContexts();
437
- if (contexts.length === 0) {
438
- console.log(c.yellow(" No contexts configured."));
439
- } else {
440
- console.log(c.bold("\n\u2501\u2501\u2501 Contexts \u2501\u2501\u2501\n"));
441
- for (const ctx of contexts) {
442
- console.log(` ${c.cyan(ctx.collection)}:${ctx.path} \u2192 ${c.dim(ctx.context)}`);
443
- }
444
- }
445
- brain2.close();
446
- return;
447
- }
448
- const task = args.slice(1).join(" ");
449
- if (!task) {
450
- console.log(c.red("Usage: brainbank context <task description>"));
451
- console.log(c.dim(" brainbank context add <collection> <path> <description>"));
452
- console.log(c.dim(" brainbank context list"));
453
- process.exit(1);
454
- }
455
- const brain = await createBrain();
456
- const context = await brain.getContext(task);
457
- console.log(context);
458
- brain.close();
459
- }
460
- __name(cmdContext, "cmdContext");
485
+
486
+ // src/cli/commands/search.ts
461
487
  async function cmdSearch() {
462
488
  const query = args.slice(1).join(" ");
463
489
  if (!query) {
@@ -506,34 +532,55 @@ async function cmdKeywordSearch() {
506
532
  brain.close();
507
533
  }
508
534
  __name(cmdKeywordSearch, "cmdKeywordSearch");
509
- function printResults(results) {
510
- if (results.length === 0) {
511
- console.log(c.yellow(" No results found."));
535
+
536
+ // src/cli/commands/context.ts
537
+ async function cmdContext() {
538
+ const sub = args[1];
539
+ if (sub === "add") {
540
+ const collection = args[2];
541
+ const path3 = args[3];
542
+ const desc = args.slice(4).join(" ");
543
+ if (!collection || !path3 || !desc) {
544
+ console.log(c.red("Usage: brainbank context add <collection> <path> <description>"));
545
+ process.exit(1);
546
+ }
547
+ const brain2 = await createBrain();
548
+ await brain2.initialize();
549
+ brain2.addContext(collection, path3, desc);
550
+ console.log(c.green(`\u2713 Context added: ${collection}:${path3} \u2192 "${desc}"`));
551
+ brain2.close();
512
552
  return;
513
553
  }
514
- for (const r of results) {
515
- const score = Math.round(r.score * 100);
516
- if (r.type === "code") {
517
- const m = r.metadata;
518
- console.log(`${c.green(`[CODE ${score}%]`)} ${c.bold(r.filePath)} \u2014 ${m.name || m.chunkType} ${c.dim(`L${m.startLine}-${m.endLine}`)}`);
519
- const preview = r.content.split("\n").slice(0, 5).join("\n");
520
- console.log(c.dim(preview));
521
- console.log("");
522
- } else if (r.type === "commit") {
523
- const m = r.metadata;
524
- console.log(`${c.cyan(`[COMMIT ${score}%]`)} ${c.bold(m.shortHash)} ${r.content} ${c.dim(`(${m.author})`)}`);
525
- if (m.files?.length) console.log(c.dim(` Files: ${m.files.slice(0, 4).join(", ")}`));
526
- console.log("");
527
- } else if (r.type === "document") {
528
- const ctx = r.context ? ` \u2014 ${c.dim(r.context)}` : "";
529
- console.log(`${c.magenta(`[DOC ${score}%]`)} ${c.bold(r.filePath)} [${r.metadata.collection}]${ctx}`);
530
- const preview = r.content.split("\n").slice(0, 4).join("\n");
531
- console.log(c.dim(preview));
532
- console.log("");
554
+ if (sub === "list") {
555
+ const brain2 = await createBrain();
556
+ await brain2.initialize();
557
+ const contexts = brain2.listContexts();
558
+ if (contexts.length === 0) {
559
+ console.log(c.yellow(" No contexts configured."));
560
+ } else {
561
+ console.log(c.bold("\n\u2501\u2501\u2501 Contexts \u2501\u2501\u2501\n"));
562
+ for (const ctx of contexts) {
563
+ console.log(` ${c.cyan(ctx.collection)}:${ctx.path} \u2192 ${c.dim(ctx.context)}`);
564
+ }
533
565
  }
566
+ brain2.close();
567
+ return;
568
+ }
569
+ const task = args.slice(1).join(" ");
570
+ if (!task) {
571
+ console.log(c.red("Usage: brainbank context <task description>"));
572
+ console.log(c.dim(" brainbank context add <collection> <path> <description>"));
573
+ console.log(c.dim(" brainbank context list"));
574
+ process.exit(1);
534
575
  }
576
+ const brain = await createBrain();
577
+ const context = await brain.getContext(task);
578
+ console.log(context);
579
+ brain.close();
535
580
  }
536
- __name(printResults, "printResults");
581
+ __name(cmdContext, "cmdContext");
582
+
583
+ // src/cli/commands/system.ts
537
584
  async function cmdStats() {
538
585
  const brain = await createBrain();
539
586
  await brain.initialize();
@@ -682,6 +729,9 @@ function showHelp() {
682
729
  console.log(c.dim(" brainbank serve"));
683
730
  }
684
731
  __name(showHelp, "showHelp");
732
+
733
+ // src/cli/index.ts
734
+ var command = args[0];
685
735
  async function main() {
686
736
  switch (command) {
687
737
  case "index":