brainbank 0.9.0 → 0.9.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/brainbank +1 -1
- package/dist/{chunk-Z54MHEYW.js → chunk-6NM6WRDX.js} +6 -1
- package/dist/chunk-6NM6WRDX.js.map +1 -0
- package/dist/cli.js +339 -63
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +0 -6
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/src/cli/commands/help.ts +3 -0
- package/src/cli/commands/index.ts +37 -6
- package/src/cli/commands/mcp-export.ts +311 -0
- package/src/cli/index.ts +7 -0
- package/src/constants.ts +8 -0
- package/dist/chunk-Z54MHEYW.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/config.ts","../src/constants.ts","../src/db/sqlite-adapter.ts","../src/db/tracker.ts","../src/db/metadata.ts","../src/lib/write-lock.ts","../src/lib/math.ts","../src/lib/rerank.ts","../src/lib/rrf.ts","../src/lib/prune.ts","../src/search/bm25-boost.ts","../src/lib/logger.ts","../src/search/context-builder.ts","../src/search/keyword/composite-bm25-search.ts","../src/search/vector/composite-vector-search.ts","../src/providers/vector/hnsw-index.ts","../src/lib/fts.ts","../src/services/collection.ts","../src/services/kv-service.ts","../src/lib/languages.ts","../src/services/watch.ts","../src/services/webhook-server.ts","../src/brainbank.ts","../src/providers/vector/hnsw-loader.ts","../src/engine/index-api.ts","../src/engine/reembed.ts","../src/engine/search-api.ts","../src/services/plugin-registry.ts","../src/cli/utils.ts","../src/cli/factory/brain-context.ts","../src/cli/factory/builtin-registration.ts","../src/cli/factory/plugin-loader.ts","../src/cli/factory/config-loader.ts","../src/cli/factory/index.ts"],"sourcesContent":["import type { BrainBankConfig, ResolvedConfig } from './types.ts';\n\nimport * as path from 'node:path';\n\n\nexport const DEFAULTS: ResolvedConfig = {\n repoPath: '.',\n dbPath: '.brainbank/data/brainbank.db',\n gitDepth: 500,\n maxFileSize: 512_000, // 500KB\n maxDiffBytes: 8192,\n hnswM: 16,\n hnswEfConstruction: 200,\n hnswEfSearch: 50,\n embeddingDims: 384,\n maxElements: 2_000_000,\n};\n\n\n/**\n * Merge partial config with defaults.\n * All fields become required.\n * Relative dbPath is resolved against repoPath.\n */\nexport function resolveConfig(partial: BrainBankConfig = {}): ResolvedConfig {\n const repoPath = path.resolve(partial.repoPath ?? DEFAULTS.repoPath);\n const rawDbPath = partial.dbPath ?? DEFAULTS.dbPath;\n // Resolve relative dbPath against repoPath so DB lives alongside the repo\n const dbPath = path.isAbsolute(rawDbPath) ? rawDbPath : path.join(repoPath, rawDbPath);\n\n return {\n repoPath,\n dbPath,\n gitDepth: partial.gitDepth ?? DEFAULTS.gitDepth,\n maxFileSize: partial.maxFileSize ?? DEFAULTS.maxFileSize,\n maxDiffBytes: partial.maxDiffBytes ?? DEFAULTS.maxDiffBytes,\n hnswM: partial.hnswM ?? DEFAULTS.hnswM,\n hnswEfConstruction: partial.hnswEfConstruction ?? DEFAULTS.hnswEfConstruction,\n hnswEfSearch: partial.hnswEfSearch ?? DEFAULTS.hnswEfSearch,\n embeddingDims: partial.embeddingDims ?? DEFAULTS.embeddingDims,\n maxElements: partial.maxElements ?? DEFAULTS.maxElements,\n embeddingProvider: partial.embeddingProvider,\n reranker: partial.reranker,\n pruner: partial.pruner,\n expander: partial.expander,\n webhookPort: partial.webhookPort,\n contextFields: partial.contextFields,\n };\n}\n\n","/**\n * BrainBank — Constants\n *\n * Core-only constants. Plugin names are NOT defined here — they belong\n * to their respective packages. Only keys owned by the core live here.\n */\n\nimport { createRequire } from 'node:module';\n\nconst require = createRequire(import.meta.url);\nconst pkg = require('../package.json') as { version: string };\n\n/** Package version from package.json. */\nexport const VERSION: string = pkg.version;\n\n/** HNSW index key for KV collections (core-owned). */\nexport const HNSW = {\n KV: 'kv',\n} as const;\n\nexport type HnswKey = typeof HNSW[keyof typeof HNSW];\n","/**\n * BrainBank — SQLite Adapter\n *\n * Implements `DatabaseAdapter` using Node.js built-in `node:sqlite`.\n * Zero native addons — no ABI issues across Node versions.\n * Handles WAL mode, directory creation, schema init, and transactions.\n */\n\nimport type { DatabaseAdapter, AdapterCapabilities, PreparedStatement, ExecuteResult } from './adapter.ts';\nimport type { DatabaseSync as DatabaseSyncType, StatementSync as StatementSyncType } from 'node:sqlite';\n\nimport { DatabaseSync } from 'node:sqlite';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\n\n\n// ── Schema ──────────────────────────────────────────────────────────\n\nexport const SCHEMA_VERSION = 9;\n\n/**\n * Create core tables and indices.\n * Safe to call multiple times — uses IF NOT EXISTS.\n * Domain tables are created by plugins via runPluginMigrations().\n */\nfunction createSchema(adapter: DatabaseAdapter): void {\n adapter.exec(`\n -- ── Schema versioning ──────────────────────────\n CREATE TABLE IF NOT EXISTS schema_version (\n version INTEGER PRIMARY KEY,\n applied_at INTEGER NOT NULL DEFAULT (unixepoch())\n );\n INSERT OR IGNORE INTO schema_version (version) VALUES (${SCHEMA_VERSION});\n\n -- ── Plugin Versions (migration tracking) ──────\n CREATE TABLE IF NOT EXISTS plugin_versions (\n plugin_name TEXT PRIMARY KEY,\n version INTEGER NOT NULL,\n applied_at INTEGER NOT NULL DEFAULT (unixepoch())\n );\n\n -- ── Dynamic Collections (KV Store) ───────────\n CREATE TABLE IF NOT EXISTS kv_data (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n collection TEXT NOT NULL,\n content TEXT NOT NULL,\n meta_json TEXT NOT NULL DEFAULT '{}',\n tags_json TEXT NOT NULL DEFAULT '[]',\n expires_at INTEGER,\n created_at INTEGER NOT NULL DEFAULT (unixepoch())\n );\n\n CREATE TABLE IF NOT EXISTS kv_vectors (\n data_id INTEGER PRIMARY KEY REFERENCES kv_data(id) ON DELETE CASCADE,\n embedding BLOB NOT NULL\n );\n\n CREATE VIRTUAL TABLE IF NOT EXISTS fts_kv USING fts5(\n content,\n collection,\n content='kv_data',\n content_rowid='id',\n tokenize='porter unicode61'\n );\n\n CREATE TRIGGER IF NOT EXISTS trg_fts_kv_insert AFTER INSERT ON kv_data BEGIN\n INSERT INTO fts_kv(rowid, content, collection)\n VALUES (new.id, new.content, new.collection);\n END;\n CREATE TRIGGER IF NOT EXISTS trg_fts_kv_delete AFTER DELETE ON kv_data BEGIN\n INSERT INTO fts_kv(fts_kv, rowid, content, collection)\n VALUES ('delete', old.id, old.content, old.collection);\n END;\n\n CREATE INDEX IF NOT EXISTS idx_kv_collection ON kv_data(collection);\n CREATE INDEX IF NOT EXISTS idx_kv_created ON kv_data(created_at DESC);\n\n -- ── Embedding Metadata ───────────────────────\n CREATE TABLE IF NOT EXISTS embedding_meta (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL\n );\n\n -- ── Index State (cross-process coordination) ─\n CREATE TABLE IF NOT EXISTS index_state (\n name TEXT PRIMARY KEY,\n version INTEGER NOT NULL DEFAULT 0,\n writer_pid INTEGER NOT NULL DEFAULT 0,\n updated_at INTEGER NOT NULL DEFAULT (unixepoch())\n );\n\n -- ── Plugin Tracking (incremental indexing) ────\n CREATE TABLE IF NOT EXISTS plugin_tracking (\n plugin TEXT NOT NULL,\n key TEXT NOT NULL,\n content_hash TEXT NOT NULL,\n indexed_at INTEGER NOT NULL DEFAULT (unixepoch()),\n PRIMARY KEY (plugin, key)\n );\n `);\n}\n\n/** Get the current schema version from the database. */\nexport function getSchemaVersion(adapter: DatabaseAdapter): number {\n try {\n const row = adapter.prepare('SELECT MAX(version) as v FROM schema_version').get() as { v: number } | undefined;\n return row?.v ?? 0;\n } catch {\n return 0;\n }\n}\n\n\n// ── Statement Wrapper ───────────────────────────────────────────────\n\n/** SQLite parameter type accepted by node:sqlite. */\ntype SqlParam = string | number | bigint | null | Uint8Array;\n\n/** Wraps a `node:sqlite` StatementSync into a `PreparedStatement<T>`. */\nfunction wrapStatement<T>(stmt: StatementSyncType): PreparedStatement<T> {\n return {\n get(...params: unknown[]): T | undefined {\n return stmt.get(...(params as SqlParam[])) as T | undefined;\n },\n all(...params: unknown[]): T[] {\n return stmt.all(...(params as SqlParam[])) as T[];\n },\n run(...params: unknown[]): ExecuteResult {\n const info = stmt.run(...(params as SqlParam[]));\n return {\n lastInsertRowid: info.lastInsertRowid,\n changes: Number(info.changes),\n };\n },\n iterate(...params: unknown[]): IterableIterator<T> {\n return stmt.iterate(...(params as SqlParam[])) as IterableIterator<T>;\n },\n };\n}\n\n\n// ── SQLiteAdapter ───────────────────────────────────────────────────\n\nexport class SQLiteAdapter implements DatabaseAdapter {\n private _db: DatabaseSyncType;\n\n readonly capabilities: AdapterCapabilities = {\n fts: 'fts5',\n upsert: 'or-replace',\n json: true,\n vectors: false,\n };\n\n constructor(dbPath: string) {\n // Ensure parent directory exists\n const dir = path.dirname(dbPath);\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n\n this._db = new DatabaseSync(dbPath);\n this._db.exec('PRAGMA journal_mode = WAL');\n this._db.exec('PRAGMA busy_timeout = 5000');\n this._db.exec('PRAGMA synchronous = NORMAL');\n this._db.exec('PRAGMA foreign_keys = ON');\n\n // Initialize schema\n createSchema(this);\n }\n\n /** Prepare a reusable statement. */\n prepare<T = unknown>(sql: string): PreparedStatement<T> {\n return wrapStatement<T>(this._db.prepare(sql));\n }\n\n /** Execute raw SQL (no results). */\n exec(sql: string): void {\n this._db.exec(sql);\n }\n\n /** Run a function inside a transaction. Auto-commits on success, auto-rollbacks on error. */\n transaction<T>(fn: () => T): T {\n this._db.exec('BEGIN');\n try {\n const result = fn();\n this._db.exec('COMMIT');\n return result;\n } catch (err) {\n this._db.exec('ROLLBACK');\n throw err;\n }\n }\n\n /** Run a prepared statement on multiple rows. Wraps in a single transaction. */\n batch<T extends unknown[]>(sql: string, rows: T[]): void {\n const stmt = this._db.prepare(sql);\n this.transaction(() => {\n for (const row of rows) {\n stmt.run(...(row as SqlParam[]));\n }\n });\n }\n\n /** Close the database. */\n close(): void {\n this._db.close();\n }\n\n /**\n * Access the underlying `node:sqlite` DatabaseSync instance.\n *\n * @deprecated Use `DatabaseAdapter` methods instead. This exists\n * only for gradual migration of plugins that depend on driver internals.\n */\n raw<T = unknown>(): T {\n return this._db as unknown as T;\n }\n}\n","/**\n * BrainBank — Incremental Tracker\n *\n * Standardized helper for plugins to detect add/update/delete during indexing.\n * Uses a shared `plugin_tracking` table with per-plugin namespacing.\n *\n * Usage in a plugin:\n * const tracker = ctx.createTracker(); // uses plugin name\n * for (const file of files) {\n * const hash = sha256(content);\n * if (tracker.isUnchanged(file, hash)) { skipped++; continue; }\n * indexFile(file, content);\n * tracker.markIndexed(file, hash);\n * }\n * const orphans = tracker.findOrphans(new Set(files));\n * for (const key of orphans) { removeData(key); tracker.remove(key); }\n */\n\nimport type { DatabaseAdapter } from './adapter.ts';\n\n/** Incremental index tracker — detects add/update/delete for plugin files. */\nexport interface IncrementalTracker {\n /** Check if a key's content is unchanged. Returns true if the hash matches (skip indexing). */\n isUnchanged(key: string, contentHash: string): boolean;\n\n /** Mark a key as successfully indexed with the given hash. Call after indexing completes. */\n markIndexed(key: string, contentHash: string): void;\n\n /** Find tracked keys that are NOT in the current set. Returns keys to delete. */\n findOrphans(currentKeys: Set<string>): string[];\n\n /** Remove tracking for a key. Call after cleaning up the key's data. */\n remove(key: string): void;\n\n /** Remove all tracking entries for this plugin. */\n clear(): void;\n}\n\n/** Create tracking table. Called during core schema init. */\nexport function createTrackingTable(db: DatabaseAdapter): void {\n db.exec(`\n CREATE TABLE IF NOT EXISTS plugin_tracking (\n plugin TEXT NOT NULL,\n key TEXT NOT NULL,\n content_hash TEXT NOT NULL,\n indexed_at INTEGER NOT NULL DEFAULT (unixepoch()),\n PRIMARY KEY (plugin, key)\n );\n `);\n}\n\n/** Create an IncrementalTracker scoped to a plugin name. */\nexport function createTracker(db: DatabaseAdapter, pluginName: string): IncrementalTracker {\n return {\n isUnchanged(key: string, contentHash: string): boolean {\n const row = db.prepare(\n 'SELECT content_hash FROM plugin_tracking WHERE plugin = ? AND key = ?'\n ).get(pluginName, key) as { content_hash: string } | undefined;\n return row?.content_hash === contentHash;\n },\n\n markIndexed(key: string, contentHash: string): void {\n db.prepare(`\n INSERT INTO plugin_tracking (plugin, key, content_hash)\n VALUES (?, ?, ?)\n ON CONFLICT(plugin, key) DO UPDATE SET\n content_hash = excluded.content_hash,\n indexed_at = unixepoch()\n `).run(pluginName, key, contentHash);\n },\n\n findOrphans(currentKeys: Set<string>): string[] {\n const rows = db.prepare(\n 'SELECT key FROM plugin_tracking WHERE plugin = ?'\n ).all(pluginName) as { key: string }[];\n return rows.filter(r => !currentKeys.has(r.key)).map(r => r.key);\n },\n\n remove(key: string): void {\n db.prepare(\n 'DELETE FROM plugin_tracking WHERE plugin = ? AND key = ?'\n ).run(pluginName, key);\n },\n\n clear(): void {\n db.prepare(\n 'DELETE FROM plugin_tracking WHERE plugin = ?'\n ).run(pluginName);\n },\n };\n}\n","/**\n * BrainBank — Database Metadata\n *\n * Helpers for reading/writing metadata stored in core SQLite tables:\n *\n * - **Index State** — cross-process HNSW version tracking.\n * Processes compare in-memory versions with DB to detect staleness\n * and trigger hot-reload via `ensureFresh()`.\n *\n * - **Embedding Meta** — tracks which embedding provider is stored in\n * the database. Detects dimension mismatches at startup and updates\n * metadata after `reembed()`.\n */\n\nimport type { EmbeddingProvider } from '@/types.ts';\nimport type { DatabaseAdapter, EmbeddingMetaRow } from './adapter.ts';\n\nimport { providerKey } from '@/lib/provider-key.ts';\n\n\n// ── Index State ─────────────────────────────────────────────────────\n\n/** Row shape returned from index_state queries. */\ninterface IndexStateRow {\n name: string;\n version: number;\n writer_pid: number;\n updated_at: number;\n}\n\n/**\n * Increment the version for a given index name.\n * Sets writer_pid to current process PID.\n * Uses UPSERT so the row is created on first call.\n */\nexport function bumpVersion(db: DatabaseAdapter, name: string): number {\n const row = db.prepare(`\n INSERT INTO index_state (name, version, writer_pid, updated_at)\n VALUES (?, 1, ?, unixepoch())\n ON CONFLICT(name) DO UPDATE SET\n version = version + 1,\n writer_pid = excluded.writer_pid,\n updated_at = excluded.updated_at\n RETURNING version\n `).get(name, process.pid) as { version: number };\n return row.version;\n}\n\n/**\n * Get all index versions as a Map.\n * Used by `ensureFresh()` to compare against in-memory versions.\n */\nexport function getVersions(db: DatabaseAdapter): Map<string, number> {\n const rows = db.prepare('SELECT name, version FROM index_state').all() as IndexStateRow[];\n const map = new Map<string, number>();\n for (const row of rows) {\n map.set(row.name, row.version);\n }\n return map;\n}\n\n/** Get the version of a single index. Returns 0 if not found. */\nexport function getVersion(db: DatabaseAdapter, name: string): number {\n const row = db.prepare('SELECT version FROM index_state WHERE name = ?').get(name) as { version: number } | undefined;\n return row?.version ?? 0;\n}\n\n\n// ── Embedding Meta ──────────────────────────────────────────────────\n\n/** Stored embedding metadata shape. */\nexport interface EmbeddingMeta {\n provider: string;\n dims: number;\n /** Stable key for auto-resolving provider on startup (e.g. 'openai', 'local'). */\n providerKey: string;\n}\n\n/** Get stored embedding metadata. Returns null if not set. */\nexport function getEmbeddingMeta(db: DatabaseAdapter): EmbeddingMeta | null {\n try {\n const provider = db.prepare(\n \"SELECT value FROM embedding_meta WHERE key = 'provider'\"\n ).get() as EmbeddingMetaRow | undefined;\n const dims = db.prepare(\n \"SELECT value FROM embedding_meta WHERE key = 'dims'\"\n ).get() as EmbeddingMetaRow | undefined;\n const key = db.prepare(\n \"SELECT value FROM embedding_meta WHERE key = 'provider_key'\"\n ).get() as EmbeddingMetaRow | undefined;\n\n if (!provider || !dims) return null;\n return {\n provider: provider.value,\n dims: Number(dims.value),\n providerKey: key?.value ?? 'local',\n };\n } catch {\n return null;\n }\n}\n\n/** Store current provider info. */\nexport function setEmbeddingMeta(db: DatabaseAdapter, embedding: EmbeddingProvider): void {\n const upsert = db.prepare(\n 'INSERT OR REPLACE INTO embedding_meta (key, value) VALUES (?, ?)'\n );\n upsert.run('provider', embedding.constructor?.name ?? 'unknown');\n upsert.run('dims', String(embedding.dims));\n upsert.run('provider_key', providerKey(embedding));\n upsert.run('indexed_at', new Date().toISOString());\n}\n\n/** Check if the configured provider differs from what's stored. */\nexport function detectProviderMismatch(\n db: DatabaseAdapter,\n embedding: EmbeddingProvider,\n): { mismatch: boolean; stored: string; current: string } | null {\n const meta = getEmbeddingMeta(db);\n if (!meta) return null; // First time, no mismatch\n\n const currentName = embedding.constructor?.name ?? 'unknown';\n const mismatch = meta.dims !== embedding.dims || meta.provider !== currentName;\n\n return {\n mismatch,\n stored: `${meta.provider}/${meta.dims}`,\n current: `${currentName}/${embedding.dims}`,\n };\n}\n","/**\n * BrainBank — Write Lock\n *\n * Advisory file lock for cross-process HNSW write exclusion.\n * Uses `O_CREAT | O_EXCL` for atomic lock creation — works on all OS.\n * Stale locks (dead PID) are detected and stolen automatically.\n */\n\nimport { openSync, closeSync, unlinkSync, readFileSync, writeFileSync, existsSync, mkdirSync, constants } from 'node:fs';\nimport { join } from 'node:path';\n\n/** Max wait time before giving up on acquiring a lock (ms). */\nconst MAX_WAIT_MS = 30_000;\n\n/** Initial retry delay (ms), doubled on each retry. */\nconst INITIAL_DELAY_MS = 50;\n\n/** Check if a process is alive by sending signal 0. */\nfunction isProcessAlive(pid: number): boolean {\n if (isNaN(pid)) return false;\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n\n/** Resolve the lock file path. */\nfunction lockPath(lockDir: string, name: string): string {\n return join(lockDir, `${name}.lock`);\n}\n\n/** Try to create the lock file atomically. Returns true on success. */\nfunction tryCreateLock(filePath: string): boolean {\n try {\n const fd = openSync(filePath, constants.O_CREAT | constants.O_EXCL | constants.O_WRONLY);\n writeFileSync(fd, String(process.pid));\n closeSync(fd);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Acquire an advisory lock. Blocks with exponential backoff if another\n * process holds the lock. Steals stale locks from dead processes.\n *\n * @throws After MAX_WAIT_MS if the lock cannot be acquired.\n */\nexport async function acquireLock(lockDir: string, name: string): Promise<void> {\n if (!existsSync(lockDir)) {\n mkdirSync(lockDir, { recursive: true });\n }\n\n const fp = lockPath(lockDir, name);\n let delay = INITIAL_DELAY_MS;\n let elapsed = 0;\n\n while (true) {\n if (tryCreateLock(fp)) return;\n\n // Lock exists — check if holder is alive\n try {\n const content = readFileSync(fp, 'utf-8').trim();\n const pid = parseInt(content, 10);\n if (isNaN(pid) || !isProcessAlive(pid)) {\n // Stale lock (dead or invalid PID) — steal it\n try { unlinkSync(fp); } catch { /* race: another process stole it first */ }\n if (tryCreateLock(fp)) return;\n }\n } catch {\n // File gone between check and read — retry\n if (tryCreateLock(fp)) return;\n }\n\n if (elapsed >= MAX_WAIT_MS) {\n throw new Error(`BrainBank: Could not acquire write lock '${name}' after ${MAX_WAIT_MS}ms. Another process may be indexing.`);\n }\n\n await new Promise<void>(r => setTimeout(r, delay));\n elapsed += delay;\n delay = Math.min(delay * 2, 2000);\n }\n}\n\n/** Release an advisory lock. Safe to call even if not held. */\nexport function releaseLock(lockDir: string, name: string): void {\n try {\n unlinkSync(lockPath(lockDir, name));\n } catch {\n // Already released or never acquired — safe to ignore\n }\n}\n\n/**\n * Execute a function while holding an advisory lock.\n * Lock is always released, even on error.\n */\nexport async function withLock<T>(lockDir: string, name: string, fn: () => T | Promise<T>): Promise<T> {\n await acquireLock(lockDir, name);\n try {\n return await fn();\n } finally {\n releaseLock(lockDir, name);\n }\n}\n","/**\n * BrainBank — Math Utilities\n * \n * Pure vector math functions for similarity calculations.\n * No dependencies — works on Float32Array directly.\n */\n\n/**\n * Cosine similarity between two vectors.\n * Assumes vectors are already normalized (unit length).\n * Returns value between -1.0 and 1.0.\n */\nexport function cosineSimilarity(a: Float32Array, b: Float32Array): number {\n if (a.length !== b.length) {\n throw new Error(`Vector dimension mismatch: ${a.length} vs ${b.length}`);\n }\n if (a.length === 0) return 0;\n\n let dot = 0;\n for (let i = 0; i < a.length; i++) {\n dot += a[i] * b[i];\n }\n return dot;\n}\n\n/**\n * Full cosine similarity (normalizes first).\n * Use this when vectors may not be pre-normalized.\n */\nexport function cosineSimilarityFull(a: Float32Array, b: Float32Array): number {\n if (a.length !== b.length) {\n throw new Error(`Vector dimension mismatch: ${a.length} vs ${b.length}`);\n }\n if (a.length === 0) return 0;\n\n let dot = 0, normA = 0, normB = 0;\n for (let i = 0; i < a.length; i++) {\n dot += a[i] * b[i];\n normA += a[i] * a[i];\n normB += b[i] * b[i];\n }\n const denom = Math.sqrt(normA) * Math.sqrt(normB);\n return denom === 0 ? 0 : dot / denom;\n}\n\n/**\n * L2-normalize a vector to unit length.\n * Returns a new Float32Array.\n */\nexport function normalize(vec: Float32Array): Float32Array {\n let norm = 0;\n for (let i = 0; i < vec.length; i++) {\n norm += vec[i] * vec[i];\n }\n norm = Math.sqrt(norm);\n if (norm === 0) return new Float32Array(vec.length);\n\n const result = new Float32Array(vec.length);\n for (let i = 0; i < vec.length; i++) {\n result[i] = vec[i] / norm;\n }\n return result;\n}\n\n/**\n * Euclidean distance between two vectors.\n */\nexport function euclideanDistance(a: Float32Array, b: Float32Array): number {\n if (a.length !== b.length) {\n throw new Error(`Vector dimension mismatch: ${a.length} vs ${b.length}`);\n }\n let sum = 0;\n for (let i = 0; i < a.length; i++) {\n const d = a[i] - b[i];\n sum += d * d;\n }\n return Math.sqrt(sum);\n}\n\n/**\n * Convert a Float32Array to a Buffer for SQLite storage.\n * Handles views with non-zero byteOffset (e.g. from batched embedding output).\n * Using Buffer.from(vec.buffer) directly is WRONG for views — it copies the entire parent buffer.\n */\nexport function vecToBuffer(vec: Float32Array): Buffer {\n return Buffer.from(vec.buffer, vec.byteOffset, vec.byteLength);\n}\n","/**\n * BrainBank — Rerank\n * \n * Position-aware score blending between retrieval and reranker.\n * Pure function — no state.\n * \n * Top 1-3: 75% retrieval / 25% reranker (preserves exact matches)\n * Top 4-10: 60% retrieval / 40% reranker\n * Top 11+: 40% retrieval / 60% reranker (trust reranker more)\n */\n\nimport type { Reranker, SearchResult } from '@/types.ts';\n\n/** Re-rank results using position-aware blending. */\nexport async function rerank(\n query: string,\n results: SearchResult[],\n reranker: Reranker,\n): Promise<SearchResult[]> {\n const documents = results.map(r => r.content);\n const scores = await reranker.rank(query, documents);\n\n const blended = results.map((r, i) => {\n const pos = i + 1;\n const rrfWeight = pos <= 3 ? 0.75 : pos <= 10 ? 0.60 : 0.40;\n return {\n ...r,\n score: rrfWeight * r.score + (1 - rrfWeight) * (scores[i] ?? 0),\n };\n });\n\n return blended.sort((a, b) => b.score - a.score);\n}\n","/**\n * BrainBank — Reciprocal Rank Fusion (RRF)\n * \n * Combines results from multiple search systems (vector + BM25)\n * using the RRF algorithm: score = Σ 1/(k + rank_i)\n * \n * This is the same algorithm used by Elasticsearch, QMD, and most\n * production hybrid search systems. Simple but very effective.\n * \n * Reference: Cormack et al., \"Reciprocal Rank Fusion outperforms\n * Condorcet and individual Rank Learning Methods\" (2009)\n */\n\nimport type { SearchResult } from '@/types.ts';\n\n/**\n * Fuse ranked lists from different search systems into a single ranked list.\n * \n * @param resultSets - Arrays of SearchResult from different systems (e.g. vector, BM25)\n * @param k - Smoothing constant. Default: 60 (standard value). Higher = less emphasis on top ranks.\n * @param maxResults - Maximum results to return.\n */\nexport function reciprocalRankFusion(\n resultSets: SearchResult[][],\n k: number = 60,\n maxResults: number = 15,\n): SearchResult[] {\n // Build a map: unique key → { bestResult, rrfScore }\n const fused = new Map<string, { result: SearchResult; rrfScore: number }>();\n\n for (const results of resultSets) {\n for (let rank = 0; rank < results.length; rank++) {\n const r = results[rank];\n const key = resultKey(r);\n const rrfContribution = 1.0 / (k + rank + 1);\n\n const existing = fused.get(key);\n if (existing) {\n existing.rrfScore += rrfContribution;\n // Keep the result with the higher original score\n if (r.score > existing.result.score) {\n existing.result = { ...r };\n }\n } else {\n fused.set(key, {\n result: { ...r },\n rrfScore: rrfContribution,\n });\n }\n }\n }\n\n // Sort by RRF score descending, normalize, and return\n const sorted = Array.from(fused.values())\n .sort((a, b) => b.rrfScore - a.rrfScore)\n .slice(0, maxResults);\n\n // Normalize RRF scores to 0..1 range.\n // Note: A single result always normalizes to 1.0. This is correct for RRF —\n // the score is relative to the result set, not absolute relevance.\n // Use minScore filters sparingly with RRF.\n const maxRRF = sorted[0]?.rrfScore ?? 1;\n return sorted.map(entry => ({\n ...entry.result,\n score: entry.rrfScore / maxRRF,\n metadata: {\n ...entry.result.metadata,\n rrfScore: entry.rrfScore,\n },\n }) as SearchResult);\n}\n\n/**\n * Generate a unique key for a search result to detect duplicates across systems.\n */\nfunction resultKey(r: SearchResult): string {\n switch (r.type) {\n case 'code':\n return `code:${r.filePath}:${r.metadata.startLine}-${r.metadata.endLine}`;\n case 'commit':\n return `commit:${r.metadata.hash || r.metadata.shortHash}`;\n case 'document':\n return `document:${r.filePath ?? ''}:${r.metadata.collection ?? ''}:${r.metadata.seq ?? ''}:${r.content?.slice(0, 80)}`;\n case 'collection':\n return `collection:${r.metadata.id ?? r.content?.slice(0, 80)}`;\n }\n}\n\n/**\n * Generic RRF that works on any type — no SearchResult required.\n *\n * @param lists - Ranked lists from different search systems.\n * @param keyFn - Returns a stable unique string per item.\n * @param scoreFn - Extracts the original score from an item.\n * @param k - Smoothing constant. Default: 60.\n * @param maxResults - Maximum results to return.\n */\nexport function fuseRankedLists<T>(\n lists: T[][],\n keyFn: (item: T) => string,\n scoreFn: (item: T) => number,\n k: number = 60,\n maxResults: number = 15,\n): { item: T; score: number }[] {\n const fused = new Map<string, { item: T; rrfScore: number; bestScore: number }>();\n\n for (const list of lists) {\n for (let rank = 0; rank < list.length; rank++) {\n const item = list[rank];\n const key = keyFn(item);\n const contribution = 1.0 / (k + rank + 1);\n const score = scoreFn(item);\n\n const existing = fused.get(key);\n if (existing) {\n existing.rrfScore += contribution;\n if (score > existing.bestScore) {\n existing.item = item;\n existing.bestScore = score;\n }\n } else {\n fused.set(key, { item, rrfScore: contribution, bestScore: score });\n }\n }\n }\n\n const sorted = [...fused.values()]\n .sort((a, b) => b.rrfScore - a.rrfScore)\n .slice(0, maxResults);\n\n const maxRRF = sorted[0]?.rrfScore ?? 1;\n return sorted.map(e => ({ item: e.item, score: e.rrfScore / maxRRF }));\n}\n","/**\n * BrainBank — Prune Utility\n *\n * Bridges SearchResult[] → Pruner.prune() → filtered SearchResult[].\n * Converts results to lightweight PrunerItems with full content previews,\n * calls the pruner, and filters out dropped results.\n *\n * Content strategy: send the FULL chunk content to the pruner so it can\n * make informed decisions. A per-item character cap prevents cost blowups\n * on monster files — when truncated, the middle is kept (imports + core\n * logic) rather than just the top.\n */\n\nimport type { Pruner, PrunerItem, SearchResult } from '@/types.ts';\n\n/**\n * Max characters per item sent to the pruner.\n * ~8K chars ≈ 200-250 lines — enough for the model to understand\n * the file's purpose without blowing up token budgets.\n */\nconst MAX_PREVIEW_CHARS = 8_000;\n\n/** Run the pruner on search results. Returns results in the order the pruner chose. */\nexport async function pruneResults(\n query: string,\n results: SearchResult[],\n pruner: Pruner,\n): Promise<SearchResult[]> {\n if (results.length <= 1) return results;\n\n // Map results to items with full content (capped per item)\n const items: PrunerItem[] = results.map((r, i) => ({\n id: i,\n filePath: r.filePath ?? 'unknown',\n preview: _buildPreview(r.content),\n metadata: r.metadata as Record<string, unknown>,\n }));\n\n const keepIds = await pruner.prune(query, items);\n const validIds = new Set(Array.from({ length: results.length }, (_, i) => i));\n\n // Respect the pruner's ordering — map IDs to results in returned order\n return keepIds\n .filter(id => validIds.has(id))\n .map(id => results[id]);\n}\n\n/**\n * Build a preview from full content.\n *\n * If the content fits within MAX_PREVIEW_CHARS, return it as-is.\n * For oversized content, keep the first half + last quarter with a\n * \"[... N lines omitted ...]\" marker — this preserves imports/types\n * at the top AND exports/key functions that often live at the bottom.\n */\nfunction _buildPreview(content: string): string {\n if (content.length <= MAX_PREVIEW_CHARS) return content;\n\n const lines = content.split('\\n');\n const totalLines = lines.length;\n\n // Keep ~60% from top, ~25% from bottom\n const topCount = Math.floor(totalLines * 0.6);\n const bottomCount = Math.floor(totalLines * 0.25);\n const omitted = totalLines - topCount - bottomCount;\n\n const topPart = lines.slice(0, topCount).join('\\n');\n const bottomPart = lines.slice(totalLines - bottomCount).join('\\n');\n\n return `${topPart}\\n\\n// [... ${omitted} lines omitted ...]\\n\\n${bottomPart}`;\n}\n","/**\n * BrainBank — BM25 Intersection Boost\n *\n * Pure functions for post-processing vector search results with BM25 keyword overlap.\n * Extracted from ContextBuilder for single-responsibility and testability.\n */\n\nimport type { SearchResult } from '@/types.ts';\nimport type { SearchStrategy } from './types.ts';\n\n/** BM25 boost factor applied to vector results that also match keywords. */\nexport const BM25_BOOST = 0.15;\n\n/**\n * Boost vector results that also appear in BM25 keyword results.\n * Does NOT add new results — only re-scores and re-sorts existing vector hits.\n * This promotes keyword-relevant files without introducing BM25-only noise.\n */\nexport async function boostWithBM25(\n vectorResults: SearchResult[],\n bm25: SearchStrategy,\n query: string,\n sources: Record<string, number>,\n): Promise<SearchResult[]> {\n if (vectorResults.length === 0) return vectorResults;\n\n const bm25Results = await bm25.search(query, { sources });\n if (bm25Results.length === 0) return vectorResults;\n\n // Build a set of BM25 hit keys for fast lookup\n const bm25Keys = new Set<string>();\n for (const r of bm25Results) {\n bm25Keys.add(resultKey(r));\n }\n\n // Boost scores of vector results that also appear in BM25\n const boosted = vectorResults.map(r => {\n const k = resultKey(r);\n if (bm25Keys.has(k)) {\n return { ...r, score: r.score + BM25_BOOST };\n }\n return r;\n });\n\n // Re-sort by boosted score\n boosted.sort((a, b) => b.score - a.score);\n return boosted;\n}\n\n/** Filter results whose filePath starts with `prefix`. */\nexport function filterByPath(results: SearchResult[], prefix: string | undefined): SearchResult[] {\n if (!prefix) return results;\n return results.filter(r => r.filePath?.startsWith(prefix));\n}\n\n/** Exclude results whose filePath starts with any of the given prefixes. */\nexport function filterByIgnore(results: SearchResult[], ignorePaths: string[] | undefined): SearchResult[] {\n if (!ignorePaths || ignorePaths.length === 0) return results;\n return results.filter(r => !r.filePath || !ignorePaths.some(p => r.filePath!.startsWith(p)));\n}\n\n/** Generate a dedup key for a search result (file:startLine:endLine). */\nexport function resultKey(r: SearchResult): string {\n const sl = 'startLine' in r.metadata ? r.metadata.startLine : '';\n const el = 'endLine' in r.metadata ? r.metadata.endLine : '';\n return `${r.filePath ?? ''}:${sl}:${el}`;\n}\n","/**\n * BrainBank — Query Debug Logger\n *\n * Appends structured, human-readable entries to /tmp/brainbank.log.\n * Covers all search operations: getContext, search, hybridSearch, searchBM25.\n * Truncates at 10 MB (keeps the newest half).\n *\n * Layer 0 — pure functions, no state.\n */\n\nimport * as fs from 'node:fs';\n\nconst LOG_PATH = '/tmp/brainbank.log';\nconst MAX_BYTES = 10 * 1024 * 1024; // 10 MB\n\n// ── Public Types ─────────────────────────────────────\n\nexport type QuerySource = 'cli' | 'mcp' | 'daemon' | 'api';\n\nexport interface QueryLogEntry {\n source: QuerySource;\n method: 'getContext' | 'search' | 'hybridSearch' | 'searchBM25';\n query: string;\n embedding: string;\n pruner: string | null;\n reranker: string | null;\n options: Record<string, unknown>;\n results: QueryLogResult[];\n pruned?: QueryLogResult[];\n durationMs: number;\n}\n\nexport interface QueryLogResult {\n filePath: string;\n score: number;\n type: string;\n name?: string;\n}\n\n// ── Public API ───────────────────────────────────────\n\n/** Append a query log entry to /tmp/brainbank.log. Never throws. */\nexport function logQuery(entry: QueryLogEntry): void {\n try {\n _truncateIfNeeded();\n fs.appendFileSync(LOG_PATH, _formatEntry(entry));\n } catch {\n // Logging must never break the app\n }\n}\n\n// ── Formatting ───────────────────────────────────────\n\nfunction _formatEntry(e: QueryLogEntry): string {\n const divider = '═'.repeat(70);\n const lines: string[] = [\n '',\n divider,\n `[${new Date().toISOString()}] ${e.source.toUpperCase()} · ${e.method}`,\n `Query: \"${e.query}\"`,\n `Embedding: ${e.embedding} | Pruner: ${e.pruner ?? 'none'} | Reranker: ${e.reranker ?? 'none'}`,\n ];\n\n // Options (sources, path, etc.)\n const opts = Object.entries(e.options).filter(([, v]) => v !== undefined);\n if (opts.length > 0) {\n const parts = opts.map(([k, v]) =>\n `${k}: ${typeof v === 'object' ? JSON.stringify(v) : String(v)}`\n );\n lines.push(parts.join(' | '));\n }\n\n lines.push(`Duration: ${e.durationMs}ms`);\n lines.push('');\n\n // Results\n const resultCount = e.results.length;\n const prunedCount = e.pruned?.length ?? 0;\n const header = prunedCount > 0\n ? `Results (${resultCount + prunedCount} → ${resultCount} after pruning):`\n : `Results (${resultCount}):`;\n lines.push(header);\n\n for (let i = 0; i < e.results.length; i++) {\n const r = e.results[i];\n const pct = Math.round(r.score * 100);\n const name = r.name ? `[${r.name}]` : '';\n lines.push(` #${String(i + 1).padStart(2)} ${String(pct).padStart(3)}% ${r.filePath.padEnd(45)} ${name}`);\n }\n\n // Pruned items\n if (e.pruned && e.pruned.length > 0) {\n lines.push('');\n lines.push(`Pruned (${e.pruned.length} removed):`);\n for (const r of e.pruned) {\n const name = r.name ? `[${r.name}]` : '';\n lines.push(` ✗ ${r.filePath.padEnd(45)} ${name}`);\n }\n }\n\n lines.push(divider);\n lines.push('');\n\n return lines.join('\\n');\n}\n\n// ── Truncation ───────────────────────────────────────\n\nfunction _truncateIfNeeded(): void {\n try {\n const stat = fs.statSync(LOG_PATH);\n if (stat.size < MAX_BYTES) return;\n\n // Keep the newest half\n const content = fs.readFileSync(LOG_PATH, 'utf-8');\n const half = Math.floor(content.length / 2);\n // Find the next entry boundary after the midpoint\n const nextEntry = content.indexOf('\\n═', half);\n if (nextEntry > 0) {\n fs.writeFileSync(LOG_PATH, '[truncated]\\n' + content.slice(nextEntry + 1));\n }\n } catch {\n // File doesn't exist yet — fine\n }\n}\n","/**\n * BrainBank — Context Builder\n *\n * Orchestrates the context-building pipeline:\n * 1. Vector search (primary)\n * 2. Path scoping (filter)\n * 3. LLM noise pruning (optional)\n * 4. Session dedup (filter)\n * 5. LLM context expansion (optional — expander field)\n * 6. Plugin formatters (output)\n *\n * All search post-processing lives in `bm25-boost.ts`.\n * Plugin-agnostic — discovers formatters from ContextFormatterPlugin.\n */\n\nimport type { ContextOptions, EmbeddingProvider, Expander, ExpanderManifestItem, Pruner, SearchResult } from '@/types.ts';\nimport type { SearchStrategy } from './types.ts';\nimport type { PluginRegistry } from '@/services/plugin-registry.ts';\n\nimport { isContextFormatterPlugin, isContextFieldPlugin, isExpandablePlugin, isSearchable } from '@/plugin.ts';\nimport { filterByPath, filterByIgnore } from './bm25-boost.ts';\nimport { pruneResults } from '@/lib/prune.ts';\nimport { logQuery } from '@/lib/logger.ts';\nimport type { QueryLogResult } from '@/lib/logger.ts';\nimport { providerKey } from '@/lib/provider-key.ts';\n\nexport class ContextBuilder {\n constructor(\n private _search: SearchStrategy | undefined,\n private _registry: PluginRegistry,\n private _pruner?: Pruner,\n private _embedding?: EmbeddingProvider,\n private _rerankerName?: string,\n private _configFields: Record<string, unknown> = {},\n private _expander?: Expander,\n ) {}\n\n /** Set config-level context field defaults (from config.json \"context\" section). */\n set configFields(fields: Record<string, unknown>) {\n this._configFields = fields;\n }\n\n /** Set the expander instance. */\n set expander(expander: Expander | undefined) {\n this._expander = expander;\n }\n\n /** Build a full context block for a task. Returns markdown for system prompt. */\n async build(task: string, options: ContextOptions = {}): Promise<string> {\n const t0 = Date.now();\n const src = options.sources ?? {};\n const { minScore = 0.25, useMMR = true, mmrLambda = 0.7 } = options;\n\n // 1. Primary: vector search (includes per-repo BM25 fusion internally)\n let results: SearchResult[] = this._search\n ? await this._search.search(task, {\n sources: src,\n minScore, useMMR, mmrLambda,\n })\n : [];\n\n // 2. Path scoping + ignore filtering\n results = filterByPath(results, options.pathPrefix);\n results = filterByIgnore(results, options.ignorePaths);\n\n // 3. LLM noise pruning (optional — per-request override or construction-time)\n const pruner = options.pruner ?? this._pruner;\n const beforePrune = results;\n if (pruner && results.length > 1) {\n results = await pruneResults(task, results, pruner);\n }\n\n // 4. Exclude already-returned files (session dedup)\n if (options.excludeFiles && options.excludeFiles.size > 0) {\n results = results.filter(r => !r.filePath || !options.excludeFiles!.has(r.filePath));\n }\n\n // 5. LLM context expansion (optional — only when expander field is enabled)\n const resolvedFields = this._resolveFields(options);\n let expanderNote: string | undefined;\n if (resolvedFields.expander === true && this._expander && results.length > 0) {\n const expansion = await this._expand(task, results);\n if (expansion.results.length > 0) {\n results = [...results, ...expansion.results];\n }\n expanderNote = expansion.note;\n }\n\n // 6. Format output\n const parts: string[] = [`# Context for: \"${task}\"\\n`];\n this._appendFormatterResults(results, parts, options, resolvedFields);\n await this._appendSearchableResults(task, src, minScore, parts);\n\n // 7. Append expander note (last section)\n if (expanderNote) {\n parts.push(`\\n## Expansion Notes\\n\\n${expanderNote}\\n`);\n }\n\n // ── Log ──\n const prunedResults = pruner\n ? beforePrune.filter(r => !results.includes(r))\n : [];\n logQuery({\n source: options.source ?? 'api',\n method: 'getContext',\n query: task,\n embedding: this._embedding ? providerKey(this._embedding) : 'unknown',\n pruner: pruner ? _prunerName(pruner) : null,\n reranker: this._rerankerName ?? null,\n options: {\n sources: src,\n pathPrefix: options.pathPrefix,\n ignorePaths: options.ignorePaths,\n minScore,\n affectedFiles: options.affectedFiles,\n },\n results: results.map(_toLogResult),\n pruned: prunedResults.length > 0 ? prunedResults.map(_toLogResult) : undefined,\n durationMs: Date.now() - t0,\n });\n\n return parts.join('\\n');\n }\n\n /** Invoke ContextFormatterPlugins. Multi-repo: each plugin formats its own results. */\n private _appendFormatterResults(\n results: SearchResult[],\n parts: string[],\n options: ContextOptions,\n resolvedFields?: Record<string, unknown>,\n ): void {\n const fields = resolvedFields ?? this._resolveFields(options);\n const seenFormatters = new Set<string>();\n\n for (const mod of this._registry.all) {\n if (!isContextFormatterPlugin(mod)) continue;\n const baseType = mod.name.split(':')[0];\n\n // Multi-repo plugin (e.g. 'code:servicehub-frontend'):\n // scope results to this repo and let each plugin format its own\n const colonIdx = mod.name.indexOf(':');\n if (colonIdx > 0) {\n const repoPrefix = mod.name.slice(colonIdx + 1);\n const scoped = results.filter(r =>\n r.filePath?.startsWith(repoPrefix + '/'),\n );\n if (scoped.length > 0) {\n mod.formatContext(scoped, parts, fields);\n }\n continue;\n }\n\n // Single-repo plugin: dedup by base type (old behavior)\n if (seenFormatters.has(baseType)) continue;\n seenFormatters.add(baseType);\n mod.formatContext(results, parts, fields);\n }\n }\n\n /**\n * Resolve context fields: plugin defaults ← config.json ← per-query.\n * Returns a flat Record with the final value for each field.\n */\n private _resolveFields(options: ContextOptions): Record<string, unknown> {\n // 1. Collect plugin defaults\n const defaults: Record<string, unknown> = {};\n for (const mod of this._registry.all) {\n if (isContextFieldPlugin(mod)) {\n for (const field of mod.contextFields()) {\n defaults[field.name] = field.default;\n }\n }\n }\n\n // 2. Merge: defaults ← config ← per-query\n return { ...defaults, ...this._configFields, ...(options.fields ?? {}) };\n }\n\n /**\n * Run LLM expansion: build manifest of candidate chunks from files\n * NOT already in search results, call expander, resolve selected IDs.\n */\n private async _expand(task: string, results: SearchResult[]): Promise<{ results: SearchResult[]; note?: string }> {\n if (!this._expander) return { results: [] };\n\n // Detect multi-repo prefix from results (e.g. 'servicehub-frontend')\n // Results have prefixed filePaths like 'servicehub-frontend/src/...'\n // but DB chunks have unprefixed paths like 'src/...'\n const repoPrefix = this._detectRepoPrefix(results);\n\n // Collect unique file paths already in results (strip repo prefix for DB match)\n const excludeFilePaths = [...new Set(\n results.filter(r => r.filePath).map(r => {\n const fp = r.filePath as string;\n return repoPrefix && fp.startsWith(repoPrefix + '/') ? fp.slice(repoPrefix.length + 1) : fp;\n }),\n )];\n\n // Collect current chunk IDs (to exclude from manifest)\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 + resolve from the MATCHING ExpandablePlugin only\n // In multi-repo, expand only from the plugin whose name matches the result set's repo\n const manifest: ExpanderManifestItem[] = [];\n let resolver: ((ids: number[]) => SearchResult[]) | undefined;\n for (const mod of this._registry.all) {\n if (!isExpandablePlugin(mod)) continue;\n\n // In multi-repo, only expand from the plugin matching the result set's repo\n // e.g. 'code:servicehub-frontend' matches repoPrefix 'servicehub-frontend'\n const colonIdx = mod.name.indexOf(':');\n const pluginRepo = colonIdx > 0 ? mod.name.slice(colonIdx + 1) : undefined;\n if (repoPrefix && pluginRepo && pluginRepo !== repoPrefix) continue;\n\n manifest.push(...mod.buildManifest(excludeFilePaths, excludeIds));\n if (!resolver) {\n const prefix = pluginRepo;\n resolver = (ids: number[]) => {\n const chunks = mod.resolveChunks(ids);\n // Add repo prefix back to resolved chunk filePaths\n if (prefix) {\n for (const chunk of chunks) {\n if (chunk.filePath) chunk.filePath = `${prefix}/${chunk.filePath}`;\n const meta = chunk.metadata as Record<string, unknown>;\n if (typeof meta.filePath === 'string') {\n meta.filePath = `${prefix}/${meta.filePath}`;\n }\n }\n }\n return chunks;\n };\n }\n }\n if (manifest.length === 0 || !resolver) return { results: [] };\n\n // Call expander\n try {\n const expandResult = await this._expander.expand(task, excludeIds, manifest);\n if (expandResult.ids.length === 0) return { results: [], note: expandResult.note };\n return { results: resolver(expandResult.ids), note: expandResult.note };\n } catch {\n // Fail-open: expansion errors are non-fatal\n return { results: [] };\n }\n }\n\n /** Detect the multi-repo prefix from existing results (e.g. 'servicehub-frontend'). */\n private _detectRepoPrefix(results: SearchResult[]): string | undefined {\n for (const r of results) {\n if (!r.filePath) continue;\n // Multi-repo filePaths look like 'servicehub-frontend/src/...'\n // The repo prefix is the first path segment before 'src/'\n const srcIdx = r.filePath.indexOf('/src/');\n if (srcIdx > 0) return r.filePath.slice(0, srcIdx);\n }\n return undefined;\n }\n\n /** Collect results from SearchablePlugins that don't have their own formatter. */\n private async _appendSearchableResults(\n task: string,\n sources: Record<string, number>,\n minScore: number,\n parts: string[],\n ): Promise<void> {\n for (const mod of this._registry.all) {\n if (isContextFormatterPlugin(mod)) continue;\n if (!isSearchable(mod)) continue;\n const hits = await mod.search(task, { k: sources[mod.name.split(':')[0]] ?? 6, minScore });\n if (hits.length > 0) {\n parts.push(`## ${mod.name}\\n`);\n for (const r of hits) {\n parts.push(`- [${Math.round(r.score * 100)}%] ${r.content.slice(0, 200)}`);\n }\n parts.push('');\n }\n }\n }\n}\n\n// ── Helpers ──────────────────────────────────────────\n\nfunction _toLogResult(r: SearchResult): QueryLogResult {\n const meta = r.metadata as Record<string, unknown> | undefined;\n return {\n filePath: r.filePath ?? 'unknown',\n score: r.score,\n type: r.type,\n name: (meta?.name as string | undefined) ?? undefined,\n };\n}\n\nfunction _prunerName(pruner: Pruner): string {\n return pruner.constructor?.name ?? 'custom';\n}\n","/**\n * BrainBank — Composite BM25 Search Strategy\n *\n * Generic BM25 coordinator that discovers BM25SearchPlugin instances\n * from the registry and delegates per-source keyword search.\n */\n\nimport type { SearchResult } from '@/types.ts';\nimport type { SearchStrategy, SearchOptions } from '@/search/types.ts';\nimport type { PluginRegistry } from '@/services/plugin-registry.ts';\n\nimport { isBM25SearchPlugin } from '@/plugin.ts';\n\nconst DEFAULT_K = 8;\n\nexport class CompositeBM25Search implements SearchStrategy {\n constructor(private _registry: PluginRegistry) {}\n\n /**\n * Run BM25 keyword search across all plugins that implement BM25SearchPlugin.\n * Each plugin searches its own FTS5 tables.\n */\n async search(query: string, options: SearchOptions = {}): Promise<SearchResult[]> {\n const src = options.sources ?? {};\n const results: SearchResult[] = [];\n\n for (const plugin of this._registry.all) {\n if (!isBM25SearchPlugin(plugin)) continue;\n\n const baseType = plugin.name.split(':')[0];\n const k = src[baseType] ?? DEFAULT_K;\n if (k <= 0) continue;\n\n const hits = plugin.searchBM25(query, k);\n\n // Multi-repo: prefix filePaths with sub-repo name (same as CompositeVectorSearch)\n const colonIdx = plugin.name.indexOf(':');\n if (colonIdx > 0) {\n const subRepo = plugin.name.slice(colonIdx + 1);\n for (const hit of hits) {\n if (hit.filePath) hit.filePath = `${subRepo}/${hit.filePath}`;\n const meta = hit.metadata as Record<string, unknown>;\n if (typeof meta.filePath === 'string') {\n meta.filePath = `${subRepo}/${meta.filePath}`;\n }\n }\n }\n\n results.push(...hits);\n }\n\n return results.sort((a, b) => b.score - a.score);\n }\n\n /** Rebuild FTS5 indices across all BM25 plugins. */\n rebuild(): void {\n for (const plugin of this._registry.all) {\n if (!isBM25SearchPlugin(plugin)) continue;\n plugin.rebuildFTS?.();\n }\n }\n}\n","/**\n * BrainBank — Composite Vector Search\n *\n * Generic orchestrator for domain-specific vector searches.\n * Embeds the query once, delegates to registered DomainVectorSearch strategies.\n * Uses round-robin interleaving when multiple strategies exist to ensure\n * balanced representation across repos/domains.\n * Plugin-agnostic — strategies are discovered at wiring time.\n */\n\nimport type { EmbeddingProvider, SearchResult } from '@/types.ts';\nimport type { SearchStrategy, SearchOptions, DomainVectorSearch } from '@/search/types.ts';\n\nexport interface CompositeVectorConfig {\n strategies: Map<string, DomainVectorSearch>;\n embedding: EmbeddingProvider;\n /** Default K values per strategy name. Strategies not listed default to 0. */\n defaults?: Record<string, number>;\n}\n\nexport class CompositeVectorSearch implements SearchStrategy {\n /** Default K when no source override is provided. */\n private static readonly DEFAULT_K = 6;\n\n constructor(private _c: CompositeVectorConfig) {}\n\n /** Search across all registered domain strategies with score-based merge. */\n async search(query: string, options: SearchOptions = {}): Promise<SearchResult[]> {\n const src = options.sources ?? {};\n const { minScore = 0.25, useMMR = true, mmrLambda = 0.7 } = options;\n\n const queryVec = await this._c.embedding.embed(query);\n\n // Each strategy gets full K for ranking quality, cap total after merge\n const allResults: SearchResult[] = [];\n let requestedK = 0;\n\n for (const [name, strategy] of this._c.strategies) {\n const baseName = name.split(':')[0];\n const k = src[name] ?? src[baseName] ?? this._c.defaults?.[name] ?? CompositeVectorSearch.DEFAULT_K;\n if (k <= 0) continue;\n requestedK = Math.max(requestedK, k);\n const hits = strategy.search(queryVec, k, minScore, useMMR, mmrLambda, query);\n\n // Multi-repo: prefix filePaths with sub-repo name so path filtering works\n // e.g. strategy 'code:servicehub-backend' → filePath 'servicehub-backend/src/app.ts'\n const colonIdx = name.indexOf(':');\n if (colonIdx > 0) {\n const subRepo = name.slice(colonIdx + 1);\n for (const hit of hits) {\n if (hit.filePath) hit.filePath = `${subRepo}/${hit.filePath}`;\n const meta = hit.metadata as Record<string, unknown>;\n if (typeof meta.filePath === 'string') {\n meta.filePath = `${subRepo}/${meta.filePath}`;\n }\n }\n }\n\n allResults.push(...hits);\n }\n\n if (allResults.length === 0) return [];\n\n // Sort by raw rrfScore (comparable across repos), cap to requested K\n allResults.sort((a, b) => b.score - a.score);\n const capped = allResults.slice(0, requestedK);\n\n // Normalize scores 0-1 globally\n const maxScore = capped[0].score;\n if (maxScore > 0) {\n for (const r of capped) r.score = r.score / maxScore;\n }\n\n return capped;\n }\n}\n","/**\n * BrainBank — HNSW Vector Index\n * \n * Wraps hnswlib-node for O(log n) approximate nearest neighbor search.\n * M=16 connections, ef=200 construction, ef=50 search by default.\n * 150x faster than brute force at 1M vectors.\n *\n * Supports disk persistence: save(path) / tryLoad(path, count)\n * to skip costly vector-by-vector rebuild on startup.\n */\n\nimport type { VectorIndex, SearchHit } from '@/types.ts';\n\nimport { existsSync } from 'node:fs';\n\n/** Shape of the HNSW index from hnswlib-node. */\ninterface HnswlibIndex {\n initIndex(maxElements: number, M: number, efConstruction: number): void;\n setEf(ef: number): void;\n addPoint(vector: number[], id: number): void;\n markDelete(id: number): void;\n searchKnn(vector: number[], k: number): { neighbors: number[]; distances: number[] };\n writeIndexSync(path: string): void;\n readIndexSync(path: string): void;\n getCurrentCount(): number;\n getIdsList(): number[];\n}\n\n/** Shape of the hnswlib-node module (supports default + named exports). */\ninterface HnswlibModule {\n default?: { HierarchicalNSW: new (space: 'cosine' | 'l2' | 'ip', dims: number) => HnswlibIndex };\n HierarchicalNSW?: new (space: 'cosine' | 'l2' | 'ip', dims: number) => HnswlibIndex;\n}\n\nexport class HNSWIndex implements VectorIndex {\n private _index: HnswlibIndex | null = null;\n private _lib: HnswlibModule | null = null;\n private _ids = new Set<number>();\n\n constructor(\n private _dims: number,\n private _maxElements: number = 2_000_000,\n private _M: number = 16,\n private _efConstruction: number = 200,\n private _efSearch: number = 50,\n ) {}\n\n /**\n * Initialize the HNSW index.\n * Must be called before add/search.\n */\n async init(): Promise<this> {\n this._lib = await import('hnswlib-node');\n this._createIndex();\n return this;\n }\n\n /**\n * Reinitialize the index in-place, clearing all vectors.\n * Required after reembed or full re-index to avoid duplicate IDs.\n * init() must have been called first.\n */\n reinit(): void {\n if (!this._lib) throw new Error('HNSW not initialized — call init() first');\n this._createIndex();\n }\n\n private _createIndex(): void {\n if (!this._lib) throw new Error('HNSW lib not loaded');\n const HNSW = this._lib.default?.HierarchicalNSW ?? this._lib.HierarchicalNSW;\n if (!HNSW) throw new Error('HierarchicalNSW not found in hnswlib-node module');\n this._index = new HNSW('cosine', this._dims);\n this._index.initIndex(this._maxElements, this._M, this._efConstruction);\n this._index.setEf(this._efSearch);\n this._ids = new Set();\n }\n\n /** Maximum capacity of this index. */\n get maxElements(): number { return this._maxElements; }\n\n /**\n * Add a vector with an integer ID.\n * The vector should be pre-normalized for cosine distance.\n */\n add(vector: Float32Array, id: number): void {\n if (!this._index) throw new Error('HNSW index not initialized — call init() first');\n if (this._ids.has(id)) return; // idempotent: skip duplicates\n if (this._ids.size >= this._maxElements) {\n throw new Error(\n `HNSW index full (${this._maxElements} elements). ` +\n `Increase maxElements in config or prune old data.`\n );\n }\n this._index.addPoint(Array.from(vector), id);\n this._ids.add(id);\n }\n\n /**\n * Mark a vector as deleted so it no longer appears in searches.\n * Uses hnswlib-node markDelete under the hood.\n * Safe to call with an ID that doesn't exist.\n */\n remove(id: number): void {\n if (!this._index || this._ids.size === 0) return;\n if (!this._ids.has(id)) return;\n try {\n this._index.markDelete(id);\n this._ids.delete(id);\n } catch {\n // ID not found — ignore silently\n }\n }\n\n /**\n * Search for the k nearest neighbors.\n * Returns results sorted by score (highest first).\n * Score is 1 - cosine_distance (1.0 = identical).\n */\n search(query: Float32Array, k: number): SearchHit[] {\n if (!this._index || this._ids.size === 0) return [];\n\n const actualK = Math.min(k, this._ids.size);\n const result = this._index.searchKnn(Array.from(query), actualK);\n\n return result.neighbors.map((id: number, i: number) => ({\n id,\n score: 1 - result.distances[i],\n }));\n }\n\n /** Number of vectors in the index. */\n get size(): number {\n return this._ids.size;\n }\n\n /**\n * Save the HNSW graph to disk.\n * The file can be loaded later with tryLoad() to skip vector-by-vector insertion.\n */\n save(path: string): void {\n if (!this._index || this._ids.size === 0) return;\n this._index.writeIndexSync(path);\n }\n\n /**\n * Try to load a previously saved HNSW index from disk.\n * Returns true if loaded successfully, false if stale or missing.\n * @param path File path to the saved index\n * @param expectedCount Expected number of vectors (from SQLite) — used to detect staleness\n */\n tryLoad(path: string, expectedCount: number): boolean {\n if (!this._index || !existsSync(path)) return false;\n\n try {\n this._index.readIndexSync(path);\n const loadedCount = this._index.getCurrentCount();\n\n // Stale: vector count in DB differs from saved index\n if (loadedCount !== expectedCount) {\n this.reinit();\n return false;\n }\n\n // Rebuild _ids set from the loaded index\n const ids = this._index.getIdsList();\n this._ids = new Set(ids);\n this._index.setEf(this._efSearch);\n return true;\n } catch {\n this.reinit();\n return false;\n }\n }\n}\n","/**\n * BrainBank — FTS Utilities\n * \n * Shared helpers for SQLite FTS5 query sanitization.\n */\n\n/**\n * Split camelCase, PascalCase, and snake_case into individual words.\n * \"MagicLinkCallback\" → \"Magic Link Callback\"\n * \"tenant_worker\" → \"tenant worker\"\n */\nfunction splitCompound(word: string): string {\n return word\n .replace(/([a-z])([A-Z])/g, '$1 $2') // camelCase → camel Case\n .replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2') // HTMLParser → HTML Parser\n .replace(/[_\\-./\\\\]/g, ' ') // snake_case, kebab-case, paths\n .trim();\n}\n\n/**\n * Sanitize a user query for FTS5 syntax.\n * Strips operators that would cause parse errors, splits compound words,\n * and converts words to implicit AND with exact-match quoting.\n */\nexport function sanitizeFTS(query: string): string {\n const clean = query\n .replace(/[{}[\\]()^~*:]/g, ' ')\n .replace(/\\bAND\\b|\\bOR\\b|\\bNOT\\b|\\bNEAR\\b/gi, '')\n .trim();\n\n // Split compound words (camelCase, PascalCase, snake_case)\n const expanded = clean.split(/\\s+/)\n .map(w => splitCompound(w))\n .join(' ');\n\n const words = expanded.split(/\\s+/).filter(w => w.length > 1);\n if (words.length === 0) return '';\n\n return words.map(w => `\"${w}\"`).join(' ');\n}\n\n/**\n * Normalize BM25 score from SQLite (negative, lower = better)\n * to 0.0–1.0 (higher = better) for consistency with vector search.\n */\nexport function normalizeBM25(rawScore: number): number {\n const abs = Math.abs(rawScore);\n return 1.0 / (1.0 + Math.exp(-0.3 * (abs - 5)));\n}\n\n/**\n * Escape SQL LIKE wildcard characters (`%`, `_`, `\\`).\n * Use with `LIKE ? ESCAPE '\\'` in queries.\n */\nexport function escapeLike(s: string): string {\n return s.replace(/[%_\\\\]/g, '\\\\$&');\n}\n","/**\n * BrainBank — Collection\n * \n * Universal key-value store with vector + BM25 hybrid search.\n * The foundation primitive — store anything, search semantically.\n * \n * const errors = brain.collection('debug_errors');\n * await errors.add('Fixed null check in api handler', { file: 'api.ts' });\n * const hits = await errors.search('null pointer');\n */\n\nimport type { DatabaseAdapter, KvDataRow, CountRow } from '@/db/adapter.ts';\nimport type { HNSWIndex } from '@/providers/vector/hnsw-index.ts';\nimport type { EmbeddingProvider, Reranker, SearchResult } from '@/types.ts';\n\nimport { sanitizeFTS, normalizeBM25 } from '@/lib/fts.ts';\nimport { vecToBuffer } from '@/lib/math.ts';\nimport { rerank } from '@/lib/rerank.ts';\nimport { fuseRankedLists } from '@/lib/rrf.ts';\n\nexport interface CollectionItem {\n id: number;\n collection: string;\n content: string;\n metadata: Record<string, unknown>;\n tags: string[];\n createdAt: number;\n expiresAt?: number;\n score?: number;\n}\n\nexport interface CollectionSearchOptions {\n /** Max results. Default: 5 */\n k?: number;\n /** Search mode. Default: 'hybrid' */\n mode?: 'hybrid' | 'vector' | 'keyword';\n /** Minimum score threshold. Default: 0.15 */\n minScore?: number;\n /** Filter by tags (item must have ALL specified tags). */\n tags?: string[];\n}\n\nexport interface CollectionAddOptions {\n /** Metadata key-value pairs. */\n metadata?: Record<string, unknown>;\n /** Tags for filtering. */\n tags?: string[];\n /** Time-to-live duration string (e.g. '7d', '24h', '30m'). */\n ttl?: string;\n}\n\nexport class Collection {\n constructor(\n private _name: string,\n private _db: DatabaseAdapter,\n private _embedding: EmbeddingProvider,\n private _hnsw: HNSWIndex,\n private _vecs: Map<number, Float32Array>,\n private _reranker?: Reranker,\n ) {}\n\n /** Collection name. */\n get name(): string { return this._name; }\n\n /** Add an item. Returns its ID. */\n async add(content: string, options: CollectionAddOptions | Record<string, unknown> = {}): Promise<number> {\n // Support both signatures: add(content, { metadata, tags, ttl }) and add(content, metadata)\n const opts = 'tags' in options || 'ttl' in options || 'metadata' in options\n ? options as CollectionAddOptions\n : { metadata: options as Record<string, unknown> };\n\n const metadata = opts.metadata ?? {};\n const tags = opts.tags ?? [];\n const expiresAt = opts.ttl ? Math.floor(Date.now() / 1000) + parseDuration(opts.ttl) : null;\n\n // Embed FIRST — if this throws, no orphaned rows are left in kv_data\n const vec = await this._embedding.embed(content);\n\n const result = this._db.prepare(\n 'INSERT INTO kv_data (collection, content, meta_json, tags_json, expires_at) VALUES (?, ?, ?, ?, ?)'\n ).run(this._name, content, JSON.stringify(metadata), JSON.stringify(tags), expiresAt);\n\n const id = Number(result.lastInsertRowid);\n this._db.prepare(\n 'INSERT INTO kv_vectors (data_id, embedding) VALUES (?, ?)'\n ).run(id, vecToBuffer(vec));\n\n this._hnsw.add(vec, id);\n this._vecs.set(id, vec);\n\n return id;\n }\n\n /** Update an item's content (re-embeds). Returns the new ID. */\n async update(id: number, content: string, options?: CollectionAddOptions): Promise<number> {\n const row = this._db.prepare(\n 'SELECT * FROM kv_data WHERE id = ? AND collection = ?'\n ).get(id, this._name) as KvDataRow | undefined;\n\n if (!row) throw new Error(`BrainBank: Item ${id} not found in collection '${this._name}'.`);\n\n // Merge: keep original metadata/tags unless overridden\n const metadata = options?.metadata ?? JSON.parse(row.meta_json || '{}');\n const tags = options?.tags ?? JSON.parse(row.tags_json || '[]');\n const ttl = options?.ttl;\n\n this._removeById(id);\n return this.add(content, { metadata, tags, ...(ttl ? { ttl } : {}) });\n }\n\n /** Add multiple items. Returns their IDs. */\n async addMany(items: { content: string; metadata?: Record<string, unknown>; tags?: string[]; ttl?: string }[]): Promise<number[]> {\n if (items.length === 0) return [];\n\n // Batch embed all texts at once\n const texts = items.map(i => i.content);\n const vecs = await this._embedding.embedBatch(texts);\n\n // Commit DB rows atomically. HNSW is updated ONLY after this succeeds.\n // If the transaction throws, execution never reaches the HNSW loop below.\n const ids: number[] = [];\n const insertData = this._db.prepare(\n 'INSERT INTO kv_data (collection, content, meta_json, tags_json, expires_at) VALUES (?, ?, ?, ?, ?)'\n );\n const insertVec = this._db.prepare(\n 'INSERT INTO kv_vectors (data_id, embedding) VALUES (?, ?)'\n );\n\n this._db.transaction(() => {\n for (let i = 0; i < items.length; i++) {\n const item = items[i];\n const expiresAt = item.ttl ? Math.floor(Date.now() / 1000) + parseDuration(item.ttl) : null;\n\n const result = insertData.run(\n this._name,\n item.content,\n JSON.stringify(item.metadata ?? {}),\n JSON.stringify(item.tags ?? []),\n expiresAt,\n );\n\n const id = Number(result.lastInsertRowid);\n insertVec.run(id, vecToBuffer(vecs[i]));\n ids.push(id);\n }\n });\n\n // HNSW + cache updated after successful commit — no orphan risk on rollback.\n for (let i = 0; i < ids.length; i++) {\n this._hnsw.add(vecs[i], ids[i]);\n this._vecs.set(ids[i], vecs[i]);\n }\n\n return ids;\n }\n\n /** Search this collection. */\n async search(query: string, options: CollectionSearchOptions = {}): Promise<CollectionItem[]> {\n const { k = 5, mode = 'hybrid', minScore = 0.15, tags } = options;\n\n // Auto-prune expired items before search\n this._pruneExpired();\n\n if (mode === 'keyword') return this._filterByTags(this._searchBM25(query, k, minScore), tags);\n if (mode === 'vector') return this._filterByTags(await this._searchVector(query, k, minScore), tags);\n\n // Hybrid: vector + BM25 → generic RRF (no SearchResult conversion)\n const [vectorHits, bm25Hits] = await Promise.all([\n this._searchVector(query, k, 0),\n Promise.resolve(this._searchBM25(query, k, 0)),\n ]);\n\n const fused = fuseRankedLists(\n [vectorHits, bm25Hits],\n h => String(h.id),\n h => h.score ?? 0,\n );\n\n const results: CollectionItem[] = fused\n .map(({ item, score }) => ({ ...item, score }))\n .filter(r => r.score >= minScore)\n .slice(0, k);\n\n // Apply re-ranking if available\n if (this._reranker && results.length > 1) {\n const asSearchResults: SearchResult[] = results.map(r => ({\n type: 'collection' as const,\n score: r.score ?? 0,\n content: r.content,\n metadata: { id: r.id },\n }));\n const reranked = await rerank(query, asSearchResults, this._reranker);\n const rerankedById = new Map(\n reranked.map(r => [r.type === 'collection' ? r.metadata.id : undefined, r.score]),\n );\n const blended = results.map(r => ({ ...r, score: rerankedById.get(r.id) ?? r.score ?? 0 }));\n return this._filterByTags(\n blended.sort((a, b) => (b.score ?? 0) - (a.score ?? 0)),\n tags,\n );\n }\n\n return this._filterByTags(results, tags);\n }\n\n /** Search and return results as SearchResult[] for use in hybrid search pipelines. */\n async searchAsResults(query: string, k: number): Promise<SearchResult[]> {\n const hits = await this.search(query, { k });\n return hits.map(h => ({\n type: 'collection' as const,\n score: h.score ?? 0,\n content: h.content,\n metadata: { ...h.metadata, id: h.id, collection: this._name },\n }));\n }\n\n /** List items (newest first). */\n list(options: { limit?: number; offset?: number; tags?: string[] } = {}): CollectionItem[] {\n const { limit = 20, offset = 0, tags } = options;\n\n // Auto-prune expired items\n this._pruneExpired();\n\n const rows = this._db.prepare(\n 'SELECT * FROM kv_data WHERE collection = ? AND (expires_at IS NULL OR expires_at > ?) ORDER BY created_at DESC, id DESC LIMIT ? OFFSET ?'\n ).all(this._name, Math.floor(Date.now() / 1000), limit, offset) as KvDataRow[];\n return this._filterByTags(rows.map(r => this._rowToItem(r)), tags);\n }\n\n /** Count items in this collection. */\n count(): number {\n return (this._db.prepare(\n 'SELECT COUNT(*) as c FROM kv_data WHERE collection = ? AND (expires_at IS NULL OR expires_at > ?)'\n ).get(this._name, Math.floor(Date.now() / 1000)) as CountRow).c;\n }\n\n /** Keep only the N most recent items, remove the rest. */\n async trim(options: { keep: number }): Promise<{ removed: number }> {\n const before = this.count();\n if (before <= options.keep) return { removed: 0 };\n\n // Get IDs to remove (oldest first, beyond the keep window)\n const toRemove = this._db.prepare(`\n SELECT id FROM kv_data \n WHERE collection = ? \n ORDER BY created_at DESC, id DESC \n LIMIT -1 OFFSET ?\n `).all(this._name, options.keep) as Pick<KvDataRow, 'id'>[];\n\n for (const row of toRemove) {\n this._removeById(row.id);\n }\n\n return { removed: toRemove.length };\n }\n\n /** Remove items older than a duration string (e.g. '30d', '12h'). */\n async prune(options: { olderThan: string }): Promise<{ removed: number }> {\n const seconds = parseDuration(options.olderThan);\n const cutoff = Math.floor(Date.now() / 1000) - seconds;\n\n const toRemove = this._db.prepare(\n 'SELECT id FROM kv_data WHERE collection = ? AND created_at < ?'\n ).all(this._name, cutoff) as Pick<KvDataRow, 'id'>[];\n\n for (const row of toRemove) {\n this._removeById(row.id);\n }\n\n return { removed: toRemove.length };\n }\n\n /** Remove a specific item by ID. */\n remove(id: number): void {\n this._removeById(id);\n }\n\n /** Clear all items in this collection. */\n clear(): void {\n const rows = this._db.prepare(\n 'SELECT id FROM kv_data WHERE collection = ?'\n ).all(this._name) as Pick<KvDataRow, 'id'>[];\n\n for (const row of rows) {\n this._removeById(row.id);\n }\n }\n\n\n private _removeById(id: number): void {\n // DB first — can fail (disk full, lock). If it throws, HNSW+cache stay consistent.\n this._db.prepare('DELETE FROM kv_data WHERE id = ?').run(id);\n // HNSW + cache after — these always succeed\n this._hnsw.remove(id);\n this._vecs.delete(id);\n }\n\n private async _searchVector(query: string, k: number, minScore: number): Promise<CollectionItem[]> {\n if (this._hnsw.size === 0) return [];\n\n const queryVec = await this._embedding.embed(query);\n // Adaptive over-fetch: proportional to total/collection density, clamped [3, 50]\n const searchK = this._adaptiveSearchK(k);\n const hits = this._hnsw.search(queryVec, searchK);\n\n const ids = hits.map(h => h.id);\n if (ids.length === 0) return [];\n\n const scoreMap = new Map(hits.map(h => [h.id, h.score]));\n const placeholders = ids.map(() => '?').join(',');\n\n const rows = this._db.prepare(\n `SELECT * FROM kv_data WHERE id IN (${placeholders}) AND collection = ?`\n ).all(...ids, this._name) as KvDataRow[];\n\n return rows\n .map(r => ({ ...this._rowToItem(r), score: scoreMap.get(r.id) ?? 0 }))\n .filter(r => r.score >= minScore)\n .sort((a, b) => (b.score ?? 0) - (a.score ?? 0))\n .slice(0, k);\n }\n\n /** Compute adaptive over-fetch multiplier based on collection density in shared HNSW. */\n private _adaptiveSearchK(k: number): number {\n const totalSize = this._hnsw.size;\n if (totalSize === 0) return 0;\n const collectionCount = this.count();\n if (collectionCount === 0) return Math.min(k * 3, totalSize);\n const ratio = Math.ceil(totalSize / collectionCount);\n const multiplier = Math.max(3, Math.min(ratio, 50));\n return Math.min(k * multiplier, totalSize);\n }\n\n private _searchBM25(query: string, k: number, minScore: number): CollectionItem[] {\n const ftsQuery = sanitizeFTS(query);\n if (!ftsQuery) return [];\n\n try {\n const rows = this._db.prepare(`\n SELECT d.*, bm25(fts_kv, 5.0, 1.0) AS score\n FROM fts_kv f\n JOIN kv_data d ON d.id = f.rowid\n WHERE fts_kv MATCH ? AND d.collection = ?\n ORDER BY score ASC\n LIMIT ?\n `).all(ftsQuery, this._name, k) as (KvDataRow & { score: number })[];\n\n return rows\n .map(r => ({\n ...this._rowToItem(r),\n score: normalizeBM25(r.score),\n }))\n .filter(r => (r.score ?? 0) >= minScore);\n } catch {\n return [];\n }\n }\n\n private _rowToItem(r: KvDataRow): CollectionItem {\n return {\n id: r.id,\n collection: r.collection,\n content: r.content,\n metadata: JSON.parse(r.meta_json || '{}') as Record<string, unknown>,\n tags: JSON.parse(r.tags_json || '[]') as string[],\n createdAt: r.created_at,\n expiresAt: r.expires_at ?? undefined,\n };\n }\n\n /** Filter results by tags (item must have ALL specified tags). */\n private _filterByTags(items: CollectionItem[], tags?: string[]): CollectionItem[] {\n if (!tags || tags.length === 0) return items;\n return items.filter(item =>\n tags.every(t => item.tags.includes(t))\n );\n }\n\n /** Remove expired items (TTL). Called automatically on search/list. */\n private _pruneExpired(): void {\n const now = Math.floor(Date.now() / 1000);\n const expired = this._db.prepare(\n 'SELECT id FROM kv_data WHERE collection = ? AND expires_at IS NOT NULL AND expires_at <= ?'\n ).all(this._name, now) as Pick<KvDataRow, 'id'>[];\n\n for (const row of expired) {\n this._removeById(row.id);\n }\n }\n}\n\n/** Parse a duration string like '30d', '12h', '5m' to seconds. */\nfunction parseDuration(s: string): number {\n const match = s.match(/^(\\d+)([dhms])$/);\n if (!match) throw new Error(`Invalid duration: \"${s}\". Use format like '30d', '12h', '5m'.`);\n\n const n = parseInt(match[1], 10);\n switch (match[2]) {\n case 'd': return n * 86400;\n case 'h': return n * 3600;\n case 'm': return n * 60;\n case 's': return n;\n default: return n;\n }\n}\n","/**\n * BrainBank — KV Service\n *\n * Owns the shared HNSW index and vector cache for KV collections.\n * Provides collection creation, listing, and deletion.\n * Extracted from BrainBank to separate infrastructure from facade.\n */\n\nimport type { DatabaseAdapter } from '@/db/adapter.ts';\nimport type { HNSWIndex } from '@/providers/vector/hnsw-index.ts';\nimport type { EmbeddingProvider, Reranker } from '@/types.ts';\nimport { Collection } from './collection.ts';\n\nexport class KVService {\n private _collections = new Map<string, Collection>();\n\n constructor(\n private _db: DatabaseAdapter,\n private _embedding: EmbeddingProvider,\n private _hnsw: HNSWIndex,\n private _vecs: Map<number, Float32Array>,\n private _reranker?: Reranker,\n ) {}\n\n /** Get or create a named collection. */\n collection(name: string): Collection {\n if (this._collections.has(name)) return this._collections.get(name)!;\n const coll = new Collection(name, this._db, this._embedding, this._hnsw, this._vecs, this._reranker);\n this._collections.set(name, coll);\n return coll;\n }\n\n /** List all collection names that have data. */\n listNames(): string[] {\n return (this._db.prepare('SELECT DISTINCT collection FROM kv_data ORDER BY collection').all() as { collection: string }[])\n .map(r => r.collection);\n }\n\n /** Delete a collection's data and evict from cache. Removes vectors from HNSW to prevent ghost entries. */\n delete(name: string): void {\n const ids = this._db.prepare(\n 'SELECT id FROM kv_data WHERE collection = ?'\n ).all(name) as { id: number }[];\n\n for (const { id } of ids) {\n this._hnsw.remove(id);\n this._vecs.delete(id);\n }\n\n this._db.prepare('DELETE FROM kv_data WHERE collection = ?').run(name);\n this._collections.delete(name);\n }\n\n /** Access the shared HNSW index (used by reembed). */\n get hnsw(): HNSWIndex { return this._hnsw; }\n\n /** Access the shared vector cache. @internal */\n get vecs(): Map<number, Float32Array> { return this._vecs; }\n\n /** Clear all cached collections and vectors. */\n clear(): void {\n this._collections.clear();\n this._vecs.clear();\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\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 (JSON + YAML excluded — config/CI files cause search noise)\n '.toml': 'toml',\n '.xml': 'xml',\n '.graphql': 'graphql',\n '.gql': 'graphql',\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\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 // Auto-generated code\n 'generated',\n 'sdk',\n 'openapi',\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 // Database (auto-generated migrations, dumps, seeds)\n 'migrations',\n 'db_dumps',\n 'seeds',\n\n // AI / Model cache\n '.model-cache',\n '.brainbank',\n\n // OS\n '.DS_Store',\n]);\n\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\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/** Check if a relative path matches any of the given glob patterns. */\nexport function matchesGlob(relPath: string, patterns: string[]): boolean {\n for (const pattern of patterns) {\n const regex = pattern\n .replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&') // escape regex specials (not * ?)\n .replace(/\\*\\*/g, '\\x00') // placeholder for **\n .replace(/\\*/g, '[^/]*') // * = anything except /\n .replace(/\\?/g, '.') // ? = any single char\n .replace(/\\x00/g, '.*'); // ** = anything including /\n if (new RegExp(`^${regex}$`).test(relPath)) return true;\n }\n return false;\n}\n","/**\n * BrainBank — Watcher\n *\n * Thin coordinator for plugin-driven watching. Each plugin CAN drive its own\n * watching via WatchablePlugin.watch(). For IndexablePlugins that don't\n * implement WatchablePlugin, the Watcher provides a single shared fs.watch\n * tree with fan-out routing so each plugin only receives relevant events.\n *\n * Responsibilities:\n * 1. Call `plugin.watch(onEvent)` for each WatchablePlugin\n * 2. For IndexablePlugins without watch(), share one recursive fs.watch tree\n * 3. Route events to the correct plugin based on sub-repo scope\n * 4. Dedup macOS double-fire events (change+rename per save)\n * 5. Apply per-plugin debounce from `plugin.watchConfig()`\n * 6. On event: call `plugin.indexItems([id])` or `plugin.index()` for re-indexing\n * 7. Call `handle.stop()` on `close()`\n *\n * const watcher = brain.watch({ debounceMs: 2000 });\n * watcher.close(); // stop watching\n */\n\nimport type { Plugin } from '@/plugin.ts';\nimport type { WatchEvent, WatchHandle } from '@/types.ts';\n\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { isIndexable, isWatchable } from '@/plugin.ts';\nimport { isSupported, isIgnoredDir, matchesGlob } from '@/lib/languages.ts';\n\n/** Doc file extensions that the docs plugin indexes. */\nconst DOC_EXTENSIONS = new Set(['.md', '.mdx', '.txt', '.rst']);\n\n\nexport interface WatchOptions {\n /** Default debounce for plugins that don't specify watchConfig. Default: 2000 */\n debounceMs?: number;\n /** Glob patterns to ignore (from config.json code.ignore). */\n ignore?: string[];\n /** Called when a source triggers re-indexing. */\n onIndex?: (sourceId: string, pluginName: string) => void;\n /** Called on errors. */\n onError?: (error: Error) => void;\n}\n\n\n/** Pending event batch for a single plugin. */\ninterface PluginBatch {\n plugin: Plugin;\n handle: WatchHandle;\n events: WatchEvent[];\n timer: ReturnType<typeof setTimeout> | null;\n flushing: boolean;\n}\n\n\n/** Plugin-driven watcher that coordinates re-indexing across all WatchablePlugins. */\nexport class Watcher {\n private _active = true;\n private _batches = new Map<string, PluginBatch>();\n private _reindexFn: () => Promise<void>;\n private _options: WatchOptions;\n private _keepalive: ReturnType<typeof setInterval> | null = null;\n\n constructor(\n reindexFn: () => Promise<void>,\n plugins: Plugin[],\n options: WatchOptions = {},\n repoPath?: string,\n ) {\n this._reindexFn = reindexFn;\n this._options = options;\n this._startWatching(plugins, repoPath);\n }\n\n /** Whether the watcher is active. */\n get active(): boolean { return this._active; }\n\n /** Stop all plugin watchers. */\n async close(): Promise<void> {\n this._active = false;\n\n if (this._keepalive) {\n clearInterval(this._keepalive);\n this._keepalive = null;\n }\n\n for (const batch of this._batches.values()) {\n if (batch.timer) clearTimeout(batch.timer);\n try {\n await batch.handle.stop();\n } catch (err) {\n this._options.onError?.(err instanceof Error ? err : new Error(String(err)));\n }\n }\n this._batches.clear();\n }\n\n\n /** Start watching for each WatchablePlugin, with shared fs.watch fallback. */\n private _startWatching(plugins: Plugin[], repoPath?: string): void {\n let hasAnyWatcher = false;\n const fallbackPlugins: Plugin[] = [];\n\n for (const plugin of plugins) {\n if (isWatchable(plugin)) {\n // Plugin-driven watching\n try {\n const handle = plugin.watch((event) => this._onEvent(plugin, event));\n\n this._batches.set(plugin.name, {\n plugin,\n handle,\n events: [],\n timer: null,\n flushing: false,\n });\n hasAnyWatcher = true;\n } catch (err) {\n this._options.onError?.(err instanceof Error ? err : new Error(String(err)));\n }\n } else if (isIndexable(plugin) && repoPath) {\n // Collect for shared fs.watch fallback\n fallbackPlugins.push(plugin);\n }\n }\n\n // Create a SINGLE shared fs.watch tree for all fallback plugins\n if (fallbackPlugins.length > 0 && repoPath) {\n const sharedHandle = this._startSharedFsWatch(fallbackPlugins, repoPath);\n if (sharedHandle) {\n // Register batches for each fallback plugin with the shared handle\n for (const plugin of fallbackPlugins) {\n this._batches.set(plugin.name, {\n plugin,\n handle: sharedHandle,\n events: [],\n timer: null,\n flushing: false,\n });\n }\n hasAnyWatcher = true;\n }\n }\n\n // Keep the Node event loop alive even if no native watchers are active\n if (hasAnyWatcher) {\n this._keepalive = setInterval(() => {}, 60_000);\n this._keepalive.unref?.(); // allow graceful exit on SIGINT\n }\n }\n\n\n /**\n * Single shared recursive fs.watch that fans out events to multiple plugins.\n * Each event is routed based on: sub-repo prefix (code:backend → servicehub-backend/),\n * file extension (docs → .md only), and code support (code → isSupported).\n */\n private _startSharedFsWatch(plugins: Plugin[], repoPath: string): WatchHandle | null {\n const watchers: fs.FSWatcher[] = [];\n const ignorePatterns = this._options.ignore ?? [];\n\n // Dedup: macOS fs.watch fires both 'change' + 'rename' for a single save.\n const recentEvents = new Map<string, number>();\n const DEDUP_MS = 100;\n\n // Pre-compute routing info per plugin\n const routes = plugins.map(plugin => {\n const baseName = plugin.name.split(':')[0];\n const subRepo = plugin.name.includes(':')\n ? plugin.name.split(':').slice(1).join(':')\n : null;\n return { plugin, baseName, subRepo };\n });\n\n const watchDir = (dir: string): void => {\n try {\n const watcher = fs.watch(dir, { persistent: true }, (_eventType, filename) => {\n if (!filename || !this._active) return;\n const fullPath = path.join(dir, filename);\n const relPath = path.relative(repoPath, fullPath);\n const ext = path.extname(fullPath).toLowerCase();\n\n // Config ignore: skip files matching user-defined glob patterns\n if (ignorePatterns.length > 0 && matchesGlob(relPath, ignorePatterns)) return;\n\n // Dedup: skip if we already saw this file within DEDUP_MS\n const now = Date.now();\n const lastSeen = recentEvents.get(relPath);\n if (lastSeen && now - lastSeen < DEDUP_MS) return;\n recentEvents.set(relPath, now);\n\n const event: WatchEvent = {\n type: 'update',\n sourceId: relPath,\n sourceName: 'file',\n };\n\n // Fan out to matching plugins\n for (const { plugin, baseName, subRepo } of routes) {\n // Sub-repo routing: skip files outside this plugin's scope\n if (subRepo && !relPath.startsWith(subRepo + '/')) continue;\n\n // Extension-based routing\n if (baseName === 'docs') {\n // Docs plugin only cares about doc files\n if (!DOC_EXTENSIONS.has(ext)) continue;\n } else {\n // Code/git plugins only care about supported source files\n if (!isSupported(fullPath)) continue;\n }\n\n this._onEvent(plugin, event);\n }\n });\n\n watcher.on('error', (err) => {\n this._options.onError?.(err instanceof Error ? err : new Error(String(err)));\n });\n\n watchers.push(watcher);\n } catch {\n // Directory might not exist or be inaccessible — skip\n }\n\n // Recurse into subdirectories\n try {\n for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue;\n if (isIgnoredDir(entry.name)) continue;\n if (entry.name.startsWith('.')) continue;\n // Skip directories matching config ignore patterns\n const dirRel = path.relative(repoPath, path.join(dir, entry.name));\n if (ignorePatterns.length > 0 && matchesGlob(dirRel + '/', ignorePatterns)) continue;\n watchDir(path.join(dir, entry.name));\n }\n } catch {\n // Directory read failed — skip\n }\n };\n\n watchDir(repoPath);\n\n if (watchers.length === 0) return null;\n\n // Periodically clean up stale dedup entries to prevent memory leak\n const cleanupInterval = setInterval(() => {\n const cutoff = Date.now() - 10_000;\n for (const [key, ts] of recentEvents) {\n if (ts < cutoff) recentEvents.delete(key);\n }\n }, 30_000);\n cleanupInterval.unref?.();\n\n let stopped = false;\n return {\n get active() { return !stopped; },\n async stop() {\n if (stopped) return;\n stopped = true;\n clearInterval(cleanupInterval);\n for (const w of watchers) {\n try { w.close(); } catch { /* safe to ignore */ }\n }\n watchers.length = 0;\n },\n };\n }\n\n\n /** Handle an incoming event from a plugin. */\n private _onEvent(plugin: Plugin, event: WatchEvent): void {\n if (!this._active) return;\n\n const batch = this._batches.get(plugin.name);\n if (!batch) return;\n\n batch.events.push(event);\n\n // Resolve debounce: plugin config > global options > 2000ms default\n const pluginDebounce = isWatchable(plugin)\n ? plugin.watchConfig?.()?.debounceMs\n : undefined;\n const debounceMs = pluginDebounce ?? this._options.debounceMs ?? 2000;\n\n // Check batch size limit\n const batchSize = isWatchable(plugin)\n ? plugin.watchConfig?.()?.batchSize\n : undefined;\n\n const shouldFlushNow = debounceMs === 0\n || (batchSize !== undefined && batch.events.length >= batchSize);\n\n if (shouldFlushNow) {\n if (batch.timer) clearTimeout(batch.timer);\n batch.timer = null;\n void this._flush(batch);\n return;\n }\n\n // Debounce: reset timer on each new event\n if (batch.timer) clearTimeout(batch.timer);\n batch.timer = setTimeout(() => void this._flush(batch), debounceMs);\n }\n\n /** Flush pending events for a plugin — trigger re-indexing. */\n private async _flush(batch: PluginBatch): Promise<void> {\n if (batch.flushing || batch.events.length === 0) return;\n batch.flushing = true;\n\n const { onIndex, onError } = this._options;\n\n try {\n const events = [...batch.events];\n batch.events.length = 0;\n\n const ids = events.map(e => e.sourceId);\n\n // Try granular re-index first, fall back to full re-index\n if (isIndexable(batch.plugin) && batch.plugin.indexItems) {\n await batch.plugin.indexItems(ids);\n for (const id of ids) {\n onIndex?.(id, batch.plugin.name);\n }\n } else if (isIndexable(batch.plugin)) {\n await batch.plugin.index();\n for (const id of ids) {\n onIndex?.(id, batch.plugin.name);\n }\n } else {\n // Plugin is watchable but not indexable — use global re-index\n await this._reindexFn();\n for (const id of ids) {\n onIndex?.(id, batch.plugin.name);\n }\n }\n } catch (err) {\n onError?.(err instanceof Error ? err : new Error(String(err)));\n } finally {\n batch.flushing = false;\n\n // If new events arrived during flush, schedule another flush\n if (batch.events.length > 0 && this._active) {\n const debounceMs = this._options.debounceMs ?? 2000;\n batch.timer = setTimeout(() => void this._flush(batch), debounceMs);\n }\n }\n }\n}\n","/**\n * BrainBank — Webhook Server\n *\n * Optional shared HTTP server for push-based watch plugins (e.g. Jira, GitHub).\n * Opt-in: only created when `new BrainBank({ webhookPort: 4242 })` is configured.\n *\n * Plugins register routes during `watch()`:\n * ctx.webhookServer?.register('jira', '/jira/webhook', handler);\n *\n * Each plugin gets its own path namespace. Unregistering cleans up the route.\n */\n\nimport * as http from 'node:http';\n\n\n/** Handler for incoming webhook payloads. */\nexport type WebhookHandler = (body: unknown) => void;\n\ninterface Route {\n pluginName: string;\n path: string;\n handler: WebhookHandler;\n}\n\n\n/** Shared HTTP server for push-based watch plugins. */\nexport class WebhookServer {\n private _server: http.Server | null = null;\n private _routes: Route[] = [];\n private _listening = false;\n\n /** Start listening on the specified port. */\n listen(port: number): void {\n if (this._listening) return;\n\n this._server = http.createServer((req, res) => {\n this._handleRequest(req, res);\n });\n\n this._server.listen(port);\n this._listening = true;\n }\n\n /** Register a webhook route for a plugin. */\n register(pluginName: string, path: string, handler: WebhookHandler): void {\n // Normalize path to start with /\n const normalizedPath = path.startsWith('/') ? path : `/${path}`;\n this._routes.push({ pluginName, path: normalizedPath, handler });\n }\n\n /** Remove all routes for a plugin. */\n unregister(pluginName: string): void {\n this._routes = this._routes.filter(r => r.pluginName !== pluginName);\n }\n\n /** Stop the server and clear all routes. */\n close(): void {\n this._server?.close();\n this._server = null;\n this._routes = [];\n this._listening = false;\n }\n\n /** Whether the server is currently listening. */\n get active(): boolean {\n return this._listening;\n }\n\n /** Route incoming POST requests to the matching handler. */\n private _handleRequest(req: http.IncomingMessage, res: http.ServerResponse): void {\n if (req.method !== 'POST') {\n res.writeHead(405, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Method not allowed' }));\n return;\n }\n\n const route = this._routes.find(r => req.url === r.path);\n if (!route) {\n res.writeHead(404, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Not found' }));\n return;\n }\n\n const chunks: Buffer[] = [];\n req.on('data', (chunk: Buffer) => chunks.push(chunk));\n req.on('end', () => {\n try {\n const raw = Buffer.concat(chunks).toString('utf8');\n const body = raw ? JSON.parse(raw) as unknown : {};\n route.handler(body);\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ ok: true }));\n } catch {\n // Malformed JSON — still acknowledge receipt\n res.writeHead(400, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Invalid JSON' }));\n }\n });\n }\n}\n","/**\n * BrainBank — Main Orchestrator\n *\n * Thin facade that composes services:\n * - **PluginRegistry** — registration + lookup\n * - **SearchAPI** — all search + context logic\n * - **runIndex** — code / git / docs indexing orchestration\n *\n * Initialization is inline — no indirection layers.\n * All heavy logic lives in those modules; BrainBank owns state,\n * guards (`_requireInit` / `initialize`), and public API shape.\n *\n * Multi-process coordination:\n * - `ensureFresh()` detects stale HNSW indices via `index_state` table\n * - Hot-reloads from disk when another process updated the index\n * - Called implicitly before every search operation\n */\n\nimport type { ReembedResult, ReembedOptions } from './engine/reembed.ts';\nimport type { IndexDeps } from './engine/index-api.ts';\nimport type { Plugin, PluginContext } from './plugin.ts';\nimport type { SearchOptions } from './search/types.ts';\nimport type { WatchOptions } from './services/watch.ts';\nimport type {\n BrainBankConfig, ResolvedConfig, EmbeddingProvider,\n SearchResult, ICollection,\n ContextOptions, StageProgressCallback,\n} from './types.ts';\n\nimport { EventEmitter } from 'node:events';\n\nimport * as path from 'node:path';\nimport { resolveConfig } from './config.ts';\nimport { HNSW } from './constants.ts';\nimport type { DatabaseAdapter } from './db/adapter.ts';\nimport { SQLiteAdapter } from './db/sqlite-adapter.ts';\nimport { createTracker } from './db/tracker.ts';\nimport { setEmbeddingMeta, getEmbeddingMeta, detectProviderMismatch, getVersions } from './db/metadata.ts';\nimport { runIndex } from './engine/index-api.ts';\nimport { reembedAll } from './engine/reembed.ts';\nimport { SearchAPI, createSearchAPI } from './engine/search-api.ts';\nimport { isReembeddable, isFileResolvable } from './plugin.ts';\n\nimport { resolveEmbedding } from './providers/embeddings/resolve.ts';\nimport { HNSWIndex } from './providers/vector/hnsw-index.ts';\nimport { hnswPath, countRows, saveAllHnsw, loadVectors, loadVecCache, reloadHnsw } from './providers/vector/hnsw-loader.ts';\nimport { KVService } from './services/kv-service.ts';\nimport { PluginRegistry } from './services/plugin-registry.ts';\nimport { Watcher } from './services/watch.ts';\nimport { WebhookServer } from './services/webhook-server.ts';\n\n\nexport class BrainBank extends EventEmitter {\n private _config: ResolvedConfig;\n private _db!: DatabaseAdapter;\n private _embedding!: EmbeddingProvider;\n private _registry = new PluginRegistry();\n private _searchAPI?: SearchAPI;\n private _indexDeps?: IndexDeps;\n private _kvService?: KVService;\n private _initialized = false;\n private _initPromise: Promise<void> | null = null;\n private _watcher?: Watcher;\n private _webhookServer?: WebhookServer;\n private _sharedHnsw = new Map<string, { hnsw: HNSWIndex; vecCache: Map<number, Float32Array> }>();\n private _repoDBs = new Map<string, DatabaseAdapter>();\n private _loadedVersions = new Map<string, number>();\n\n constructor(config: BrainBankConfig = {}) {\n super();\n this._config = resolveConfig(config);\n }\n\n /** Whether the brainbank has been initialized. */\n get isInitialized(): boolean {\n return this._initialized;\n }\n\n /** The resolved configuration. */\n get config(): Readonly<ResolvedConfig> {\n return this._config;\n }\n\n /** All registered plugin names (insertion order). */\n get plugins(): string[] {\n return this._registry.names;\n }\n\n /**\n * Register a plugin. Chainable.\n *\n * @example\n * brain.use(code({ repoPath: '.' })).use(docs());\n *\n * @throws If called after `initialize()`.\n */\n use(plugin: Plugin): this {\n if (this._initialized) {\n throw new Error(\n `BrainBank: Cannot add plugin '${plugin.name}' after initialization. ` +\n `Call .use() before any operations.`,\n );\n }\n this._registry.register(plugin);\n return this;\n }\n\n /**\n * Check if a plugin is loaded.\n * Also matches type prefix (e.g. `'code'` matches `'code:frontend'`).\n */\n has(name: string): boolean {\n return this._registry.has(name);\n }\n\n /** Get a plugin instance by name. Returns `undefined` if not loaded. */\n plugin<T extends Plugin = Plugin>(name: string): T | undefined {\n return this._registry.has(name) ? this._registry.get<T>(name) : undefined;\n }\n\n /**\n * Initialize database, HNSW indices, and load existing vectors.\n * Automatically called by `index` / `search` methods if not yet initialized.\n * Concurrent calls are deduped via `_initPromise`.\n *\n * @param options.force - If `true`, skip vector load on dimension mismatch.\n */\n async initialize(options: { force?: boolean } = {}): Promise<void> {\n if (this._initialized) return;\n if (this._initPromise) return this._initPromise;\n\n this._initPromise = this._runInitialize(options)\n .then(() => { this._initPromise = null; })\n .catch(err => {\n this._cleanupAfterFailedInit();\n throw err;\n });\n\n return this._initPromise;\n }\n\n /**\n * Estimated memory footprint of loaded HNSW indices (bytes).\n * Counts only vector data: `vectorCount × dims × 4`.\n * Returns 0 if not initialized.\n */\n memoryHint(): number {\n if (!this._initialized) return 0;\n const dims = this._config.embeddingDims;\n const bytesPerVector = dims * 4;\n\n let total = 0;\n if (this._kvService) total += this._kvService.hnsw.size * bytesPerVector;\n for (const { hnsw } of this._sharedHnsw.values()) {\n total += hnsw.size * bytesPerVector;\n }\n return total;\n }\n\n /** Close database and release all resources. Synchronous. */\n close(): void {\n void this._watcher?.close();\n this._webhookServer?.close();\n for (const plugin of this._registry.all) plugin.close?.();\n\n const reranker = this._config.reranker as { close?: () => void } | undefined;\n reranker?.close?.();\n\n const pruner = this._config.pruner as { close?: () => void } | undefined;\n pruner?.close?.();\n\n this._embedding?.close().catch(() => { });\n for (const db of this._repoDBs.values()) db.close();\n this._repoDBs.clear();\n this._db?.close();\n this._initialized = false;\n this._kvService?.clear();\n this._sharedHnsw.clear();\n this._loadedVersions.clear();\n this._kvService = undefined;\n this._searchAPI = undefined;\n this._indexDeps = undefined;\n this._webhookServer = undefined;\n this._registry.clear();\n }\n\n /**\n * Get or create a dynamic collection (universal KV primitive).\n *\n * @example\n * const errors = brain.collection('debug_errors');\n * await errors.add('Fixed null check', { file: 'api.ts' });\n * const hits = await errors.search('null pointer');\n *\n * @throws If not initialized.\n */\n collection(name: string): ICollection {\n if (!this._kvService) {\n throw new Error('BrainBank: Collections not ready. Call await brain.initialize() first.');\n }\n return this._kvService.collection(name);\n }\n\n /** List all collection names that have data. */\n listCollectionNames(): string[] {\n this._requireInit('listCollectionNames');\n return this._kvService!.listNames();\n }\n\n /** Delete a collection's data and evict from cache. */\n deleteCollection(name: string): void {\n this._requireInit('deleteCollection');\n this._kvService!.delete(name);\n }\n\n /** Run indexing across selected modules. Auto-initializes. */\n async index(options: {\n modules?: string[];\n forceReindex?: boolean;\n onProgress?: StageProgressCallback;\n pluginOptions?: Record<string, unknown>;\n } = {}): Promise<Record<string, unknown>> {\n await this.initialize();\n return runIndex(this._indexDeps!, options);\n }\n\n /**\n * Detect stale HNSW indices and hot-reload from disk.\n * Called implicitly before every search operation.\n * Cost: one SQLite SELECT (~5μs on WAL mode).\n */\n async ensureFresh(): Promise<void> {\n if (!this._initialized) return;\n\n const dbVersions = getVersions(this._db);\n for (const [name, dbVersion] of dbVersions) {\n const loaded = this._loadedVersions.get(name) ?? 0;\n if (dbVersion <= loaded) continue;\n\n this.emit('progress', `Hot-reload: ${name} version ${loaded} → ${dbVersion}`);\n this._reloadIndex(name);\n this._loadedVersions.set(name, dbVersion);\n }\n }\n\n /**\n * Semantic search across all loaded modules.\n * Scope via `sources: { code: 10, git: 0 }`.\n */\n async search(query: string, options?: SearchOptions): Promise<SearchResult[]> {\n await this.initialize();\n await this.ensureFresh();\n return this._searchAPI?.search(query, options) ?? [];\n }\n\n /**\n * Hybrid search: vector + BM25 fused with Reciprocal Rank Fusion.\n * Scope via `sources: { code: 10, git: 5, docs: 3, myNotes: 5 }`.\n */\n async hybridSearch(query: string, options?: SearchOptions): Promise<SearchResult[]> {\n await this.initialize();\n await this.ensureFresh();\n return this._searchAPI?.hybridSearch(query, options) ?? [];\n }\n\n /** BM25 keyword search only (no embeddings needed). */\n async searchBM25(query: string, options?: SearchOptions): Promise<SearchResult[]> {\n await this.initialize();\n await this.ensureFresh();\n return this._searchAPI?.searchBM25(query, options) ?? [];\n }\n\n /** Build formatted context block for LLM system prompt injection. Auto-initializes. */\n async getContext(task: string, options: ContextOptions = {}): Promise<string> {\n await this.initialize();\n await this.ensureFresh();\n return this._searchAPI?.getContext(task, options) ?? '';\n }\n\n /**\n * Resolve file paths, directories, and glob patterns to full SearchResults.\n * Bypasses search entirely — reads directly from plugin indexes.\n *\n * @example\n * const files = brain.resolveFiles(['src/auth/login.ts', 'src/graph/']);\n */\n resolveFiles(patterns: string[]): SearchResult[] {\n this._requireInit('resolveFiles');\n const results: SearchResult[] = [];\n for (const mod of this._registry.all) {\n if (!isFileResolvable(mod)) continue;\n results.push(...mod.resolveFiles(patterns));\n }\n return results;\n }\n\n /** Rebuild FTS5 indices. */\n rebuildFTS(): void {\n this._requireInit('rebuildFTS');\n this._searchAPI?.rebuildFTS();\n }\n\n /** Get statistics for all loaded plugins. */\n stats(): Record<string, Record<string, number | string> | undefined> {\n this._requireInit('stats');\n const result: Record<string, Record<string, number | string> | undefined> = {};\n\n for (const mod of this._registry.all) {\n if (mod.stats) {\n const baseType = mod.name.split(':')[0];\n result[baseType] = mod.stats();\n }\n }\n\n return result;\n }\n\n\n /** Start watching for changes and auto-re-index. */\n watch(options: WatchOptions = {}): Watcher {\n this._requireInit('watch');\n void this._watcher?.close();\n this._watcher = new Watcher(\n async () => { await this.index(); },\n this._registry.all,\n options,\n this._config.repoPath,\n );\n return this._watcher;\n }\n\n /**\n * Re-embed all existing text with the current embedding provider.\n * Use after switching providers (e.g. Local → OpenAI).\n */\n async reembed(options: ReembedOptions = {}): Promise<ReembedResult> {\n await this.initialize();\n\n const hnswMap = new Map<string, { hnsw: HNSWIndex; vecs: Map<number, Float32Array> }>();\n\n if (this._kvService) {\n hnswMap.set(HNSW.KV, { hnsw: this._kvService.hnsw, vecs: this._kvService.vecs });\n }\n for (const [type, shared] of this._sharedHnsw) {\n hnswMap.set(type, { hnsw: shared.hnsw, vecs: shared.vecCache });\n }\n\n\n const result = await reembedAll(this._db, this._embedding, hnswMap, this._registry.all, options, {\n dbPath: this._config.dbPath,\n kvHnsw: this._kvService!.hnsw,\n sharedHnsw: this._sharedHnsw,\n });\n\n this.emit('reembedded', result);\n return result;\n }\n\n /**\n * Linear 8-step initialization:\n * 1. Open database\n * 2. Resolve embedding provider\n * 3. Check dimension mismatch\n * 4. Create KV HNSW + KVService\n * 5. Load KV vectors\n * 6. Initialize plugins\n * 7. Persist HNSW indices\n * 8. Build SearchAPI + index deps\n */\n private async _runInitialize(options: { force?: boolean } = {}): Promise<void> {\n if (this._initialized) return;\n\n this._db = new SQLiteAdapter(this._config.dbPath);\n this._embedding = await this._resolveEmbedding();\n\n const mismatch = detectProviderMismatch(this._db, this._embedding);\n if (mismatch?.mismatch && !options.force) {\n this._db.close();\n throw new Error(\n `BrainBank: Embedding dimension mismatch (stored: ${mismatch.stored}, current: ${mismatch.current}). ` +\n `Run brain.reembed() to re-index with the new provider, or switch back to the original provider.`,\n );\n }\n setEmbeddingMeta(this._db, this._embedding);\n\n const skipVectorLoad = !!(options.force && mismatch?.mismatch);\n const dims = this._embedding.dims ?? this._config.embeddingDims;\n\n const kvHnsw = new HNSWIndex(\n dims,\n this._config.maxElements ?? 500_000,\n this._config.hnswM,\n this._config.hnswEfConstruction,\n this._config.hnswEfSearch,\n );\n await kvHnsw.init();\n\n this._kvService = new KVService(this._db, this._embedding, kvHnsw, new Map(), this._config.reranker);\n\n if (!skipVectorLoad) {\n const kvIndexPath = hnswPath(this._config.dbPath, 'kv');\n const kvCount = countRows(this._db, 'kv_vectors');\n if (kvHnsw.tryLoad(kvIndexPath, kvCount)) {\n loadVecCache(this._db, 'kv_vectors', 'data_id', this._kvService.vecs);\n } else {\n loadVectors(this._db, 'kv_vectors', 'data_id', kvHnsw, this._kvService.vecs);\n }\n }\n\n const privateHnsw = new Map<string, HNSWIndex>();\n for (const mod of this._registry.all) {\n const pluginDb = this._getOrCreatePluginDb(mod.name);\n // Propagate embedding meta to per-repo DBs\n if (pluginDb !== this._db) {\n setEmbeddingMeta(pluginDb, this._embedding);\n }\n const ctx = this._buildPluginContext(skipVectorLoad, privateHnsw, pluginDb, mod.name);\n await mod.initialize(ctx);\n }\n\n // Start webhook server if configured (after plugins so they can register routes)\n if (this._config.webhookPort) {\n this._webhookServer = new WebhookServer();\n this._webhookServer.listen(this._config.webhookPort);\n }\n\n await saveAllHnsw(this._config.dbPath, kvHnsw, this._sharedHnsw, privateHnsw);\n\n this._searchAPI = createSearchAPI(\n this._db, this._embedding, this._config,\n this._registry, this._kvService, this._sharedHnsw,\n );\n this._indexDeps = {\n db: this._db,\n dbPath: this._config.dbPath,\n sharedHnsw: this._sharedHnsw,\n kvHnsw,\n registry: this._registry,\n emit: (e, d) => this.emit(e, d),\n };\n\n // Snapshot current versions for staleness detection\n this._loadedVersions = getVersions(this._db);\n\n this._initialized = true;\n this.emit('initialized', { plugins: this.plugins });\n }\n\n /** Reset shared state after a failed `_runInitialize`. */\n private _cleanupAfterFailedInit(): void {\n for (const { hnsw } of this._sharedHnsw.values()) {\n try { hnsw.reinit(); } catch (e) {\n this.emit('warn', `HNSW reinit failed during cleanup: ${e}`);\n }\n }\n this._kvService?.clear();\n if (this._kvService) {\n try { this._kvService.hnsw.reinit(); } catch (e) {\n this.emit('warn', `KV HNSW reinit failed during cleanup: ${e}`);\n }\n }\n try { this._db?.close(); } catch { /* DB already closed — safe to ignore */ }\n\n this._db = undefined!;\n this._kvService = undefined;\n this._searchAPI = undefined;\n this._indexDeps = undefined;\n this._initPromise = null;\n }\n\n /** Resolve embedding: explicit config > stored DB key > local default. */\n private async _resolveEmbedding(): Promise<EmbeddingProvider> {\n if (this._config.embeddingProvider) return this._config.embeddingProvider;\n\n const meta = getEmbeddingMeta(this._db);\n if (meta?.providerKey && meta.providerKey !== 'local') {\n this.emit('progress', `Embedding: auto-resolved '${meta.providerKey}' from DB`);\n return resolveEmbedding(meta.providerKey);\n }\n return resolveEmbedding('local');\n }\n\n /**\n * Get or create a per-repo SQLiteAdapter for namespaced plugins.\n * Non-namespaced plugins use the root DB.\n * DB path: `.brainbank/<repoName>.db` (e.g., `servicehub-backend.db`).\n */\n private _getOrCreatePluginDb(pluginName: string): DatabaseAdapter {\n if (!pluginName.includes(':')) return this._db;\n\n const repoName = pluginName.split(':').slice(1).join(':');\n const existing = this._repoDBs.get(repoName);\n if (existing) return existing;\n\n const dir = path.dirname(this._config.dbPath);\n const repoDbPath = path.join(dir, `${repoName}.db`);\n const db = new SQLiteAdapter(repoDbPath);\n this._repoDBs.set(repoName, db);\n return db;\n }\n\n /** Build a per-plugin `PluginContext` with appropriate DB and HNSW scoping. */\n private _buildPluginContext(\n skipVectorLoad: boolean,\n privateHnsw: Map<string, HNSWIndex>,\n pluginDb: DatabaseAdapter,\n pluginName: string,\n ): PluginContext {\n let autoId = 0;\n const dbPath = this._config.dbPath;\n\n return {\n db: pluginDb,\n embedding: this._embedding,\n config: this._config,\n\n createHnsw: async (maxElements?: number, dims?: number, name?: string) => {\n const hnsw = await new HNSWIndex(\n dims ?? this._config.embeddingDims,\n maxElements ?? this._config.maxElements,\n this._config.hnswM,\n this._config.hnswEfConstruction,\n this._config.hnswEfSearch,\n ).init();\n privateHnsw.set(name ?? `private-${autoId++}`, hnsw);\n return hnsw;\n },\n\n loadVectors: (table, idCol, hnsw, cache) => {\n if (skipVectorLoad) return;\n const indexName = table.replace('_vectors', '').replace('_chunks', '');\n const indexPath = hnswPath(dbPath, `${indexName}-${pluginDb === this._db ? 'root' : 'repo'}`);\n const rowCount = countRows(pluginDb, table);\n if (hnsw.tryLoad(indexPath, rowCount)) {\n loadVecCache(pluginDb, table, idCol, cache);\n } else {\n loadVectors(pluginDb, table, idCol, hnsw, cache);\n }\n },\n\n getOrCreateSharedHnsw: async (type, maxElements, dims) => {\n const existing = this._sharedHnsw.get(type);\n if (existing) return { ...existing, isNew: false };\n\n const hnsw = await new HNSWIndex(\n dims ?? this._config.embeddingDims,\n maxElements ?? this._config.maxElements,\n this._config.hnswM,\n this._config.hnswEfConstruction,\n this._config.hnswEfSearch,\n ).init();\n\n const vecCache = new Map<number, Float32Array>();\n this._sharedHnsw.set(type, { hnsw, vecCache });\n return { hnsw, vecCache, isNew: true };\n },\n\n collection: (name) => this._kvService!.collection(name),\n\n createTracker: () => createTracker(pluginDb, pluginName),\n\n webhookServer: this._webhookServer,\n };\n }\n\n /**\n * Reload a single HNSW index by name.\n * Discovers the vector table via ReembeddablePlugin capability.\n * KV is handled directly since it's core-owned.\n *\n * The `name` comes from `index_state` and equals the plugin's `mod.name`\n * (e.g. `code:backend`, `git`, `docs`). This matches the key used in\n * `getOrCreateSharedHnsw()` during initialization.\n */\n private _reloadIndex(name: string): void {\n // KV HNSW — core-owned, known table\n if (name === HNSW.KV && this._kvService) {\n reloadHnsw({\n dbPath: this._config.dbPath,\n db: this._db,\n name,\n hnsw: this._kvService.hnsw,\n vecCache: this._kvService.vecs,\n vectorTable: 'kv_vectors',\n idCol: 'data_id',\n });\n return;\n }\n\n // Shared HNSW — exact key match against the map\n const shared = this._sharedHnsw.get(name);\n if (!shared) return;\n\n // Discover vector table from the plugin that owns this HNSW key.\n // Match by plugin name (e.g. 'code:backend') or reembed name (e.g. 'code').\n for (const mod of this._registry.all) {\n if (!isReembeddable(mod)) continue;\n if (mod.name !== name) continue;\n\n const cfg = mod.reembedConfig();\n reloadHnsw({\n dbPath: this._config.dbPath,\n db: this._db,\n name,\n hnsw: shared.hnsw,\n vecCache: shared.vecCache,\n vectorTable: cfg.vectorTable,\n idCol: cfg.fkColumn,\n });\n return;\n }\n }\n\n /** Guard: throw descriptive error if not initialized. */\n private _requireInit(method: string): void {\n if (!this._initialized) {\n throw new Error(`BrainBank: Not initialized. Call await brain.initialize() before ${method}().`);\n }\n }\n}\n","/**\n * BrainBank — HNSW Loader\n *\n * Utilities for persisting and loading HNSW indexes to/from disk.\n * Used by BrainBank._runInitialize() and PluginContext.loadVectors().\n *\n * Includes cross-process write locking and hot-reload support\n * for multi-process coordination.\n */\n\nimport type { DatabaseAdapter, CountRow } from '@/db/adapter.ts';\nimport type { HNSWIndex } from './hnsw-index.ts';\n\nimport { dirname, join } from 'node:path';\nimport { withLock } from '@/lib/write-lock.ts';\n\n/** Derive the HNSW index file path from the DB path. */\nexport function hnswPath(dbPath: string, name: string): string {\n return join(dirname(dbPath), `hnsw-${name}.index`);\n}\n\n/** Derive the lock directory from the DB path. */\nexport function lockDir(dbPath: string): string {\n return dirname(dbPath);\n}\n\n/** Count rows in a vector table (fast, no data transfer). */\nexport function countRows(db: DatabaseAdapter, table: string): number {\n const row = db.prepare(`SELECT COUNT(*) as c FROM ${table}`).get() as CountRow;\n return row?.c ?? 0;\n}\n\n/**\n * Save all HNSW indexes to disk with cross-process file locking.\n * Prevents concurrent writes from corrupting `.index` files.\n */\nexport async function saveAllHnsw(\n dbPath: string,\n kvHnsw: HNSWIndex,\n sharedHnsw: Map<string, { hnsw: HNSWIndex; vecCache: Map<number, Float32Array> }>,\n privateHnsw: Map<string, HNSWIndex>,\n): Promise<boolean> {\n try {\n await withLock(lockDir(dbPath), 'hnsw', () => {\n kvHnsw.save(hnswPath(dbPath, 'kv'));\n for (const [name, { hnsw }] of sharedHnsw) {\n hnsw.save(hnswPath(dbPath, name));\n }\n for (const [name, hnsw] of privateHnsw) {\n hnsw.save(hnswPath(dbPath, name));\n }\n });\n return true;\n } catch {\n // Non-fatal: next startup rebuilds from SQLite (slower).\n return false;\n }\n}\n\n/** Load vectors from SQLite into HNSW + cache. */\nexport function loadVectors(\n db: DatabaseAdapter,\n table: string,\n idCol: string,\n hnsw: HNSWIndex,\n cache: Map<number, Float32Array>,\n): void {\n const iter = db.prepare(`SELECT ${idCol}, embedding FROM ${table}`).iterate() as IterableIterator<{ embedding: Uint8Array; [key: string]: unknown }>;\n for (const row of iter) {\n const vec = new Float32Array(\n row.embedding.buffer.slice(\n row.embedding.byteOffset,\n row.embedding.byteOffset + row.embedding.byteLength,\n ),\n );\n hnsw.add(vec, row[idCol] as number);\n cache.set(row[idCol] as number, vec);\n }\n}\n\n/** Populate only the vecCache from SQLite (HNSW already loaded from file). */\nexport function loadVecCache(\n db: DatabaseAdapter,\n table: string,\n idCol: string,\n cache: Map<number, Float32Array>,\n): void {\n const iter = db.prepare(`SELECT ${idCol}, embedding FROM ${table}`).iterate() as IterableIterator<{ embedding: Uint8Array; [key: string]: unknown }>;\n for (const row of iter) {\n const vec = new Float32Array(\n row.embedding.buffer.slice(\n row.embedding.byteOffset,\n row.embedding.byteOffset + row.embedding.byteLength,\n ),\n );\n cache.set(row[idCol] as number, vec);\n }\n}\n\n/** Deps for reloading a single HNSW index from disk. */\ninterface ReloadDeps {\n dbPath: string;\n db: DatabaseAdapter;\n name: string;\n hnsw: HNSWIndex;\n vecCache: Map<number, Float32Array>;\n vectorTable: string;\n idCol: string;\n}\n\n/**\n * Reload a single HNSW index from disk after detecting a stale version.\n * Reinitializes the in-memory HNSW, loads the saved index file, and\n * refreshes the vector cache from SQLite.\n */\nexport function reloadHnsw(deps: ReloadDeps): void {\n const { dbPath, db, name, hnsw, vecCache, vectorTable, idCol } = deps;\n const indexPath = hnswPath(dbPath, name);\n const rowCount = countRows(db, vectorTable);\n\n hnsw.reinit();\n vecCache.clear();\n\n if (hnsw.tryLoad(indexPath, rowCount)) {\n loadVecCache(db, vectorTable, idCol, vecCache);\n } else {\n loadVectors(db, vectorTable, idCol, hnsw, vecCache);\n }\n}\n","/**\n * BrainBank — Index API\n *\n * Orchestrates indexing across all registered plugins.\n * Plugin-agnostic — uses capability interfaces to discover what can be indexed.\n *\n * After each plugin finishes indexing, bumps the version in `index_state`\n * and saves HNSW indices to disk (with cross-process file locking).\n */\n\nimport type { DatabaseAdapter } from '@/db/adapter.ts';\nimport type { HNSWIndex } from '@/providers/vector/hnsw-index.ts';\nimport type { PluginRegistry } from '@/services/plugin-registry.ts';\nimport type { IndexResult, StageProgressCallback } from '@/types.ts';\n\nimport { bumpVersion } from '@/db/metadata.ts';\nimport { isIndexable } from '@/plugin.ts';\nimport { saveAllHnsw } from '@/providers/vector/hnsw-loader.ts';\n\n/** Deps injected by BrainBank at init time. */\nexport interface IndexDeps {\n db: DatabaseAdapter;\n dbPath: string;\n sharedHnsw: Map<string, { hnsw: HNSWIndex; vecCache: Map<number, Float32Array> }>;\n kvHnsw: HNSWIndex;\n registry: PluginRegistry;\n emit: (event: string, data: unknown) => void;\n}\n\n/** Merge two `IndexResult` values, accumulating counts. */\nfunction mergeResult(acc: IndexResult | undefined, r: IndexResult): IndexResult {\n if (!acc) return { ...r };\n return {\n indexed: acc.indexed + r.indexed,\n skipped: acc.skipped + r.skipped,\n chunks: (acc.chunks ?? 0) + (r.chunks ?? 0),\n };\n}\n\n/** Run indexing across all indexable plugins. Filter with `modules` (base types). */\nexport async function runIndex(deps: IndexDeps, options: {\n modules?: string[];\n forceReindex?: boolean;\n onProgress?: StageProgressCallback;\n /** Plugin-specific options forwarded to `IndexablePlugin.index()`. */\n pluginOptions?: Record<string, unknown>;\n} = {}): Promise<Record<string, unknown>> {\n const want = options.modules ? new Set(options.modules) : null;\n const results: Record<string, unknown> = {};\n\n for (const mod of deps.registry.all) {\n const baseType = mod.name.split(':')[0];\n\n if (want && !want.has(baseType)) continue;\n if (!isIndexable(mod)) continue;\n\n const label = mod.name;\n options.onProgress?.(label, 'Starting...');\n\n const r = await mod.index({\n forceReindex: options.forceReindex,\n onProgress: (msg: string, cur: number, total: number) =>\n options.onProgress?.(label, `[${cur}/${total}] ${msg}`),\n ...options.pluginOptions,\n });\n\n results[baseType] = mergeResult(results[baseType] as IndexResult | undefined, r);\n\n // Bump version per plugin name (= HNSW key) so hot-reload resolves correctly.\n // In multi-repo setups the HNSW key is the full name (e.g. 'code:backend'),\n // not the base type ('code'). ensureFresh() matches against HNSW map keys.\n bumpVersion(deps.db, mod.name);\n }\n\n // Save HNSW indices with file locking after all plugins complete\n await saveAllHnsw(\n deps.dbPath,\n deps.kvHnsw,\n deps.sharedHnsw,\n new Map(),\n );\n\n deps.emit('indexed', results);\n return results;\n}\n","/**\n * BrainBank — Re-embedding Engine\n * \n * Regenerates all vectors without re-indexing.\n * Reads existing text from SQLite, embeds with the current provider,\n * and replaces vector BLOBs. No file I/O, no git parsing, no re-chunking.\n * \n * Usage:\n * const result = await brain.reembed({ onProgress });\n * // → { code: 1200, git: 500, docs: 80, kv: 45, total: 1837 }\n */\n\nimport type { DatabaseAdapter, CountRow, VectorRow } from '@/db/adapter.ts';\nimport type { Plugin, ReembedTable } from '@/plugin.ts';\nimport type { HNSWIndex } from '@/providers/vector/hnsw-index.ts';\nimport type { EmbeddingProvider, ProgressCallback } from '@/types.ts';\n\nimport { setEmbeddingMeta } from '@/db/metadata.ts';\nimport { vecToBuffer } from '@/lib/math.ts';\nimport { isReembeddable } from '@/plugin.ts';\nimport { saveAllHnsw } from '@/providers/vector/hnsw-loader.ts';\n\n\nconst CORE_TABLES: ReembedTable[] = [\n {\n name: 'kv',\n textTable: 'kv_data',\n vectorTable: 'kv_vectors',\n idColumn: 'id',\n fkColumn: 'data_id',\n textBuilder: (r) => String(r.content),\n },\n];\n\n/** Collect reembed tables from plugins + core. Deduplicates by vectorTable for multi-repo. */\nfunction collectTables(plugins: Plugin[]): ReembedTable[] {\n const byVectorTable = new Map<string, ReembedTable>();\n for (const p of plugins) {\n if (isReembeddable(p)) {\n const config = p.reembedConfig();\n byVectorTable.set(config.vectorTable, config);\n }\n }\n for (const t of CORE_TABLES) {\n byVectorTable.set(t.vectorTable, t);\n }\n return [...byVectorTable.values()];\n}\n\n\nexport interface ReembedResult {\n /** Per-table vector counts. Keys are table names (e.g. 'code', 'git', 'docs', 'kv'). */\n counts: Record<string, number>;\n total: number;\n}\n\nexport interface ReembedOptions {\n /** Progress callback: (tableName, current, total) */\n onProgress?: ProgressCallback;\n /** Batch size for embedBatch. Default: 50 */\n batchSize?: number;\n}\n\n\n/**\n * Re-embed all existing text with the current embedding provider.\n * Does NOT re-parse files, git, or documents — only replaces vectors.\n */\nexport async function reembedAll(\n db: DatabaseAdapter,\n embedding: EmbeddingProvider,\n hnswMap: Map<string, { hnsw: HNSWIndex; vecs: Map<number, Float32Array> }>,\n plugins: Plugin[],\n options: ReembedOptions = {},\n persist?: {\n dbPath: string;\n kvHnsw: HNSWIndex;\n sharedHnsw: Map<string, { hnsw: HNSWIndex; vecCache: Map<number, Float32Array> }>;\n },\n): Promise<ReembedResult> {\n const { batchSize = 50, onProgress } = options;\n const tables = collectTables(plugins);\n const counts: Record<string, number> = {};\n let total = 0;\n\n for (const table of tables) {\n // Skip tables that don't exist (plugin not installed)\n try {\n const textExists = (db.prepare(\n `SELECT COUNT(*) as c FROM sqlite_master WHERE type='table' AND name=?`\n ).get(table.textTable) as CountRow).c;\n const vecExists = (db.prepare(\n `SELECT COUNT(*) as c FROM sqlite_master WHERE type='table' AND name=?`\n ).get(table.vectorTable) as CountRow).c;\n if (!textExists || !vecExists) continue;\n } catch (e: unknown) {\n if (e instanceof Error && e.message.includes('no such table')) continue;\n throw e;\n }\n\n const count = await reembedTable(db, embedding, table, batchSize, onProgress);\n counts[table.name] = count;\n total += count;\n\n // Rebuild HNSW if available\n const entry = hnswMap.get(table.name);\n if (entry && count > 0) {\n await rebuildHnsw(db, table, entry.hnsw, entry.vecs);\n }\n }\n\n // Persist provider metadata + HNSW indexes to disk\n setEmbeddingMeta(db, embedding);\n if (persist) {\n saveAllHnsw(persist.dbPath, persist.kvHnsw, persist.sharedHnsw, new Map());\n }\n\n return {\n counts,\n total,\n };\n}\n\n/**\n * Re-embed a single table. Returns count of vectors regenerated.\n * \n * Streams per-batch to avoid OOM on large tables — memory stays O(batchSize).\n * Tradeoff: if embedBatch fails mid-way, partial vectors exist. Reembed is\n * a destructive operation by design — re-run to completion if interrupted.\n */\nasync function reembedTable(\n db: DatabaseAdapter,\n embedding: EmbeddingProvider,\n table: ReembedTable,\n batchSize: number,\n onProgress?: ProgressCallback,\n): Promise<number> {\n const totalCount = (db.prepare(\n `SELECT COUNT(*) as c FROM ${table.textTable}`\n ).get() as CountRow).c;\n\n if (totalCount === 0) return 0;\n\n // Phase 1: Build new vectors in a temp table (safe — old data untouched)\n const tempTable = `_reembed_${table.vectorTable}`;\n db.exec(`DROP TABLE IF EXISTS ${tempTable}`);\n db.exec(`CREATE TABLE ${tempTable} AS SELECT * FROM ${table.vectorTable} WHERE 0`);\n\n const insertTemp = db.prepare(\n `INSERT INTO ${tempTable} (${table.fkColumn}, embedding) VALUES (?, ?)`\n );\n\n let processed = 0;\n try {\n for (let offset = 0; offset < totalCount; offset += batchSize) {\n const batch = db.prepare(\n `SELECT * FROM ${table.textTable} LIMIT ? OFFSET ?`\n ).all(batchSize, offset) as Record<string, unknown>[];\n const texts = batch.map(r => table.textBuilder(r));\n const vectors = await embedding.embedBatch(texts);\n\n db.transaction(() => {\n for (let j = 0; j < batch.length; j++) {\n insertTemp.run(batch[j][table.idColumn], vecToBuffer(vectors[j]));\n }\n });\n\n processed += batch.length;\n onProgress?.(table.name, processed, totalCount);\n }\n\n // Phase 2: Atomic swap — all or nothing\n db.transaction(() => {\n db.exec(`DELETE FROM ${table.vectorTable}`);\n db.exec(`INSERT INTO ${table.vectorTable} SELECT * FROM ${tempTable}`);\n });\n } finally {\n // Always clean up temp table — even if embedBatch fails mid-batch\n db.exec(`DROP TABLE IF EXISTS ${tempTable}`);\n }\n\n return processed;\n}\n\n/** Rebuild HNSW index from vector table. */\nasync function rebuildHnsw(\n db: DatabaseAdapter,\n table: ReembedTable,\n hnsw: HNSWIndex,\n vecs: Map<number, Float32Array>,\n): Promise<void> {\n // Wipe stale vectors before repopulating\n vecs.clear();\n hnsw.reinit();\n\n const rows = db.prepare(\n `SELECT ${table.fkColumn} as id, embedding FROM ${table.vectorTable}`\n ).all() as VectorRow[];\n\n for (const row of rows) {\n const emb = row.embedding;\n const vec = new Float32Array(emb.buffer.slice(emb.byteOffset, emb.byteOffset + emb.byteLength));\n hnsw.add(vec, row.id);\n vecs.set(row.id, vec);\n }\n}\n","/**\n * BrainBank — Search API\n *\n * Thin orchestrator for all search operations.\n * Pipeline: collect → fuse (RRF) → rerank.\n *\n * Plugin-agnostic — discovers vector strategies and searchable plugins\n * via capability interfaces. No hardcoded plugin names.\n */\n\nimport type { DatabaseAdapter } from '@/db/adapter.ts';\nimport type { HNSWIndex } from '@/providers/vector/hnsw-index.ts';\nimport type { SearchStrategy, SearchOptions, DomainVectorSearch } from '@/search/types.ts';\nimport type { KVService } from '@/services/kv-service.ts';\nimport type { PluginRegistry } from '@/services/plugin-registry.ts';\nimport type { ResolvedConfig, EmbeddingProvider, SearchResult, ContextOptions } from '@/types.ts';\n\nimport { isVectorSearchPlugin, isSearchable, isCoEditPlugin, isContextFormatterPlugin } from '@/plugin.ts';\nimport { rerank } from '@/lib/rerank.ts';\nimport { reciprocalRankFusion } from '@/lib/rrf.ts';\nimport { ContextBuilder } from '@/search/context-builder.ts';\nimport { CompositeBM25Search } from '@/search/keyword/composite-bm25-search.ts';\nimport { CompositeVectorSearch } from '@/search/vector/composite-vector-search.ts';\nimport { logQuery } from '@/lib/logger.ts';\nimport type { QueryLogResult } from '@/lib/logger.ts';\nimport { providerKey } from '@/lib/provider-key.ts';\n\n/** Dependencies injected at construction time. */\nexport interface SearchAPIDeps {\n search?: SearchStrategy;\n bm25?: SearchStrategy;\n registry: PluginRegistry;\n config: ResolvedConfig;\n kvService: KVService;\n contextBuilder?: ContextBuilder;\n embedding: EmbeddingProvider;\n}\n\n/**\n * Build a fully-wired SearchAPI from registry state.\n * Discovers vector strategies from VectorSearchPlugin capability.\n * Always returns an instance — handles search-less setups internally.\n */\nexport function createSearchAPI(\n _db: DatabaseAdapter,\n embedding: EmbeddingProvider,\n config: ResolvedConfig,\n registry: PluginRegistry,\n kvService: KVService,\n sharedHnsw: Map<string, { hnsw: HNSWIndex; vecCache: Map<number, Float32Array> }>,\n): SearchAPI {\n const strategies = new Map<string, DomainVectorSearch>();\n\n for (const mod of registry.all) {\n if (isVectorSearchPlugin(mod)) {\n const vs = mod.createVectorSearch();\n if (vs) {\n // Use full plugin name (e.g. code:servicehub-backend)\n // so each repo gets its own vector search strategy\n strategies.set(mod.name, vs);\n }\n }\n }\n\n const search = strategies.size > 0\n ? new CompositeVectorSearch({\n strategies,\n embedding,\n })\n : undefined;\n\n const bm25 = new CompositeBM25Search(registry);\n\n const rerankerName = config.reranker ? (config.reranker.constructor?.name ?? 'custom') : undefined;\n const contextBuilder = new ContextBuilder(search, registry, config.pruner, embedding, rerankerName, config.contextFields ?? {}, config.expander);\n\n return new SearchAPI({\n search, bm25, registry, config,\n kvService, contextBuilder, embedding,\n });\n}\n\n\nexport class SearchAPI {\n constructor(private _d: SearchAPIDeps) {}\n\n /** Build formatted context block for LLM injection. */\n async getContext(task: string, options: ContextOptions = {}): Promise<string> {\n if (!this._d.contextBuilder) return '';\n return this._d.contextBuilder.build(task, options);\n }\n\n /** Semantic search across all loaded modules. */\n async search(query: string, options?: SearchOptions): Promise<SearchResult[]> {\n const t0 = Date.now();\n const lists: SearchResult[][] = [];\n\n if (this._d.search) {\n lists.push(await this._d.search.search(query, options));\n }\n\n lists.push(...await this._collectSearchablePlugins(query, options));\n\n let results: SearchResult[];\n if (lists.length === 0) results = [];\n else if (lists.length === 1) results = lists[0];\n else results = reciprocalRankFusion(lists);\n\n this._logSearch('search', query, options, results, Date.now() - t0);\n return results;\n }\n\n /** Hybrid search: vector + BM25 → RRF. */\n async hybridSearch(query: string, options?: SearchOptions): Promise<SearchResult[]> {\n const t0 = Date.now();\n const src = options?.sources ?? {};\n const lists: SearchResult[][] = [];\n\n if (this._d.search) {\n const [vec, kw] = await Promise.all([\n this._d.search.search(query, options),\n Promise.resolve(this._d.bm25?.search(query, options) ?? []),\n ]);\n lists.push(vec, kw);\n }\n\n lists.push(...await this._collectSearchablePlugins(query, options));\n lists.push(...await this._collectKvCollections(query, src));\n\n let results: SearchResult[];\n if (lists.length === 0) results = [];\n else {\n const fused = reciprocalRankFusion(lists);\n if (this._d.config.reranker && fused.length > 1) {\n results = await rerank(query, fused, this._d.config.reranker);\n } else {\n results = fused;\n }\n }\n\n this._logSearch('hybridSearch', query, options, results, Date.now() - t0);\n return results;\n }\n\n /** BM25 keyword search only. */\n async searchBM25(query: string, options?: SearchOptions): Promise<SearchResult[]> {\n const t0 = Date.now();\n const results = await this._d.bm25?.search(query, options) ?? [];\n this._logSearch('searchBM25', query, options, results, Date.now() - t0);\n return results;\n }\n\n /** Rebuild FTS5 indices. */\n rebuildFTS(): void {\n this._d.bm25?.rebuild?.();\n }\n\n /** Collect results from all SearchablePlugins (docs, custom). */\n private async _collectSearchablePlugins(\n query: string, options?: SearchOptions,\n ): Promise<SearchResult[][]> {\n const lists: SearchResult[][] = [];\n for (const mod of this._d.registry.all) {\n if (!isSearchable(mod)) continue;\n // Skip plugins that already participate via VectorSearchPlugin\n if (isVectorSearchPlugin(mod)) continue;\n const hits = await mod.search(query, options ? { ...options } : undefined);\n if (hits.length > 0) lists.push(hits);\n }\n return lists;\n }\n\n /** Collect results from KV collections named in sources. */\n private async _collectKvCollections(\n query: string, sources: Record<string, number>,\n ): Promise<SearchResult[][]> {\n const pluginNames = new Set(this._d.registry.names.map(n => n.split(':')[0]));\n const lists: SearchResult[][] = [];\n for (const [name, k] of Object.entries(sources)) {\n if (pluginNames.has(name)) continue;\n const hits = await this._d.kvService.collection(name).searchAsResults(query, k);\n if (hits.length > 0) lists.push(hits);\n }\n return lists;\n }\n\n /** Log a search/hybridSearch/searchBM25 call. */\n private _logSearch(\n method: 'search' | 'hybridSearch' | 'searchBM25',\n query: string,\n options: SearchOptions | undefined,\n results: SearchResult[],\n durationMs: number,\n ): void {\n logQuery({\n source: options?.source ?? 'api',\n method,\n query,\n embedding: providerKey(this._d.embedding),\n pruner: null,\n reranker: this._d.config.reranker ? (this._d.config.reranker.constructor?.name ?? 'custom') : null,\n options: {\n sources: options?.sources,\n minScore: options?.minScore,\n },\n results: results.map(_toLogResult),\n durationMs,\n });\n }\n}\n\n// ── Helpers ──────────────────────────────────────────\n\nfunction _toLogResult(r: SearchResult): QueryLogResult {\n const meta = r.metadata as Record<string, unknown> | undefined;\n return {\n filePath: r.filePath ?? 'unknown',\n score: r.score,\n type: r.type,\n name: (meta?.name as string | undefined) ?? undefined,\n };\n}\n","/**\n * BrainBank — Plugin Registry\n *\n * Manages registration and lookup of plugins.\n * Extracted from BrainBank so the facade stays focused on orchestration.\n *\n * Responsibilities:\n * - Store plugins by name\n * - Type-prefix matching ('code' finds 'code:frontend', 'code:backend')\n * - Alias resolution (currently none; add here if needed)\n * - Consistent error messages on missing plugins\n */\n\nimport type { Plugin } from '@/plugin.ts';\n\n/** Shorthand aliases that map public names to canonical plugin names. */\nconst ALIASES: Readonly<Record<string, string>> = {\n};\n\nexport class PluginRegistry {\n private _map = new Map<string, Plugin>();\n\n\n /** Store a plugin. Duplicate names silently overwrite. */\n register(plugin: Plugin): void {\n this._map.set(plugin.name, plugin);\n }\n\n\n /**\n * Check whether a plugin is registered.\n * Supports type-prefix matching: `has('code')` returns true if\n * 'code', 'code:frontend', or 'code:backend' is registered.\n */\n has(name: string): boolean {\n if (this._map.has(name)) return true;\n for (const key of this._map.keys()) {\n if (key.startsWith(name + ':')) return true;\n }\n return false;\n }\n\n /**\n * Get a plugin by name. Throws a descriptive error if not found.\n *\n * Resolution order:\n * 1. Alias map (currently empty)\n * 2. Exact match\n * 3. First type-prefix match ('code' → 'code:frontend')\n */\n get<T extends Plugin = Plugin>(name: string): T {\n const resolved = ALIASES[name] ?? name;\n\n const exact = this._map.get(resolved);\n if (exact) return exact as T;\n\n const prefixed = this.firstByType(name);\n if (prefixed) return prefixed as T;\n\n throw new Error(\n `BrainBank: Plugin '${name}' is not loaded. ` +\n `Add .use(${name}()) to your BrainBank instance.`,\n );\n }\n\n /**\n * Return every plugin whose name equals `type` or starts with `type + ':'`.\n * Example: allByType('code') → [code, code:frontend, code:backend]\n */\n allByType(type: string): Plugin[] {\n return [...this._map.values()].filter(\n m => m.name === type || m.name.startsWith(type + ':'),\n );\n }\n\n /** Return the first plugin that matches the type prefix, or undefined. */\n firstByType(type: string): Plugin | undefined {\n for (const m of this._map.values()) {\n if (m.name === type || m.name.startsWith(type + ':')) return m;\n }\n return undefined;\n }\n\n\n /** All registered plugin names (insertion order). */\n get names(): string[] {\n return [...this._map.keys()];\n }\n\n /** All registered plugin instances (insertion order). */\n get all(): Plugin[] {\n return [...this._map.values()];\n }\n\n /**\n * Underlying Map.\n * Prefer `all`, `allByType`, or `firstByType` everywhere else.\n */\n get raw(): Map<string, Plugin> {\n return this._map;\n }\n\n\n /** Remove all registered plugins. Called by BrainBank.close(). */\n clear(): void {\n this._map.clear();\n }\n}\n\n","/**\n * BrainBank CLI — Shared Utilities\n *\n * Colors, argument parsing, result formatting, and plugin discovery.\n */\n\nimport type { BrainBank } from '@/brainbank.ts';\nimport type { DocsPlugin } from '@/plugin.ts';\nimport type { SearchResult } from '@/types.ts';\n\nimport { isDocsPlugin } from '@/plugin.ts';\n\nexport const c = {\n green: (s: string) => `\\x1b[32m${s}\\x1b[0m`,\n red: (s: string) => `\\x1b[31m${s}\\x1b[0m`,\n yellow: (s: string) => `\\x1b[33m${s}\\x1b[0m`,\n cyan: (s: string) => `\\x1b[36m${s}\\x1b[0m`,\n dim: (s: string) => `\\x1b[2m${s}\\x1b[0m`,\n bold: (s: string) => `\\x1b[1m${s}\\x1b[0m`,\n magenta: (s: string) => `\\x1b[35m${s}\\x1b[0m`,\n};\n\n\n/** Raw argv, sliced past the Node binary and script path. */\nexport const args = process.argv.slice(2);\n\nexport function getFlag(name: string): string | undefined {\n const idx = args.indexOf(`--${name}`);\n return idx >= 0 ? args[idx + 1] : undefined;\n}\n\n/** Collect all values for a repeated flag (--ignore a --ignore b) or comma-separated (--ignore a,b). */\nexport function getFlagAll(name: string): string[] {\n const values: string[] = [];\n const flag = `--${name}`;\n for (let i = 0; i < args.length; i++) {\n if (args[i] === flag && args[i + 1] && !args[i + 1].startsWith('--')) {\n for (const v of args[i + 1].split(',')) {\n const trimmed = v.trim();\n if (trimmed) values.push(trimmed);\n }\n i++;\n }\n }\n return values;\n}\n\nexport function hasFlag(name: string): boolean {\n return args.includes(`--${name}`);\n}\n\n/** Known flags that take a value (--flag <value>). */\nconst VALUE_FLAGS = new Set([\n 'repo', 'depth', 'collection', 'pattern', 'context', 'name',\n 'keep', 'reranker', 'pruner', 'only', 'docs', 'path',\n 'ignore', 'meta', 'k', 'mode', 'limit',\n]);\n\n/**\n * Strip all --flags AND their values from an argv slice.\n * Returns only positional arguments.\n *\n * Handles:\n * - Known VALUE_FLAGS: --repo /path → skip both\n * - Dynamic source flags: --code 10 → skip both (any --name <number>)\n * - Boolean flags: --force, --yes → skip flag only\n *\n * stripFlags(['ksearch', 'auth', '--repo', '/path', '--code', '10'])\n * → ['ksearch', 'auth']\n */\nexport function stripFlags(argv: string[]): string[] {\n const result: string[] = [];\n for (let i = 0; i < argv.length; i++) {\n if (argv[i].startsWith('--')) {\n const name = argv[i].slice(2);\n const next = argv[i + 1];\n // Known value flag or dynamic numeric value → skip both\n if (next !== undefined && !next.startsWith('--')) {\n if (VALUE_FLAGS.has(name) || /^\\d+$/.test(next)) {\n i++; // skip the value\n }\n }\n continue;\n }\n result.push(argv[i]);\n }\n return result;\n}\n\n\nexport function printResults(results: SearchResult[], minScore = 0.70): void {\n const filtered = results.filter(r => r.score >= minScore).slice(0, 20);\n\n if (filtered.length === 0) {\n console.log(c.yellow(` No results above ${Math.round(minScore * 100)}% score.`));\n return;\n }\n\n for (const r of filtered) {\n const score = Math.round(r.score * 100);\n\n if (r.type === 'code') {\n const m = r.metadata;\n console.log(\n `${c.green(`[CODE ${score}%]`)} ${c.bold(r.filePath!)} — ` +\n `${m.name || m.chunkType} ${c.dim(`L${m.startLine}-${m.endLine}`)}`,\n );\n console.log(c.dim(r.content.split('\\n').slice(0, 5).join('\\n')));\n console.log('');\n } else if (r.type === 'commit') {\n const m = r.metadata;\n console.log(\n `${c.cyan(`[COMMIT ${score}%]`)} ${c.bold(m.shortHash)} ` +\n `${r.content} ${c.dim(`(${m.author})`)}`,\n );\n if (m.files?.length) console.log(c.dim(` Files: ${m.files.slice(0, 4).join(', ')}`));\n console.log('');\n } else if (r.type === 'document') {\n const ctx = r.context ? ` — ${c.dim(r.context)}` : '';\n console.log(\n `${c.magenta(`[DOC ${score}%]`)} ${c.bold(r.filePath!)} ` +\n `[${r.metadata.collection}]${ctx}`,\n );\n console.log(c.dim(r.content.split('\\n').slice(0, 4).join('\\n')));\n console.log('');\n }\n }\n}\n\n/** Discover the first plugin that implements DocsPlugin by capability. */\nexport function findDocsPlugin(brain: BrainBank): DocsPlugin | undefined {\n for (const name of brain.plugins) {\n const p = brain.plugin(name);\n if (p && isDocsPlugin(p)) return p;\n }\n return undefined;\n}\n","/**\n * BrainBank — Brain Context\n *\n * Portable input for `createBrain()`. Decouples the factory from\n * `process.argv` / `process.env` so it can be called from the CLI,\n * MCP server, tests, or any programmatic consumer.\n */\n\nimport { getFlag } from '../utils.ts';\n\n/** Everything the factory needs to build a BrainBank instance. */\nexport interface BrainContext {\n /** Repository root path. */\n repoPath: string;\n /** Environment variable overrides. Falls back to `process.env`. */\n env?: Record<string, string | undefined>;\n /** CLI flag overrides (e.g. `{ ignore: 'dist,vendor' }`). */\n flags?: Record<string, string | undefined>;\n}\n\n/** Build a `BrainContext` from CLI argv + process.env. */\nexport function contextFromCLI(repoPath?: string): BrainContext {\n return {\n repoPath: repoPath ?? getFlag('repo') ?? '.',\n env: process.env as Record<string, string | undefined>,\n flags: {\n ignore: getFlag('ignore'),\n reranker: getFlag('reranker'),\n pruner: getFlag('pruner'),\n embedding: getFlag('embedding'),\n },\n };\n}\n\n/** Read a flag from context, falling back to process.env equivalent. */\nexport function ctxFlag(ctx: BrainContext, name: string): string | undefined {\n return ctx.flags?.[name];\n}\n\n/** Read an env var from context, falling back to process.env. */\nexport function ctxEnv(ctx: BrainContext, name: string): string | undefined {\n return ctx.env?.[name] ?? process.env[name];\n}\n","/**\n * BrainBank CLI — Plugin Registration\n *\n * Generic plugin registration with multi-repo detection\n * and per-plugin config resolution. No hardcoded plugin names.\n */\n\nimport type { BrainBank } from '@/brainbank.ts';\nimport type { DocumentCollection } from '@/types.ts';\nimport type { ProjectConfig } from './config-loader.ts';\n\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { c } from '../utils.ts';\nimport { loadPlugin, isMultiRepoCapable, resolveEmbeddingKey } from './plugin-loader.ts';\n\n/** Read a nested property from a generic config section. */\nfunction pluginCfg(config: ProjectConfig | null, pluginName: string): Record<string, unknown> {\n const section = config?.[pluginName];\n if (section && typeof section === 'object' && !Array.isArray(section)) {\n return section as Record<string, unknown>;\n }\n return {};\n}\n\n/** Detect subdirectories that have their own .git repo. Respects optional `repos` whitelist. */\nfunction detectGitSubdirs(parentPath: string, repos?: string[]): { name: string; path: string }[] {\n try {\n const entries = fs.readdirSync(parentPath, { withFileTypes: true });\n let subdirs = entries\n .filter(e => {\n if (e.name.startsWith('.') || e.name.startsWith('node_modules')) return false;\n // Follow symlinks: isDirectory() is false for symlinks, so check via statSync\n const isDir = e.isDirectory() || (e.isSymbolicLink() && fs.statSync(path.join(parentPath, e.name)).isDirectory());\n return isDir && fs.existsSync(path.join(parentPath, e.name, '.git'));\n })\n .map(e => ({ name: e.name, path: path.join(parentPath, e.name) }));\n\n if (repos && repos.length > 0) {\n const allowed = new Set(repos);\n subdirs = subdirs.filter(s => allowed.has(s.name));\n }\n\n return subdirs;\n } catch { return []; }\n}\n\n/** Register plugins with multi-repo detection and per-plugin config. */\nexport async function registerBuiltins(\n brain: BrainBank, rp: string, pluginNames: string[],\n config: ProjectConfig | null, ignorePatterns: string[] = [],\n): Promise<void> {\n const resolvedRp = path.resolve(rp);\n const hasRootGit = fs.existsSync(path.join(resolvedRp, '.git'));\n const configRepos = config?.repos as string[] | undefined;\n const gitSubdirs = !hasRootGit ? detectGitSubdirs(resolvedRp, configRepos) : [];\n\n for (const name of pluginNames) {\n const factory = await loadPlugin(name);\n if (!factory) {\n console.error(c.yellow(` ⚠ @brainbank/${name} not installed — skipping ${name} indexing`));\n console.error(c.dim(` Install: npm i -g @brainbank/${name}`));\n continue;\n }\n\n const cfg = pluginCfg(config, name);\n\n // Resolve per-plugin embedding if configured\n const embKey = cfg.embedding as string | undefined;\n const embeddingProvider = embKey ? await resolveEmbeddingKey(embKey) : undefined;\n\n // Multi-repo: create one plugin instance per git subdir\n if (gitSubdirs.length > 0 && isMultiRepoCapable(name)) {\n console.error(c.cyan(` Multi-repo: found ${gitSubdirs.length} git repos: ${gitSubdirs.map(d => d.name).join(', ')}`));\n for (const sub of gitSubdirs) {\n const mergedIgnore = [...(cfg.ignore as string[] ?? []), ...ignorePatterns];\n brain.use(factory({\n ...cfg,\n repoPath: sub.path,\n name: `${name}:${sub.name}`,\n embeddingProvider,\n ignore: mergedIgnore.length > 0 ? mergedIgnore : undefined,\n }));\n }\n } else {\n // Single repo: merge ignore patterns for plugins that support them\n const configIgnore = cfg.ignore as string[] | undefined ?? [];\n const mergedIgnore = [...configIgnore, ...ignorePatterns];\n\n brain.use(factory({\n ...cfg,\n repoPath: rp,\n embeddingProvider,\n ignore: mergedIgnore.length > 0 ? mergedIgnore : undefined,\n }));\n }\n }\n}\n\n/** Register doc collections from config. Call after brain.initialize(). */\nexport async function registerConfigCollections(brain: BrainBank, rp: string, config: ProjectConfig | null): Promise<void> {\n const docsCfg = pluginCfg(config, 'docs');\n const collections = docsCfg.collections as DocumentCollection[] | undefined;\n if (!collections?.length) return;\n\n const { isDocsPlugin } = await import('@/plugin.ts');\n const rawPlugin = brain.plugin('docs');\n if (!rawPlugin || !isDocsPlugin(rawPlugin)) return;\n\n const repoPath = path.resolve(rp);\n for (const coll of collections) {\n const absPath = path.resolve(repoPath, coll.path);\n try {\n await rawPlugin.addCollection({\n name: coll.name, path: absPath,\n pattern: coll.pattern ?? '**/*.md', ignore: coll.ignore, context: coll.context,\n });\n } catch (e: unknown) {\n if (!(e instanceof Error && e.message.includes('already'))) throw e;\n // Collection already registered — skip\n }\n }\n}\n","/**\n * BrainBank CLI — Plugin Loader\n *\n * Generic plugin loader registry with dynamic @brainbank/* package loading\n * and auto-discovery of user plugins from .brainbank/plugins/.\n */\n\nimport type { Plugin } from '@/plugin.ts';\nimport type { EmbeddingProvider } from '@/types.ts';\nimport type { ProjectConfig } from './config-loader.ts';\n\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { c } from '../utils.ts';\n\n/** Plugin factory — accepts config, returns Plugin. */\ntype PluginFactory = (opts: Record<string, unknown>) => Plugin;\n\n/** Loader function: dynamically imports a package and returns its factory. */\ntype PluginLoaderFn = () => Promise<PluginFactory | null>;\n\n/** Built-in plugin loader registry. Extensible at runtime. */\nconst PLUGIN_LOADERS = new Map<string, PluginLoaderFn>([\n ['code', async () => { try { return (await import('@brainbank/code')).code as PluginFactory; } catch { return null; } }],\n ['git', async () => { try { return (await import('@brainbank/git')).git as PluginFactory; } catch { return null; } }],\n ['docs', async () => { try { return (await import('@brainbank/docs')).docs as PluginFactory; } catch { return null; } }],\n]);\n\n/** Plugins that support multi-repo mode (one instance per git subdir). */\nconst MULTI_REPO_PLUGINS = new Set(['code', 'git']);\n\n/** Load a plugin factory by name. Returns null if not installed. */\nexport async function loadPlugin(name: string): Promise<PluginFactory | null> {\n const loader = PLUGIN_LOADERS.get(name);\n if (!loader) return null;\n return loader();\n}\n\n/** Register a custom plugin loader. */\nexport function registerPluginLoader(name: string, loader: PluginLoaderFn): void {\n PLUGIN_LOADERS.set(name, loader);\n}\n\n/** Check if a plugin supports multi-repo mode. */\nexport function isMultiRepoCapable(name: string): boolean {\n return MULTI_REPO_PLUGINS.has(name);\n}\n\nconst INDEXER_EXTENSIONS = ['.ts', '.js', '.mjs'];\nconst NOT_LOADED = Symbol('not-loaded');\nlet _folderPluginsCache: Plugin[] | typeof NOT_LOADED = NOT_LOADED;\n\n/** Auto-discover plugins from .brainbank/plugins/ folder. */\nexport async function discoverFolderPlugins(repoPath: string): Promise<Plugin[]> {\n if (_folderPluginsCache !== NOT_LOADED) return _folderPluginsCache;\n\n const pluginsDir = path.resolve(repoPath, '.brainbank', 'plugins');\n\n if (!fs.existsSync(pluginsDir)) {\n _folderPluginsCache = [];\n return [];\n }\n\n const files = fs.readdirSync(pluginsDir)\n .filter(f => INDEXER_EXTENSIONS.some(ext => f.endsWith(ext)))\n .sort();\n\n const plugins: Plugin[] = [];\n\n for (const file of files) {\n const filePath = path.join(pluginsDir, file);\n try {\n const mod = await import(filePath);\n const plugin = mod.default ?? mod;\n\n if (plugin && typeof plugin === 'object' && plugin.name) {\n plugins.push(plugin as Plugin);\n } else {\n console.error(c.yellow(`⚠ ${file}: must export a default Plugin with a 'name' property, skipping`));\n }\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n console.error(c.red(`Error loading plugin ${file}: ${message}`));\n }\n }\n\n _folderPluginsCache = plugins;\n return plugins;\n}\n\n/** Reset folder plugins cache. Useful for tests. */\nexport function resetPluginCache(): void {\n _folderPluginsCache = NOT_LOADED;\n}\n\n/** Resolve an embedding key string to an EmbeddingProvider instance. */\nexport async function resolveEmbeddingKey(key: string): Promise<EmbeddingProvider> {\n const { resolveEmbedding } = await import('@/providers/embeddings/resolve.ts');\n return resolveEmbedding(key);\n}\n\n/** Configure reranker and global embedding provider on brainOpts. */\nexport async function setupProviders(\n brainOpts: Record<string, unknown>,\n config: ProjectConfig | null,\n flags?: Record<string, string | undefined>,\n env?: Record<string, string | undefined>,\n): Promise<void> {\n // Resolve API keys: config.keys > env vars\n const keys = config?.keys ?? {};\n const anthropicKey = keys.anthropic || process.env.ANTHROPIC_API_KEY;\n const perplexityKey = keys.perplexity || process.env.PERPLEXITY_API_KEY;\n const openaiKey = keys.openai || process.env.OPENAI_API_KEY;\n\n // Inject resolved keys into process.env so downstream providers auto-detect them\n if (anthropicKey) process.env.ANTHROPIC_API_KEY = anthropicKey;\n if (perplexityKey) process.env.PERPLEXITY_API_KEY = perplexityKey;\n if (openaiKey) process.env.OPENAI_API_KEY = openaiKey;\n\n const rerankerFlag = flags?.reranker ?? (config?.reranker as string | undefined);\n if (rerankerFlag === 'qwen3') {\n const { Qwen3Reranker } = await import('@/providers/rerankers/qwen3-reranker.ts');\n brainOpts.reranker = new Qwen3Reranker();\n }\n\n const prunerFlag = flags?.pruner ?? (config?.pruner as string | undefined);\n if (prunerFlag === 'haiku') {\n const { HaikuPruner } = await import('@/providers/pruners/haiku-pruner.ts');\n brainOpts.pruner = new HaikuPruner({ apiKey: anthropicKey });\n }\n\n // Expander: explicit opt-in only (config.json `expander: \"haiku\"` or --expander flag)\n const expanderFlag = flags?.expander ?? (config?.expander as string | undefined);\n if (expanderFlag === 'haiku') {\n try {\n const { HaikuExpander } = await import('@/providers/pruners/haiku-expander.ts');\n brainOpts.expander = new HaikuExpander({ apiKey: anthropicKey });\n } catch {\n // Fail-open: if API key missing, skip expander silently\n }\n }\n\n const embFlag = flags?.embedding\n ?? (config?.embedding as string | undefined)\n ?? env?.BRAINBANK_EMBEDDING\n ?? process.env.BRAINBANK_EMBEDDING;\n if (embFlag) {\n const provider = await resolveEmbeddingKey(embFlag);\n brainOpts.embeddingProvider = provider;\n brainOpts.embeddingDims = provider.dims;\n }\n\n // Context field defaults from config.json \"context\" section\n if (config?.context) {\n brainOpts.contextFields = config.context;\n }\n}\n","/**\n * BrainBank CLI — Config Loader\n *\n * Loads .brainbank/config.json (or .ts/.js/.mjs fallback).\n * Config priority: CLI flags > config file > defaults.\n */\n\nimport type { Plugin } from '@/plugin.ts';\nimport type { BrainBankConfig, DocumentCollection } from '@/types.ts';\n\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { c } from '../utils.ts';\n\n/** Full .brainbank/config.json schema. */\nexport interface ProjectConfig {\n plugins?: string[];\n embedding?: string;\n reranker?: string;\n pruner?: string;\n maxFileSize?: number;\n indexers?: Plugin[];\n brainbank?: Partial<BrainBankConfig>;\n /** Optional API keys — override env vars. Kept out of version control. */\n keys?: {\n anthropic?: string;\n perplexity?: string;\n openai?: string;\n };\n /** Context field defaults (e.g. { lines: true, callTree: true, symbols: false }). */\n context?: Record<string, unknown>;\n /** Per-plugin config sections (e.g. code, git, docs). */\n [pluginName: string]: unknown;\n}\n\nconst CONFIG_NAMES = ['config.json', 'config.ts', 'config.js', 'config.mjs'];\nconst NOT_LOADED = Symbol('not-loaded');\nlet _configCache: ProjectConfig | null | typeof NOT_LOADED = NOT_LOADED;\n\n/** Load .brainbank/config.json (or .ts fallback) if present. */\nexport async function loadConfig(repoPath: string): Promise<ProjectConfig | null> {\n if (_configCache !== NOT_LOADED) return _configCache;\n\n const brainbankDir = path.resolve(repoPath, '.brainbank');\n\n for (const name of CONFIG_NAMES) {\n const configPath = path.join(brainbankDir, name);\n if (!fs.existsSync(configPath)) continue;\n\n try {\n if (name === 'config.json') {\n const raw = fs.readFileSync(configPath, 'utf-8');\n _configCache = JSON.parse(raw) as ProjectConfig;\n } else {\n const mod = await import(configPath);\n _configCache = (mod.default ?? mod) as ProjectConfig;\n }\n return _configCache;\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n console.error(c.red(`Error loading .brainbank/${name}: ${message}`));\n process.exit(1);\n }\n }\n\n _configCache = null;\n return null;\n}\n\n/** Get the loaded config (for use by commands). */\nexport async function getConfig(repoPath?: string): Promise<ProjectConfig | null> {\n return loadConfig(repoPath ?? '.');\n}\n\n/** Reset config cache. Useful for tests. */\nexport function resetConfigCache(): void {\n _configCache = NOT_LOADED;\n}\n","/**\n * BrainBank CLI — Brain Factory\n *\n * Creates a configured BrainBank instance with dynamically loaded plugins,\n * auto-discovered indexers, and config file support.\n * Delegates to focused modules in factory/.\n */\n\nimport type { Plugin } from '@/plugin.ts';\nimport type { BrainBankConfig } from '@/types.ts';\nimport type { BrainContext } from './brain-context.ts';\n\nimport { BrainBank } from '@/brainbank.ts';\nimport { contextFromCLI, ctxFlag, ctxEnv } from './brain-context.ts';\nimport { registerBuiltins, registerConfigCollections } from './builtin-registration.ts';\nimport { loadConfig, getConfig, resetConfigCache } from './config-loader.ts';\nimport { discoverFolderPlugins, resetPluginCache, setupProviders } from './plugin-loader.ts';\n\nexport type { ProjectConfig } from './config-loader.ts';\nexport type { BrainContext } from './brain-context.ts';\nexport { contextFromCLI } from './brain-context.ts';\nexport { getConfig, registerConfigCollections };\n\n/** Reset factory caches. Useful for tests. */\nexport function resetFactoryCache(): void {\n resetConfigCache();\n resetPluginCache();\n}\n\n/**\n * Create a BrainBank with built-in + discovered + config plugins.\n *\n * Accepts either a `BrainContext` (for programmatic use) or an optional\n * `repoPath` string (for CLI backward compat — builds context from argv).\n */\nexport async function createBrain(contextOrRepo?: BrainContext | string): Promise<BrainBank> {\n const ctx: BrainContext = typeof contextOrRepo === 'string'\n ? contextFromCLI(contextOrRepo)\n : contextOrRepo ?? contextFromCLI();\n\n const rp = ctx.repoPath;\n const config = await loadConfig(rp);\n const folderPlugins = await discoverFolderPlugins(rp);\n\n const brainOpts: Partial<BrainBankConfig> & Record<string, unknown> = { repoPath: rp, ...(config?.brainbank ?? {}) };\n if (config?.maxFileSize) brainOpts.maxFileSize = config.maxFileSize as number;\n await setupProviders(brainOpts, config, ctx.flags, ctx.env);\n\n const brain = new BrainBank(brainOpts);\n const builtins = config?.plugins ?? ['code', 'git', 'docs'];\n\n // Merge ignore patterns from context flags\n const ignoreFlag = ctxFlag(ctx, 'ignore');\n const ignorePatterns = ignoreFlag ? ignoreFlag.split(',').map(s => s.trim()) : [];\n\n await registerBuiltins(brain, rp, builtins, config, ignorePatterns);\n\n for (const plugin of folderPlugins) brain.use(plugin);\n\n if (config?.indexers) {\n for (const plugin of config.indexers as Plugin[]) brain.use(plugin);\n }\n\n return brain;\n}\n"],"mappings":"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","names":["require","path","existsSync","mkdirSync","join","lockDir","join","existsSync","mkdirSync","fs","existsSync","HNSW","path","existsSync","path","path","fs","path","path","path","dirname","join","join","dirname","_toLogResult","fs","path","fs","path","resolveEmbedding","isDocsPlugin","fs","path","NOT_LOADED"]}
|