brainbank 0.3.1 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -8,7 +8,7 @@ BrainBank gives LLMs a long-term memory that persists between sessions.
8
8
  - **Pluggable indexers** — `.use()` only what you need (code, git, docs, or custom)
9
9
  - **Dynamic collections** — `brain.collection('errors')` for any structured data
10
10
  - **Hybrid search** — vector + BM25 fused with Reciprocal Rank Fusion
11
- - **Pluggable embeddings** — local WASM (free) or OpenAI (higher quality)
11
+ - **Pluggable embeddings** — local WASM (free), OpenAI, or Perplexity (standard & contextualized)
12
12
  - **Multi-repo** — index multiple repositories into one shared database
13
13
  - **Portable** — single `.brainbank/brainbank.db` file
14
14
  - **Optional packages** — [`@brainbank/memory`](#memory) (fact extraction + entity graph), [`@brainbank/reranker`](#reranker) (Qwen3 cross-encoder), [`@brainbank/mcp`](#mcp-server) (MCP server)
@@ -628,7 +628,7 @@ Add to your MCP config (`~/.gemini/antigravity/mcp_config.json` or Claude Deskto
628
628
 
629
629
  The agent passes the `repo` parameter on each tool call based on the active workspace — no hardcoded paths needed.
630
630
 
631
- > Set `BRAINBANK_EMBEDDING` to `openai` for higher quality search (requires `OPENAI_API_KEY`). Omit to use the free local WASM embeddings.
631
+ > Set `BRAINBANK_EMBEDDING` to `openai`, `perplexity`, or `perplexity-context` for higher quality search. Omit to use the free local WASM embeddings.
632
632
 
633
633
  > Optionally set `BRAINBANK_REPO` as a default fallback repo. If omitted, every tool call must include the `repo` parameter (recommended for multi-workspace setups).
634
634
 
@@ -642,7 +642,7 @@ The agent passes the `repo` parameter on each tool call based on the active work
642
642
  > 2. MCP server starts without `BRAINBANK_EMBEDDING` env var → defaults to local (384 dims)
643
643
  > 3. **Result:** BrainBank throws `Embedding dimension mismatch` on every search
644
644
  >
645
- > **Fix:** Always set `BRAINBANK_EMBEDDING` consistently in your MCP config, CLI, and API usage. If you indexed with OpenAI, your MCP config **must** include `"BRAINBANK_EMBEDDING": "openai"`. If you switch providers, run `brainbank reembed` to regenerate all vectors.
645
+ > **Fix:** Always set `BRAINBANK_EMBEDDING` consistently in your MCP config, CLI, and API usage. If you indexed with OpenAI, your MCP config **must** include `"BRAINBANK_EMBEDDING": "openai"`. Same for `perplexity` or `perplexity-context`. If you switch providers, run `brainbank reembed` to regenerate all vectors.
646
646
 
647
647
  ### Available Tools
648
648
 
@@ -686,22 +686,67 @@ const brain = new BrainBank({
686
686
  |----------|--------|------|-------|------|
687
687
  | **Local (default)** | built-in | 384 | ⚡ 0ms | Free |
688
688
  | **OpenAI** | `OpenAIEmbedding` | 1536 | ~100ms | $0.02/1M tokens |
689
+ | **Perplexity** | `PerplexityEmbedding` | 2560 (4b) / 1024 (0.6b) | ~100ms | $0.02/1M tokens |
690
+ | **Perplexity Context** | `PerplexityContextEmbedding` | 2560 (4b) / 1024 (0.6b) | ~100ms | $0.06/1M tokens |
691
+
692
+ #### OpenAI
689
693
 
690
694
  ```typescript
691
695
  import { OpenAIEmbedding } from 'brainbank';
692
696
 
693
- // Uses OPENAI_API_KEY env var by default
694
- new OpenAIEmbedding();
695
-
696
- // Custom options
697
+ new OpenAIEmbedding(); // uses OPENAI_API_KEY env var
697
698
  new OpenAIEmbedding({
698
699
  model: 'text-embedding-3-large',
699
- dims: 512, // custom dims (text-embedding-3 only)
700
+ dims: 512, // Matryoshka reduction
700
701
  apiKey: 'sk-...',
701
- baseUrl: 'https://my-proxy.com/v1/embeddings', // Azure, proxies
702
+ baseUrl: 'https://my-proxy.com/v1/embeddings',
702
703
  });
703
704
  ```
704
705
 
706
+ #### Perplexity (Standard)
707
+
708
+ Best for independent texts, queries, and code chunks.
709
+
710
+ ```typescript
711
+ import { PerplexityEmbedding } from 'brainbank';
712
+
713
+ new PerplexityEmbedding(); // uses PERPLEXITY_API_KEY env var
714
+ new PerplexityEmbedding({
715
+ model: 'pplx-embed-v1-0.6b', // smaller, faster (1024d)
716
+ dims: 512, // Matryoshka reduction
717
+ });
718
+ ```
719
+
720
+ #### Perplexity (Contextualized)
721
+
722
+ Chunks share document context → better retrieval for related code/docs.
723
+
724
+ ```typescript
725
+ import { PerplexityContextEmbedding } from 'brainbank';
726
+
727
+ new PerplexityContextEmbedding(); // uses PERPLEXITY_API_KEY env var
728
+ new PerplexityContextEmbedding({
729
+ model: 'pplx-embed-context-v1-0.6b', // smaller, faster (1024d)
730
+ dims: 512, // Matryoshka reduction
731
+ });
732
+ ```
733
+
734
+ #### Benchmarks
735
+
736
+ Real benchmarks on a production NestJS backend (1052 code chunks + git history):
737
+
738
+ | Provider | Dims | Index Time | Avg Search | Cost |
739
+ |----------|------|------------|------------|------|
740
+ | **Local WASM** | 384 | 87s | **8ms** | Free |
741
+ | **OpenAI** | 1536 | 106s | 202ms | $0.02/1M tok |
742
+ | **Perplexity** | 2560 | **66s** ⚡ | 168ms | $0.02/1M tok |
743
+ | **Perplexity Context** | 2560 | 78s | 135ms | $0.06/1M tok |
744
+
745
+ - **Fastest indexing:** Perplexity standard — 38% faster than OpenAI
746
+ - **Fastest search (API):** Perplexity Context — 33% faster than OpenAI
747
+ - **Fastest search (total):** Local WASM — no network latency
748
+ - **Best context awareness:** Perplexity Context — finds semantically related chunks others miss
749
+
705
750
  > [!WARNING]
706
751
  > Switching embedding provider (e.g. local → OpenAI) changes the vector dimensions. BrainBank will **refuse to initialize** if the stored dimensions don't match the current provider. Use `initialize({ force: true })` and then `reembed()` to migrate, or switch back to the original provider.
707
752
 
@@ -778,6 +823,91 @@ const myReranker: Reranker = {
778
823
 
779
824
  Without a reranker, BrainBank uses pure RRF fusion — which is already production-quality for most use cases.
780
825
 
826
+ ### Notes
827
+
828
+ The notes plugin gives your agent **persistent conversation memory** — store structured digests of past sessions and recall them via hybrid search.
829
+
830
+ ```typescript
831
+ import { BrainBank } from 'brainbank';
832
+ import { notes } from 'brainbank/notes';
833
+
834
+ const brain = new BrainBank({ repoPath: '.' });
835
+ brain.use(notes());
836
+ await brain.initialize();
837
+
838
+ const notesPlugin = brain.indexer('notes');
839
+
840
+ // Store a conversation digest
841
+ await notesPlugin.remember({
842
+ title: 'Refactored auth module',
843
+ summary: 'Extracted JWT validation into middleware, added refresh token rotation',
844
+ decisions: ['Use RS256 over HS256', 'Refresh tokens stored in httpOnly cookie'],
845
+ filesChanged: ['src/auth/jwt.ts', 'src/middleware/auth.ts'],
846
+ patterns: ['Always validate token expiry before DB lookup'],
847
+ openQuestions: ['Should we add rate limiting to the refresh endpoint?'],
848
+ tags: ['auth', 'security'],
849
+ });
850
+
851
+ // Recall relevant notes
852
+ const relevant = await notesPlugin.recall('JWT token validation', { k: 3 });
853
+
854
+ // List recent notes
855
+ const recent = notesPlugin.list(10);
856
+ const longTermOnly = notesPlugin.list(10, 'long');
857
+
858
+ // Consolidate: promote old short-term notes to long-term (keeps last 20 as short)
859
+ const { promoted } = notesPlugin.consolidate(20);
860
+ ```
861
+
862
+ **Memory tiers:**
863
+ - **`short`** (default) — Full digest with all fields, kept for recent sessions
864
+ - **`long`** — Compressed: only title, summary, decisions, and patterns preserved. Files and open questions dropped
865
+
866
+ Consolidation automatically promotes notes beyond the keep window from `short` → `long`, reducing storage while preserving key learnings.
867
+
868
+ ### Agent Memory (Patterns)
869
+
870
+ The memory plugin enables **learning from experience** — your agent records what worked (and what didn't) across tasks, then distills patterns into reusable strategies.
871
+
872
+ ```typescript
873
+ import { BrainBank } from 'brainbank';
874
+ import { memory } from 'brainbank/memory';
875
+
876
+ const brain = new BrainBank({ repoPath: '.' });
877
+ brain.use(memory());
878
+ await brain.initialize();
879
+
880
+ const mem = brain.indexer('memory');
881
+
882
+ // Record a learning pattern
883
+ await mem.learn({
884
+ taskType: 'refactor',
885
+ task: 'Extract auth logic into middleware',
886
+ approach: 'Created Express middleware, moved JWT validation from routes',
887
+ outcome: 'Reduced route handler size by 60%, improved testability',
888
+ successRate: 0.95,
889
+ critique: 'Should have added integration tests before refactoring',
890
+ });
891
+
892
+ // Search for similar patterns before starting a new task
893
+ const patterns = await mem.search('refactor database queries');
894
+
895
+ // Consolidate: prune old failures + merge duplicates
896
+ const { pruned, deduped } = mem.consolidate();
897
+
898
+ // Distill top patterns into a strategy
899
+ const strategy = mem.distill('refactor');
900
+ // → "Strategy for 'refactor' (5 patterns, avg success 88%):
901
+ // • Created middleware, moved validation from routes (95%)
902
+ // └ Should have added integration tests before refactoring"
903
+ ```
904
+
905
+ **How it works:**
906
+ 1. **Learn** — Records task, approach, outcome, and success rate. Embeds for semantic search
907
+ 2. **Search** — Finds similar successful patterns (filters by `successRate ≥ 0.5`)
908
+ 3. **Consolidate** — Auto-runs every 50 patterns: prunes failures older than 90 days, deduplicates (cosine > 0.95)
909
+ 4. **Distill** — Aggregates top patterns per task type into a single strategy text with confidence score
910
+
781
911
  ---
782
912
 
783
913
  ## Memory
@@ -842,9 +972,10 @@ The `LLMProvider` interface works with any framework:
842
972
  | Variable | Description |
843
973
  |----------|-------------|
844
974
  | `BRAINBANK_REPO` | Default repository path (optional — auto-detected from `.git/` or passed per tool call) |
845
- | `BRAINBANK_EMBEDDING` | Embedding provider: `local` (default), `openai` |
975
+ | `BRAINBANK_EMBEDDING` | Embedding provider: `local` (default), `openai`, `perplexity`, `perplexity-context` |
846
976
  | `BRAINBANK_DEBUG` | Show full stack traces |
847
977
  | `OPENAI_API_KEY` | Required when using `BRAINBANK_EMBEDDING=openai` |
978
+ | `PERPLEXITY_API_KEY` | Required when using `BRAINBANK_EMBEDDING=perplexity` or `perplexity-context` |
848
979
 
849
980
  ---
850
981
 
@@ -1143,7 +1274,7 @@ node test/benchmarks/search-quality.mjs
1143
1274
  │ └──────────────────────────────────────────────────┘│
1144
1275
  │ │
1145
1276
  │ ┌──────────────────────────────────────────────────┐│
1146
- │ │ Embedding (Local WASM 384d OpenAI 1536d) ││
1277
+ │ │ Embedding (Local 384d│OpenAI 1536d│Perplexity) ││
1147
1278
  │ └──────────────────────────────────────────────────┘│
1148
1279
  │ ┌──────────────────────────────────────────────────┐│
1149
1280
  │ │ Qwen3-Reranker (opt-in cross-encoder) ││
@@ -0,0 +1,136 @@
1
+ import {
2
+ decodeBase64Int8
3
+ } from "./chunk-N2OJRXSB.js";
4
+ import {
5
+ __name
6
+ } from "./chunk-7QVYU63E.js";
7
+
8
+ // src/providers/embeddings/perplexity-context-embedding.ts
9
+ var DEFAULT_MODEL = "pplx-embed-context-v1-4b";
10
+ var DEFAULT_DIMS = {
11
+ "pplx-embed-context-v1-0.6b": 1024,
12
+ "pplx-embed-context-v1-4b": 2560
13
+ };
14
+ var API_URL = "https://api.perplexity.ai/v1/contextualizedembeddings";
15
+ var REQUEST_TIMEOUT_MS = 3e4;
16
+ var BATCH_DELAY_MS = 100;
17
+ var PerplexityContextEmbedding = class {
18
+ static {
19
+ __name(this, "PerplexityContextEmbedding");
20
+ }
21
+ dims;
22
+ _apiKey;
23
+ _model;
24
+ _baseUrl;
25
+ _requestDims;
26
+ _timeout;
27
+ constructor(options = {}) {
28
+ this._apiKey = options.apiKey ?? process.env.PERPLEXITY_API_KEY ?? "";
29
+ this._model = options.model ?? DEFAULT_MODEL;
30
+ this._baseUrl = options.baseUrl ?? API_URL;
31
+ this._timeout = options.timeout ?? REQUEST_TIMEOUT_MS;
32
+ if (options.dims) {
33
+ this._requestDims = options.dims;
34
+ this.dims = options.dims;
35
+ } else {
36
+ this.dims = DEFAULT_DIMS[this._model] ?? 2560;
37
+ }
38
+ }
39
+ /** Embed a single text. Wraps as [[text]] for the contextualized API. */
40
+ async embed(text) {
41
+ const results = await this._request([[text]]);
42
+ return results[0];
43
+ }
44
+ /**
45
+ * Embed multiple texts as chunks of contextualized documents.
46
+ * Splits into sub-documents to stay under Perplexity's 32k token/doc limit.
47
+ */
48
+ async embedBatch(texts) {
49
+ if (texts.length === 0) return [];
50
+ const docs = splitIntoDocuments(texts);
51
+ const results = [];
52
+ for (let i = 0; i < docs.length; i++) {
53
+ if (i > 0) await sleep(BATCH_DELAY_MS);
54
+ const embeddings = await this._request([docs[i]]);
55
+ results.push(...embeddings);
56
+ }
57
+ return results;
58
+ }
59
+ async close() {
60
+ }
61
+ /** Send a contextualized request. Input is string[][] (docs × chunks). */
62
+ async _request(input) {
63
+ if (!this._apiKey) {
64
+ throw new Error(
65
+ "BrainBank: Perplexity API key required. Set PERPLEXITY_API_KEY env var or pass apiKey option."
66
+ );
67
+ }
68
+ const MAX_CHARS = 24e3;
69
+ const safeInput = input.map(
70
+ (doc) => doc.map((chunk) => chunk.length > MAX_CHARS ? chunk.slice(0, MAX_CHARS) : chunk)
71
+ );
72
+ const body = { model: this._model, input: safeInput };
73
+ if (this._requestDims) body.dimensions = this._requestDims;
74
+ const controller = new AbortController();
75
+ const timer = setTimeout(() => controller.abort(), this._timeout);
76
+ let res;
77
+ try {
78
+ res = await fetch(this._baseUrl, {
79
+ method: "POST",
80
+ headers: {
81
+ "Content-Type": "application/json",
82
+ "Authorization": `Bearer ${this._apiKey}`
83
+ },
84
+ body: JSON.stringify(body),
85
+ signal: controller.signal
86
+ });
87
+ } catch (err) {
88
+ clearTimeout(timer);
89
+ if (err instanceof Error && err.name === "AbortError") {
90
+ throw new Error(`BrainBank: Perplexity contextualized embedding request timed out after ${this._timeout}ms.`);
91
+ }
92
+ throw err;
93
+ } finally {
94
+ clearTimeout(timer);
95
+ }
96
+ if (!res.ok) {
97
+ const errText = await res.text();
98
+ throw new Error(`BrainBank: Perplexity contextualized embedding API error (${res.status}): ${errText}`);
99
+ }
100
+ const json = await res.json();
101
+ return flattenContextResponse(json, this.dims);
102
+ }
103
+ };
104
+ function flattenContextResponse(json, dims) {
105
+ return json.data.sort((a, b) => a.index - b.index).flatMap(
106
+ (doc) => doc.data.sort((a, b) => a.index - b.index).map((chunk) => decodeBase64Int8(chunk.embedding, dims))
107
+ );
108
+ }
109
+ __name(flattenContextResponse, "flattenContextResponse");
110
+ function splitIntoDocuments(texts) {
111
+ const MAX_CHARS_PER_DOC = 8e4;
112
+ const docs = [];
113
+ let current = [];
114
+ let currentChars = 0;
115
+ for (const text of texts) {
116
+ if (current.length > 0 && currentChars + text.length > MAX_CHARS_PER_DOC) {
117
+ docs.push(current);
118
+ current = [];
119
+ currentChars = 0;
120
+ }
121
+ current.push(text);
122
+ currentChars += text.length;
123
+ }
124
+ if (current.length > 0) docs.push(current);
125
+ return docs;
126
+ }
127
+ __name(splitIntoDocuments, "splitIntoDocuments");
128
+ function sleep(ms) {
129
+ return new Promise((resolve) => setTimeout(resolve, ms));
130
+ }
131
+ __name(sleep, "sleep");
132
+
133
+ export {
134
+ PerplexityContextEmbedding
135
+ };
136
+ //# sourceMappingURL=chunk-6XOXM7MI.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/providers/embeddings/perplexity-context-embedding.ts"],"sourcesContent":["/**\n * BrainBank — Perplexity Contextualized Embedding Provider\n *\n * Uses Perplexity's contextualized embeddings API for document-aware vectors.\n * Chunks from the same document share context, improving retrieval quality.\n *\n * Models: pplx-embed-context-v1-0.6b (1024d), pplx-embed-context-v1-4b (2560d).\n *\n * Key difference from standard: input is string[][] (docs × chunks) and the\n * response has a nested structure. This provider adapts the flat BrainBank\n * EmbeddingProvider interface to the nested Perplexity API:\n * - embed(text) → wraps as [[text]]\n * - embedBatch(texts) → wraps as [texts] (one \"document\" of related chunks)\n *\n * Usage:\n * const brain = new BrainBank({\n * embeddingProvider: new PerplexityContextEmbedding(),\n * });\n */\n\nimport type { EmbeddingProvider } from '@/types.ts';\nimport { decodeBase64Int8 } from './perplexity-embedding.ts';\n\nconst DEFAULT_MODEL = 'pplx-embed-context-v1-4b';\nconst DEFAULT_DIMS: Record<string, number> = {\n 'pplx-embed-context-v1-0.6b': 1024,\n 'pplx-embed-context-v1-4b': 2560,\n};\nconst API_URL = 'https://api.perplexity.ai/v1/contextualizedembeddings';\nconst MAX_BATCH = 100;\nconst REQUEST_TIMEOUT_MS = 30_000;\nconst BATCH_DELAY_MS = 100;\n\nexport interface PerplexityContextEmbeddingOptions {\n /** Perplexity API key. Falls back to PERPLEXITY_API_KEY env var. */\n apiKey?: string;\n /** Model name. Default: 'pplx-embed-context-v1-4b' */\n model?: string;\n /** Vector dimensions (Matryoshka reduction). If omitted, uses model default. */\n dims?: number;\n /** Base URL override. */\n baseUrl?: string;\n /** Request timeout in ms. Default: 30000 */\n timeout?: number;\n}\n\nexport class PerplexityContextEmbedding implements EmbeddingProvider {\n readonly dims: number;\n\n private _apiKey: string;\n private _model: string;\n private _baseUrl: string;\n private _requestDims: number | undefined;\n private _timeout: number;\n\n constructor(options: PerplexityContextEmbeddingOptions = {}) {\n this._apiKey = options.apiKey ?? process.env.PERPLEXITY_API_KEY ?? '';\n this._model = options.model ?? DEFAULT_MODEL;\n this._baseUrl = options.baseUrl ?? API_URL;\n this._timeout = options.timeout ?? REQUEST_TIMEOUT_MS;\n\n if (options.dims) {\n this._requestDims = options.dims;\n this.dims = options.dims;\n } else {\n this.dims = DEFAULT_DIMS[this._model] ?? 2560;\n }\n }\n\n /** Embed a single text. Wraps as [[text]] for the contextualized API. */\n async embed(text: string): Promise<Float32Array> {\n const results = await this._request([[text]]);\n return results[0];\n }\n\n /**\n * Embed multiple texts as chunks of contextualized documents.\n * Splits into sub-documents to stay under Perplexity's 32k token/doc limit.\n */\n async embedBatch(texts: string[]): Promise<Float32Array[]> {\n if (texts.length === 0) return [];\n\n const docs = splitIntoDocuments(texts);\n const results: Float32Array[] = [];\n\n for (let i = 0; i < docs.length; i++) {\n if (i > 0) await sleep(BATCH_DELAY_MS);\n const embeddings = await this._request([docs[i]]);\n results.push(...embeddings);\n }\n\n return results;\n }\n\n async close(): Promise<void> {\n // No resources to release\n }\n\n /** Send a contextualized request. Input is string[][] (docs × chunks). */\n private async _request(input: string[][]): Promise<Float32Array[]> {\n if (!this._apiKey) {\n throw new Error(\n 'BrainBank: Perplexity API key required. Set PERPLEXITY_API_KEY env var or pass apiKey option.',\n );\n }\n\n const MAX_CHARS = 24_000;\n const safeInput = input.map(doc =>\n doc.map(chunk => chunk.length > MAX_CHARS ? chunk.slice(0, MAX_CHARS) : chunk),\n );\n\n const body: Record<string, unknown> = { model: this._model, input: safeInput };\n if (this._requestDims) body.dimensions = this._requestDims;\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this._timeout);\n\n let res: Response;\n try {\n res = await fetch(this._baseUrl, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this._apiKey}`,\n },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n } catch (err: unknown) {\n clearTimeout(timer);\n if (err instanceof Error && err.name === 'AbortError') {\n throw new Error(`BrainBank: Perplexity contextualized embedding request timed out after ${this._timeout}ms.`);\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n\n if (!res.ok) {\n const errText = await res.text();\n throw new Error(`BrainBank: Perplexity contextualized embedding API error (${res.status}): ${errText}`);\n }\n\n const json = await res.json() as PerplexityContextResponse;\n return flattenContextResponse(json, this.dims);\n }\n}\n\n// ── Response Types ──────────────────────────────────\n\ninterface PerplexityContextResponse {\n data: Array<{\n index: number;\n data: Array<{ index: number; embedding: string }>;\n }>;\n}\n\n/** Flatten nested doc → chunk response into a single flat array. */\nfunction flattenContextResponse(json: PerplexityContextResponse, dims: number): Float32Array[] {\n return json.data\n .sort((a, b) => a.index - b.index)\n .flatMap(doc =>\n doc.data\n .sort((a, b) => a.index - b.index)\n .map(chunk => decodeBase64Int8(chunk.embedding, dims)),\n );\n}\n\n/**\n * Split chunks into sub-documents that each stay under the 32k token limit.\n * Uses ~4 chars/token estimate with safety margin (~80k chars ≈ ~20k tokens).\n */\nfunction splitIntoDocuments(texts: string[]): string[][] {\n const MAX_CHARS_PER_DOC = 80_000;\n const docs: string[][] = [];\n let current: string[] = [];\n let currentChars = 0;\n\n for (const text of texts) {\n if (current.length > 0 && currentChars + text.length > MAX_CHARS_PER_DOC) {\n docs.push(current);\n current = [];\n currentChars = 0;\n }\n current.push(text);\n currentChars += text.length;\n }\n\n if (current.length > 0) docs.push(current);\n return docs;\n}\n\n/** Simple delay helper. */\nfunction sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,117 @@
1
+ import {
2
+ __name
3
+ } from "./chunk-7QVYU63E.js";
4
+
5
+ // src/providers/embeddings/perplexity-embedding.ts
6
+ var DEFAULT_MODEL = "pplx-embed-v1-4b";
7
+ var DEFAULT_DIMS = {
8
+ "pplx-embed-v1-0.6b": 1024,
9
+ "pplx-embed-v1-4b": 2560
10
+ };
11
+ var API_URL = "https://api.perplexity.ai/v1/embeddings";
12
+ var MAX_BATCH = 100;
13
+ var REQUEST_TIMEOUT_MS = 3e4;
14
+ var BATCH_DELAY_MS = 100;
15
+ var PerplexityEmbedding = class {
16
+ static {
17
+ __name(this, "PerplexityEmbedding");
18
+ }
19
+ dims;
20
+ _apiKey;
21
+ _model;
22
+ _baseUrl;
23
+ _requestDims;
24
+ _timeout;
25
+ constructor(options = {}) {
26
+ this._apiKey = options.apiKey ?? process.env.PERPLEXITY_API_KEY ?? "";
27
+ this._model = options.model ?? DEFAULT_MODEL;
28
+ this._baseUrl = options.baseUrl ?? API_URL;
29
+ this._timeout = options.timeout ?? REQUEST_TIMEOUT_MS;
30
+ if (options.dims) {
31
+ this._requestDims = options.dims;
32
+ this.dims = options.dims;
33
+ } else {
34
+ this.dims = DEFAULT_DIMS[this._model] ?? 2560;
35
+ }
36
+ }
37
+ async embed(text) {
38
+ const results = await this._request([text]);
39
+ return results[0];
40
+ }
41
+ async embedBatch(texts) {
42
+ if (texts.length === 0) return [];
43
+ const results = [];
44
+ for (let i = 0; i < texts.length; i += MAX_BATCH) {
45
+ if (i > 0) await sleep(BATCH_DELAY_MS);
46
+ const batch = texts.slice(i, i + MAX_BATCH);
47
+ const embeddings = await this._request(batch);
48
+ results.push(...embeddings);
49
+ }
50
+ return results;
51
+ }
52
+ async close() {
53
+ }
54
+ async _request(input) {
55
+ if (!this._apiKey) {
56
+ throw new Error(
57
+ "BrainBank: Perplexity API key required. Set PERPLEXITY_API_KEY env var or pass apiKey option."
58
+ );
59
+ }
60
+ const MAX_CHARS = 24e3;
61
+ const safeInput = input.map((t) => t.length > MAX_CHARS ? t.slice(0, MAX_CHARS) : t);
62
+ const body = { model: this._model, input: safeInput };
63
+ if (this._requestDims) body.dimensions = this._requestDims;
64
+ const controller = new AbortController();
65
+ const timer = setTimeout(() => controller.abort(), this._timeout);
66
+ let res;
67
+ try {
68
+ res = await fetch(this._baseUrl, {
69
+ method: "POST",
70
+ headers: {
71
+ "Content-Type": "application/json",
72
+ "Authorization": `Bearer ${this._apiKey}`
73
+ },
74
+ body: JSON.stringify(body),
75
+ signal: controller.signal
76
+ });
77
+ } catch (err) {
78
+ clearTimeout(timer);
79
+ if (err instanceof Error && err.name === "AbortError") {
80
+ throw new Error(`BrainBank: Perplexity embedding request timed out after ${this._timeout}ms.`);
81
+ }
82
+ throw err;
83
+ } finally {
84
+ clearTimeout(timer);
85
+ }
86
+ if (!res.ok) {
87
+ const errText = await res.text();
88
+ throw new Error(`BrainBank: Perplexity embedding API error (${res.status}): ${errText}`);
89
+ }
90
+ const json = await res.json();
91
+ return json.data.sort((a, b) => a.index - b.index).map((d) => decodeBase64Int8(d.embedding, this.dims));
92
+ }
93
+ };
94
+ function decodeBase64Int8(b64, expectedDims) {
95
+ const binary = atob(b64);
96
+ const bytes = new Int8Array(binary.length);
97
+ for (let i = 0; i < binary.length; i++) {
98
+ bytes[i] = binary.charCodeAt(i) << 24 >> 24;
99
+ }
100
+ const dims = Math.min(bytes.length, expectedDims);
101
+ const result = new Float32Array(dims);
102
+ for (let i = 0; i < dims; i++) {
103
+ result[i] = bytes[i];
104
+ }
105
+ return result;
106
+ }
107
+ __name(decodeBase64Int8, "decodeBase64Int8");
108
+ function sleep(ms) {
109
+ return new Promise((resolve) => setTimeout(resolve, ms));
110
+ }
111
+ __name(sleep, "sleep");
112
+
113
+ export {
114
+ PerplexityEmbedding,
115
+ decodeBase64Int8
116
+ };
117
+ //# sourceMappingURL=chunk-N2OJRXSB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/providers/embeddings/perplexity-embedding.ts"],"sourcesContent":["/**\n * BrainBank — Perplexity Standard Embedding Provider\n *\n * Uses Perplexity's embedding API via fetch (no SDK dependency).\n * Models: pplx-embed-v1-0.6b (1024d) and pplx-embed-v1-4b (2560d).\n *\n * Perplexity returns base64-encoded signed int8 vectors by default.\n * This provider decodes them to Float32Array for HNSW compatibility.\n *\n * Usage:\n * const brain = new BrainBank({\n * embeddingProvider: new PerplexityEmbedding({ model: 'pplx-embed-v1-4b' }),\n * });\n */\n\nimport type { EmbeddingProvider } from '@/types.ts';\n\nconst DEFAULT_MODEL = 'pplx-embed-v1-4b';\nconst DEFAULT_DIMS: Record<string, number> = {\n 'pplx-embed-v1-0.6b': 1024,\n 'pplx-embed-v1-4b': 2560,\n};\nconst API_URL = 'https://api.perplexity.ai/v1/embeddings';\nconst MAX_BATCH = 100;\nconst REQUEST_TIMEOUT_MS = 30_000;\nconst BATCH_DELAY_MS = 100;\n\nexport interface PerplexityEmbeddingOptions {\n /** Perplexity API key. Falls back to PERPLEXITY_API_KEY env var. */\n apiKey?: string;\n /** Model name. Default: 'pplx-embed-v1-4b' */\n model?: string;\n /** Vector dimensions (Matryoshka reduction). If omitted, uses model default. */\n dims?: number;\n /** Base URL override. */\n baseUrl?: string;\n /** Request timeout in ms. Default: 30000 */\n timeout?: number;\n}\n\nexport class PerplexityEmbedding implements EmbeddingProvider {\n readonly dims: number;\n\n private _apiKey: string;\n private _model: string;\n private _baseUrl: string;\n private _requestDims: number | undefined;\n private _timeout: number;\n\n constructor(options: PerplexityEmbeddingOptions = {}) {\n this._apiKey = options.apiKey ?? process.env.PERPLEXITY_API_KEY ?? '';\n this._model = options.model ?? DEFAULT_MODEL;\n this._baseUrl = options.baseUrl ?? API_URL;\n this._timeout = options.timeout ?? REQUEST_TIMEOUT_MS;\n\n if (options.dims) {\n this._requestDims = options.dims;\n this.dims = options.dims;\n } else {\n this.dims = DEFAULT_DIMS[this._model] ?? 2560;\n }\n }\n\n async embed(text: string): Promise<Float32Array> {\n const results = await this._request([text]);\n return results[0];\n }\n\n async embedBatch(texts: string[]): Promise<Float32Array[]> {\n if (texts.length === 0) return [];\n\n const results: Float32Array[] = [];\n\n for (let i = 0; i < texts.length; i += MAX_BATCH) {\n if (i > 0) await sleep(BATCH_DELAY_MS);\n const batch = texts.slice(i, i + MAX_BATCH);\n const embeddings = await this._request(batch);\n results.push(...embeddings);\n }\n\n return results;\n }\n\n async close(): Promise<void> {\n // No resources to release\n }\n\n private async _request(input: string[]): Promise<Float32Array[]> {\n if (!this._apiKey) {\n throw new Error(\n 'BrainBank: Perplexity API key required. Set PERPLEXITY_API_KEY env var or pass apiKey option.',\n );\n }\n\n const MAX_CHARS = 24_000;\n const safeInput = input.map(t => t.length > MAX_CHARS ? t.slice(0, MAX_CHARS) : t);\n\n const body: Record<string, unknown> = { model: this._model, input: safeInput };\n if (this._requestDims) body.dimensions = this._requestDims;\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this._timeout);\n\n let res: Response;\n try {\n res = await fetch(this._baseUrl, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this._apiKey}`,\n },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n } catch (err: unknown) {\n clearTimeout(timer);\n if (err instanceof Error && err.name === 'AbortError') {\n throw new Error(`BrainBank: Perplexity embedding request timed out after ${this._timeout}ms.`);\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n\n if (!res.ok) {\n const errText = await res.text();\n throw new Error(`BrainBank: Perplexity embedding API error (${res.status}): ${errText}`);\n }\n\n const json = await res.json() as PerplexityStandardResponse;\n return json.data\n .sort((a, b) => a.index - b.index)\n .map(d => decodeBase64Int8(d.embedding, this.dims));\n }\n}\n\n// ── Response Types ──────────────────────────────────\n\ninterface PerplexityStandardResponse {\n data: Array<{ index: number; embedding: string }>;\n}\n\n// ── Base64 Int8 Decoding ────────────────────────────\n\n/**\n * Decode a base64-encoded signed int8 embedding to Float32Array.\n * Perplexity returns embeddings as base64(int8[]) by default.\n */\nexport function decodeBase64Int8(b64: string, expectedDims: number): Float32Array {\n const binary = atob(b64);\n const bytes = new Int8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i) << 24 >> 24; // sign-extend to int8\n }\n\n const dims = Math.min(bytes.length, expectedDims);\n const result = new Float32Array(dims);\n for (let i = 0; i < dims; i++) {\n result[i] = bytes[i];\n }\n return result;\n}\n\n/** Simple delay helper. */\nfunction sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n}\n"],"mappings":"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","names":[]}
package/dist/cli.js CHANGED
@@ -197,6 +197,16 @@ async function setupProviders(brainOpts) {
197
197
  const provider = new OpenAIEmbedding();
198
198
  brainOpts.embeddingProvider = provider;
199
199
  brainOpts.embeddingDims = provider.dims;
200
+ } else if (process.env.BRAINBANK_EMBEDDING === "perplexity") {
201
+ const { PerplexityEmbedding } = await import("./perplexity-embedding-227WQY4R.js");
202
+ const provider = new PerplexityEmbedding();
203
+ brainOpts.embeddingProvider = provider;
204
+ brainOpts.embeddingDims = provider.dims;
205
+ } else if (process.env.BRAINBANK_EMBEDDING === "perplexity-context") {
206
+ const { PerplexityContextEmbedding } = await import("./perplexity-context-embedding-KSVSZXMD.js");
207
+ const provider = new PerplexityContextEmbedding();
208
+ brainOpts.embeddingProvider = provider;
209
+ brainOpts.embeddingDims = provider.dims;
200
210
  }
201
211
  }
202
212
  __name(setupProviders, "setupProviders");
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli/utils.ts","../src/cli/commands/index-cmd.ts","../src/cli/factory.ts","../src/cli/commands/collection.ts","../src/cli/commands/kv.ts","../src/cli/commands/docs.ts","../src/cli/commands/search.ts","../src/cli/commands/context.ts","../src/cli/commands/system.ts","../src/cli/index.ts"],"sourcesContent":["/**\n * BrainBank CLI — Shared Utilities\n *\n * Colors, argument parsing, and result formatting.\n * No BrainBank imports — pure Node.js / terminal helpers.\n */\n\n// ── Colors ──────────────────────────────────────────\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// ── Argument Parsing ────────────────────────────────\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\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', 'only', 'docs',\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 * stripFlags(['ksearch', 'auth', '--repo', '/path'])\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 if (VALUE_FLAGS.has(name)) i++; // skip next (the value)\n continue;\n }\n result.push(argv[i]);\n }\n return result;\n}\n\n// ── Result Printer ──────────────────────────────────\n\nexport function printResults(results: any[]): void {\n if (results.length === 0) {\n console.log(c.yellow(' No results found.'));\n return;\n }\n\n for (const r of results) {\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 * brainbank index [path] — Index code + git + docs\n */\n\nimport * as path from 'node:path';\nimport { c, args, getFlag, hasFlag } from '@/cli/utils.ts';\nimport { createBrain } from '@/cli/factory.ts';\n\nexport async function cmdIndex(): Promise<void> {\n const repoPath = args[1] || '.';\n const force = hasFlag('force');\n const depth = parseInt(getFlag('depth') || '500', 10);\n const onlyRaw = getFlag('only');\n const docsPath = getFlag('docs');\n const modules = onlyRaw\n ? onlyRaw.split(',').map(s => s.trim()) as ('code' | 'git' | 'docs')[]\n : undefined;\n\n // If --docs is passed, auto-include 'docs' in modules\n if (docsPath && modules && !modules.includes('docs')) {\n modules.push('docs');\n }\n\n console.log(c.bold('\\n━━━ BrainBank Index ━━━'));\n console.log(c.dim(` Repo: ${repoPath}`));\n console.log(c.dim(` Force: ${force}`));\n console.log(c.dim(` Git depth: ${depth}`));\n if (modules) console.log(c.dim(` Modules: ${modules.join(', ')}`));\n if (docsPath) console.log(c.dim(` Docs path: ${docsPath}`));\n\n const brain = await createBrain(repoPath);\n\n // Auto-register docs collection from --docs path\n if (docsPath) {\n const absDocsPath = path.resolve(docsPath);\n const collName = path.basename(absDocsPath);\n try {\n await brain.addCollection({\n name: collName,\n path: absDocsPath,\n pattern: '**/*.md',\n ignore: ['deprecated/**', 'node_modules/**'],\n });\n console.log(c.dim(` Registered docs collection: ${collName}`));\n } catch {\n console.log(c.yellow(` Warning: docs module not loaded, skipping --docs`));\n }\n }\n\n const result = await brain.index({\n modules,\n forceReindex: force,\n gitDepth: depth,\n onProgress: (stage, msg) => {\n process.stdout.write(`\\r ${c.cyan(stage.toUpperCase())} ${msg} `);\n },\n });\n\n console.log('\\n');\n if (result.code) {\n console.log(` ${c.green('Code')}: ${result.code.indexed} indexed, ${result.code.skipped} skipped, ${result.code.chunks ?? 0} chunks`);\n }\n if (result.git) {\n console.log(` ${c.green('Git')}: ${result.git.indexed} indexed, ${result.git.skipped} skipped`);\n }\n if (result.docs) {\n for (const [name, stat] of Object.entries(result.docs)) {\n console.log(` ${c.green('Docs')}: [${name}] ${stat.indexed} indexed, ${stat.skipped} skipped, ${stat.chunks} chunks`);\n }\n }\n\n const stats = brain.stats();\n console.log(`\\n ${c.bold('Totals')}:`);\n if (stats.code) console.log(` Code chunks: ${stats.code.chunks}`);\n if (stats.git) console.log(` Git commits: ${stats.git.commits}`);\n if (stats.git) console.log(` Co-edit pairs: ${stats.git.coEdits}`);\n if (stats.documents) console.log(` Documents: ${stats.documents.documents}`);\n\n brain.close();\n}\n","/**\n * BrainBank CLI — Brain Factory\n *\n * Creates a configured BrainBank instance with built-in indexers,\n * auto-discovered indexers, and config file support.\n */\n\nimport * as path from 'node:path';\nimport * as fs from 'node:fs';\nimport { BrainBank } from '@/brainbank.ts';\nimport { code } from '@/indexers/code/code-plugin.ts';\nimport { git } from '@/indexers/git/git-plugin.ts';\nimport { docs } from '@/indexers/docs/docs-plugin.ts';\nimport type { Indexer } from '@/indexers/base.ts';\nimport { c, getFlag } from './utils.ts';\n\n// ── Types ───────────────────────────────────────────\n\ninterface BrainBankCliConfig {\n /** Custom indexers to register alongside built-in ones. */\n indexers?: Indexer[];\n /** Override which built-in indexers to load. Default: ['code', 'git', 'docs'] */\n builtins?: ('code' | 'git' | 'docs')[];\n /** BrainBank constructor options. */\n brainbank?: Record<string, any>;\n}\n\nconst CONFIG_NAMES = ['config.ts', 'config.js', 'config.mjs'];\nconst INDEXER_EXTENSIONS = ['.ts', '.js', '.mjs'];\n\n// ── Caches ──────────────────────────────────────────\n\nlet _configCache: BrainBankCliConfig | null | undefined = undefined;\nlet _folderIndexersCache: Indexer[] | undefined = undefined;\n\n// ── Config Loader ───────────────────────────────────\n\n/** Load .brainbank/config.ts if present. */\nasync function loadConfig(): Promise<BrainBankCliConfig | null> {\n if (_configCache !== undefined) return _configCache;\n\n const repoPath = getFlag('repo') ?? '.';\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)) {\n try {\n const mod = await import(configPath);\n _configCache = (mod.default ?? mod) as BrainBankCliConfig;\n return _configCache;\n } catch (err: any) {\n console.error(c.red(`Error loading .brainbank/${name}: ${err.message}`));\n process.exit(1);\n }\n }\n }\n\n _configCache = null;\n return null;\n}\n\n// ── Indexer Discovery ───────────────────────────────\n\n/** Auto-discover indexers from .brainbank/indexers/ folder. */\nasync function discoverFolderIndexers(): Promise<Indexer[]> {\n if (_folderIndexersCache !== undefined) return _folderIndexersCache;\n\n const repoPath = getFlag('repo') ?? '.';\n const indexersDir = path.resolve(repoPath, '.brainbank', 'indexers');\n\n if (!fs.existsSync(indexersDir)) {\n _folderIndexersCache = [];\n return [];\n }\n\n const files = fs.readdirSync(indexersDir)\n .filter(f => INDEXER_EXTENSIONS.some(ext => f.endsWith(ext)))\n .sort();\n\n const indexers: Indexer[] = [];\n\n for (const file of files) {\n const filePath = path.join(indexersDir, file);\n try {\n const mod = await import(filePath);\n const indexer = mod.default ?? mod;\n\n if (indexer && typeof indexer === 'object' && indexer.name) {\n indexers.push(indexer as Indexer);\n } else {\n console.error(c.yellow(`⚠ ${file}: must export a default Indexer with a 'name' property, skipping`));\n }\n } catch (err: any) {\n console.error(c.red(`Error loading indexer ${file}: ${err.message}`));\n }\n }\n\n _folderIndexersCache = indexers;\n return indexers;\n}\n\n// ── Multi-repo Detection ────────────────────────────\n\n/** Detect subdirectories that have their own .git repo. */\nfunction detectGitSubdirs(parentPath: string): { name: string; path: string }[] {\n try {\n const entries = fs.readdirSync(parentPath, { withFileTypes: true });\n return entries\n .filter(e =>\n e.isDirectory() &&\n !e.name.startsWith('.') &&\n !e.name.startsWith('node_modules') &&\n fs.existsSync(path.join(parentPath, e.name, '.git')),\n )\n .map(e => ({ name: e.name, path: path.join(parentPath, e.name) }));\n } catch {\n return [];\n }\n}\n\n// ── Factory ─────────────────────────────────────────\n\n/** Create a BrainBank with built-in + discovered + config indexers. */\nexport async function createBrain(repoPath?: string): Promise<BrainBank> {\n const rp = repoPath ?? getFlag('repo') ?? '.';\n const config = await loadConfig();\n const folderIndexers = await discoverFolderIndexers();\n\n const brainOpts: Record<string, any> = { repoPath: rp, ...(config?.brainbank ?? {}) };\n await setupProviders(brainOpts);\n\n const brain = new BrainBank(brainOpts);\n const builtins = config?.builtins ?? ['code', 'git', 'docs'];\n registerBuiltins(brain, rp, builtins);\n\n for (const indexer of folderIndexers) brain.use(indexer);\n if (config?.indexers) {\n for (const indexer of config.indexers) brain.use(indexer);\n }\n\n return brain;\n}\n\n/** Configure reranker and embedding provider on brainOpts. */\nasync function setupProviders(brainOpts: Record<string, any>): Promise<void> {\n const rerankerFlag = getFlag('reranker');\n if (rerankerFlag === 'qwen3') {\n const { Qwen3Reranker } = await import('@brainbank/reranker');\n brainOpts.reranker = new Qwen3Reranker();\n }\n\n if (process.env.BRAINBANK_EMBEDDING === 'openai') {\n const { OpenAIEmbedding } = await import('../providers/embeddings/openai-embedding.ts');\n const provider = new OpenAIEmbedding();\n brainOpts.embeddingProvider = provider;\n brainOpts.embeddingDims = provider.dims;\n }\n}\n\n/** Register built-in indexers with multi-repo detection. */\nfunction registerBuiltins(\n brain: BrainBank, rp: string, builtins: ('code' | 'git' | 'docs')[],\n): void {\n const resolvedRp = path.resolve(rp);\n const hasRootGit = fs.existsSync(path.join(resolvedRp, '.git'));\n const gitSubdirs = !hasRootGit ? detectGitSubdirs(resolvedRp) : [];\n\n if (gitSubdirs.length > 0 && (builtins.includes('code') || builtins.includes('git'))) {\n console.log(c.cyan(` Multi-repo: found ${gitSubdirs.length} git repos: ${gitSubdirs.map(d => d.name).join(', ')}`));\n for (const sub of gitSubdirs) {\n if (builtins.includes('code')) brain.use(code({ repoPath: sub.path, name: `code:${sub.name}` }));\n if (builtins.includes('git')) brain.use(git({ repoPath: sub.path, name: `git:${sub.name}` }));\n }\n } else {\n if (builtins.includes('code')) brain.use(code({ repoPath: rp }));\n if (builtins.includes('git')) brain.use(git());\n }\n\n if (builtins.includes('docs')) brain.use(docs());\n}\n","/**\n * brainbank collection add|list|remove — Document collection management\n */\n\nimport { c, args, getFlag, stripFlags } from '@/cli/utils.ts';\nimport { createBrain } from '@/cli/factory.ts';\n\nexport async function cmdCollection(): Promise<void> {\n const pos = stripFlags(args);\n const sub = pos[1];\n\n if (sub === 'add') {\n const path = pos[2];\n const name = getFlag('name');\n const pattern = getFlag('pattern') ?? '**/*.md';\n const context = getFlag('context');\n const ignoreRaw = getFlag('ignore');\n\n if (!path || !name) {\n console.log(c.red('Usage: brainbank collection add <path> --name <name> [--pattern \"**/*.md\"] [--ignore \"glob\"] [--context \"description\"]'));\n process.exit(1);\n }\n\n const brain = await createBrain();\n await brain.addCollection({\n name,\n path,\n pattern,\n ignore: ignoreRaw ? ignoreRaw.split(',') : [],\n context: context ?? undefined,\n });\n console.log(c.green(`✓ Collection '${name}' added: ${path} (${pattern})`));\n if (context) console.log(c.dim(` Context: ${context}`));\n brain.close();\n return;\n }\n\n if (sub === 'list') {\n const brain = await createBrain();\n await brain.initialize();\n const collections = brain.listCollections();\n if (collections.length === 0) {\n console.log(c.yellow(' No collections registered.'));\n } else {\n console.log(c.bold('\\n━━━ Collections ━━━\\n'));\n for (const col of collections) {\n console.log(` ${c.cyan(col.name)} ${c.dim('→')} ${col.path}`);\n console.log(` Pattern: ${col.pattern ?? '**/*.md'}`);\n if (col.context) console.log(` Context: ${c.dim(col.context)}`);\n }\n }\n brain.close();\n return;\n }\n\n if (sub === 'remove') {\n const name = pos[2];\n if (!name) {\n console.log(c.red('Usage: brainbank collection remove <name>'));\n process.exit(1);\n }\n const brain = await createBrain();\n await brain.removeCollection(name);\n console.log(c.green(`✓ Collection '${name}' removed.`));\n brain.close();\n return;\n }\n\n console.log(c.red('Usage: brainbank collection <add|list|remove>'));\n process.exit(1);\n}\n","/**\n * brainbank kv add|search|list|trim|clear — Dynamic KV collection management\n */\n\nimport { c, args, getFlag, stripFlags } from '@/cli/utils.ts';\nimport { createBrain } from '@/cli/factory.ts';\n\nexport async function cmdKv(): Promise<void> {\n const pos = stripFlags(args);\n const sub = pos[1];\n\n // ── add ─────────────────────────────────────────\n if (sub === 'add') {\n const collName = pos[2];\n const content = pos.slice(3).join(' ');\n const metaRaw = getFlag('meta');\n\n if (!collName || !content) {\n console.log(c.red(\"Usage: brainbank kv add <collection> <content> [--meta '{\\\"key\\\":\\\"val\\\"}']\"));\n process.exit(1);\n }\n\n const brain = await createBrain();\n await brain.initialize();\n const coll = brain.collection(collName);\n const meta = metaRaw ? JSON.parse(metaRaw) : {};\n const id = await coll.add(content, meta);\n console.log(c.green(`✓ Added item #${id} to '${collName}'`));\n brain.close();\n return;\n }\n\n // ── search ──────────────────────────────────────\n if (sub === 'search') {\n const collName = pos[2];\n const query = pos.slice(3).join(' ');\n const k = parseInt(getFlag('k') || '5', 10);\n const mode = (getFlag('mode') as any) || 'hybrid';\n\n if (!collName || !query) {\n console.log(c.red('Usage: brainbank kv search <collection> <query> [--k 5] [--mode hybrid|keyword|vector]'));\n process.exit(1);\n }\n\n const brain = await createBrain();\n await brain.initialize();\n const coll = brain.collection(collName);\n const results = await coll.search(query, { k, mode });\n\n if (results.length === 0) {\n console.log(c.yellow(' No results found.'));\n } else {\n console.log(c.bold(`\\n━━━ ${collName}: \"${query}\" ━━━\\n`));\n for (const r of results) {\n const score = Math.round((r.score ?? 0) * 100);\n console.log(` ${c.cyan(`[${score}%]`)} ${r.content}`);\n if (Object.keys(r.metadata).length > 0) {\n console.log(` ${c.dim(JSON.stringify(r.metadata))}`);\n }\n }\n }\n brain.close();\n return;\n }\n\n // ── list ────────────────────────────────────────\n if (sub === 'list') {\n const collName = pos[2];\n const limit = parseInt(getFlag('limit') || '20', 10);\n\n if (!collName) {\n const brain = await createBrain();\n await brain.initialize();\n const names = brain.listCollectionNames();\n if (names.length === 0) {\n console.log(c.yellow(' No KV collections found.'));\n } else {\n console.log(c.bold('\\n━━━ KV Collections ━━━\\n'));\n for (const n of names) {\n const coll = brain.collection(n);\n console.log(` ${c.cyan(n)} — ${coll.count()} items`);\n }\n }\n brain.close();\n return;\n }\n\n const brain = await createBrain();\n await brain.initialize();\n const coll = brain.collection(collName);\n const items = coll.list({ limit });\n if (items.length === 0) {\n console.log(c.yellow(` Collection '${collName}' is empty.`));\n } else {\n console.log(c.bold(`\\n━━━ ${collName} (${coll.count()} items) ━━━\\n`));\n for (const item of items) {\n const age = Math.round((Date.now() / 1000 - item.createdAt) / 60);\n console.log(` #${item.id} ${c.dim(`(${age}m ago)`)} ${item.content.slice(0, 80)}`);\n }\n }\n brain.close();\n return;\n }\n\n // ── trim ────────────────────────────────────────\n if (sub === 'trim') {\n const collName = pos[2];\n const keep = parseInt(getFlag('keep') || '0', 10);\n\n if (!collName || keep <= 0) {\n console.log(c.red('Usage: brainbank kv trim <collection> --keep <n>'));\n process.exit(1);\n }\n\n const brain = await createBrain();\n await brain.initialize();\n const coll = brain.collection(collName);\n const result = await coll.trim({ keep });\n console.log(c.green(`✓ Trimmed ${result.removed} items from '${collName}' (kept ${keep})`));\n brain.close();\n return;\n }\n\n // ── clear ───────────────────────────────────────\n if (sub === 'clear') {\n const collName = pos[2];\n if (!collName) {\n console.log(c.red('Usage: brainbank kv clear <collection>'));\n process.exit(1);\n }\n\n const brain = await createBrain();\n await brain.initialize();\n const coll = brain.collection(collName);\n const before = coll.count();\n coll.clear();\n console.log(c.green(`✓ Cleared ${before} items from '${collName}'`));\n brain.close();\n return;\n }\n\n console.log(c.red('Usage: brainbank kv <add|search|list|trim|clear>'));\n process.exit(1);\n}\n\n","/**\n * brainbank docs — Index document collections\n * brainbank dsearch — Search documents only\n */\n\nimport { c, args, getFlag, stripFlags } from '@/cli/utils.ts';\nimport { createBrain } from '@/cli/factory.ts';\n\nexport async function cmdDocs(): Promise<void> {\n const collection = getFlag('collection');\n const brain = await createBrain();\n\n console.log(c.bold('\\n━━━ BrainBank Docs Index ━━━\\n'));\n\n const opts: { collections?: string[]; onProgress?: any } = {};\n if (collection) opts.collections = [collection];\n opts.onProgress = (col: string, file: string, cur: number, total: number) => {\n process.stdout.write(`\\r ${c.cyan(col)} [${cur}/${total}] ${file} `);\n };\n\n const results = await brain.indexDocs(opts);\n\n console.log('\\n');\n for (const [name, stat] of Object.entries(results)) {\n console.log(` ${c.green(name)}: ${stat.indexed} indexed, ${stat.skipped} skipped, ${stat.chunks} chunks`);\n }\n\n brain.close();\n}\n\nexport async function cmdDocSearch(): Promise<void> {\n const query = stripFlags(args).slice(1).join(' ');\n if (!query) {\n console.log(c.red('Usage: brainbank dsearch <query>'));\n process.exit(1);\n }\n\n const brain = await createBrain();\n const collection = getFlag('collection');\n const k = parseInt(getFlag('k') || '8', 10);\n\n console.log(c.bold(`\\n━━━ BrainBank Doc Search: \"${query}\" ━━━\\n`));\n\n const results = await brain.searchDocs(query, { collection: collection ?? undefined, k });\n\n if (results.length === 0) {\n console.log(c.yellow(' No results found.'));\n brain.close();\n return;\n }\n\n for (const r of results) {\n const score = Math.round(r.score * 100);\n const ctx = r.context ? ` — ${c.dim(r.context)}` : '';\n console.log(`${c.magenta(`[DOC ${score}%]`)} ${c.bold(r.filePath!)} [${(r.metadata as any).collection}]${ctx}`);\n const preview = r.content.split('\\n').slice(0, 4).join('\\n');\n console.log(c.dim(preview));\n console.log('');\n }\n\n brain.close();\n}\n","/**\n * brainbank search — Semantic search (vector)\n * brainbank hsearch — Hybrid search (vector + BM25)\n * brainbank ksearch — Keyword search (BM25)\n */\n\nimport { c, args, stripFlags, printResults } from '@/cli/utils.ts';\nimport { createBrain } from '@/cli/factory.ts';\n\nexport async function cmdSearch(): Promise<void> {\n const query = stripFlags(args).slice(1).join(' ');\n if (!query) {\n console.log(c.red('Usage: brainbank search <query>'));\n process.exit(1);\n }\n\n const brain = await createBrain();\n console.log(c.bold(`\\n━━━ BrainBank Search: \"${query}\" ━━━\\n`));\n\n const results = await brain.search(query);\n printResults(results);\n brain.close();\n}\n\nexport async function cmdHybridSearch(): Promise<void> {\n const query = stripFlags(args).slice(1).join(' ');\n if (!query) {\n console.log(c.red('Usage: brainbank hsearch <query>'));\n process.exit(1);\n }\n\n const brain = await createBrain();\n console.log(c.bold(`\\n━━━ BrainBank Hybrid Search: \"${query}\" ━━━`));\n console.log(c.dim(` Mode: vector + BM25 → Reciprocal Rank Fusion\\n`));\n\n const results = await brain.hybridSearch(query);\n printResults(results);\n brain.close();\n}\n\nexport async function cmdKeywordSearch(): Promise<void> {\n const query = stripFlags(args).slice(1).join(' ');\n if (!query) {\n console.log(c.red('Usage: brainbank ksearch <query>'));\n process.exit(1);\n }\n\n const brain = await createBrain();\n await brain.initialize();\n console.log(c.bold(`\\n━━━ BrainBank Keyword Search: \"${query}\" ━━━`));\n console.log(c.dim(` Mode: BM25 full-text (instant)\\n`));\n\n const results = await brain.searchBM25(query);\n printResults(results);\n brain.close();\n}\n","/**\n * brainbank context <task> — Get formatted context for a task\n * brainbank context add <collection> <path> <description>\n * brainbank context list\n */\n\nimport { c, args, stripFlags } from '@/cli/utils.ts';\nimport { createBrain } from '@/cli/factory.ts';\n\nexport async function cmdContext(): Promise<void> {\n const pos = stripFlags(args);\n const sub = pos[1];\n\n // brainbank context add <collection> <path> <description>\n if (sub === 'add') {\n const collection = pos[2];\n const path = pos[3];\n const desc = pos.slice(4).join(' ');\n\n if (!collection || !path || !desc) {\n console.log(c.red('Usage: brainbank context add <collection> <path> <description>'));\n process.exit(1);\n }\n\n const brain = await createBrain();\n await brain.initialize();\n brain.addContext(collection, path, desc);\n console.log(c.green(`✓ Context added: ${collection}:${path} → \"${desc}\"`));\n brain.close();\n return;\n }\n\n // brainbank context list\n if (sub === 'list') {\n const brain = await createBrain();\n await brain.initialize();\n const contexts = brain.listContexts();\n if (contexts.length === 0) {\n console.log(c.yellow(' No contexts configured.'));\n } else {\n console.log(c.bold('\\n━━━ Contexts ━━━\\n'));\n for (const ctx of contexts) {\n console.log(` ${c.cyan(ctx.collection)}:${ctx.path} → ${c.dim(ctx.context)}`);\n }\n }\n brain.close();\n return;\n }\n\n // brainbank context <task> — get formatted context\n const task = stripFlags(args).slice(1).join(' ');\n if (!task) {\n console.log(c.red('Usage: brainbank context <task description>'));\n console.log(c.dim(' brainbank context add <collection> <path> <description>'));\n console.log(c.dim(' brainbank context list'));\n process.exit(1);\n }\n\n const brain = await createBrain();\n const context = await brain.getContext(task);\n console.log(context);\n brain.close();\n}\n","/**\n * brainbank stats — Show index statistics\n * brainbank reembed — Re-embed all vectors\n * brainbank watch — Watch for file changes\n * brainbank serve — Start MCP server\n */\n\nimport { c } from '@/cli/utils.ts';\nimport { createBrain } from '@/cli/factory.ts';\n\n// ── Stats ───────────────────────────────────────────\n\nexport async function cmdStats(): Promise<void> {\n const brain = await createBrain();\n await brain.initialize();\n\n const s = brain.stats();\n\n console.log(c.bold('\\n━━━ BrainBank Stats ━━━\\n'));\n console.log(` ${c.cyan('Indexers')}: ${brain.indexers.join(', ')}\\n`);\n\n if (s.code) {\n console.log(` ${c.cyan('Code')}`);\n console.log(` Files indexed: ${s.code.files}`);\n console.log(` Code chunks: ${s.code.chunks}`);\n console.log(` HNSW vectors: ${s.code.hnswSize}`);\n console.log('');\n }\n\n if (s.git) {\n console.log(` ${c.cyan('Git History')}`);\n console.log(` Commits: ${s.git.commits}`);\n console.log(` Files tracked: ${s.git.filesTracked}`);\n console.log(` Co-edit pairs: ${s.git.coEdits}`);\n console.log(` HNSW vectors: ${s.git.hnswSize}`);\n console.log('');\n }\n\n if (s.documents) {\n console.log(` ${c.cyan('Documents')}`);\n console.log(` Collections: ${s.documents.collections}`);\n console.log(` Documents: ${s.documents.documents}`);\n console.log(` Chunks: ${s.documents.chunks}`);\n console.log(` HNSW vectors: ${s.documents.hnswSize}`);\n console.log('');\n }\n\n // KV collections\n const kvNames = brain.listCollectionNames();\n if (kvNames.length > 0) {\n console.log(` ${c.cyan('KV Collections')}`);\n for (const name of kvNames) {\n const coll = brain.collection(name);\n console.log(` ${name}: ${coll.count()} items`);\n }\n console.log('');\n }\n\n brain.close();\n}\n\n// ── Re-embed ────────────────────────────────────────\n\nexport async function cmdReembed(): Promise<void> {\n const brain = await createBrain();\n await brain.initialize();\n\n console.log(c.bold('\\n━━━ BrainBank Re-embed ━━━\\n'));\n console.log(c.dim(' Regenerating vectors with current embedding provider...'));\n console.log(c.dim(' Text, FTS, and metadata remain unchanged.\\n'));\n\n const result = await brain.reembed({\n onProgress: (table, current, total) => {\n process.stdout.write(`\\r ${c.cyan(table.padEnd(8))} ${current}/${total}`);\n },\n });\n\n console.log('\\n');\n if (result.code > 0) console.log(` ${c.green('✓')} Code: ${result.code} vectors`);\n if (result.git > 0) console.log(` ${c.green('✓')} Git: ${result.git} vectors`);\n if (result.docs > 0) console.log(` ${c.green('✓')} Docs: ${result.docs} vectors`);\n if (result.kv > 0) console.log(` ${c.green('✓')} KV: ${result.kv} vectors`);\n if (result.notes > 0) console.log(` ${c.green('✓')} Notes: ${result.notes} vectors`);\n if (result.memory > 0) console.log(` ${c.green('✓')} Memory: ${result.memory} vectors`);\n console.log(`\\n ${c.bold('Total')}: ${result.total} vectors regenerated\\n`);\n\n brain.close();\n}\n\n// ── Watch ───────────────────────────────────────────\n\nexport async function cmdWatch(): Promise<void> {\n const brain = await createBrain();\n await brain.initialize();\n\n console.log(c.bold('\\n━━━ BrainBank Watch ━━━\\n'));\n console.log(c.dim(` Watching ${brain.config.repoPath} for changes...`));\n console.log(c.dim(' Press Ctrl+C to stop.\\n'));\n\n const watcher = brain.watch({\n debounceMs: 2000,\n onIndex: (file, indexer) => {\n const ts = new Date().toLocaleTimeString();\n console.log(` ${c.dim(ts)} ${c.green('✓')} ${c.cyan(indexer)}: ${file}`);\n },\n onError: (err) => {\n console.error(` ${c.red('✗')} ${err.message}`);\n },\n });\n\n // Keep process alive, clean up on Ctrl+C\n process.on('SIGINT', () => {\n console.log(c.dim('\\n Stopping watcher...'));\n watcher.close();\n brain.close();\n process.exit(0);\n });\n\n await new Promise(() => {});\n}\n\n// ── Serve ───────────────────────────────────────────\n\nexport async function cmdServe(): Promise<void> {\n await import('@brainbank/mcp');\n}\n\n// ── Help ────────────────────────────────────────────\n\nexport function showHelp(): void {\n console.log(c.bold('\\n━━━ BrainBank — Semantic Knowledge Bank ━━━\\n'));\n console.log(c.bold('Indexing:'));\n console.log(` ${c.cyan('index')} [path] Index code + git history`);\n console.log(` ${c.cyan('collection add')} <path> --name Add a document collection`);\n console.log(` ${c.cyan('collection list')} List collections`);\n console.log(` ${c.cyan('collection remove')} <name> Remove a collection`);\n console.log(` ${c.cyan('docs')} [--collection <name>] Index document collections`);\n console.log('');\n console.log(c.bold('Search:'));\n console.log(` ${c.cyan('search')} <query> Semantic search (vector)`);\n console.log(` ${c.cyan('hsearch')} <query> Hybrid search (${c.bold('best quality')})`);\n console.log(` ${c.cyan('ksearch')} <query> Keyword search (BM25, instant)`);\n console.log(` ${c.cyan('dsearch')} <query> Document search`);\n console.log('');\n console.log(c.bold('Context:'));\n console.log(` ${c.cyan('context')} <task> Get formatted context for a task`);\n console.log(` ${c.cyan('context add')} <col> <path> <desc> Add context metadata`);\n console.log(` ${c.cyan('context list')} List all context metadata`);\n console.log('');\n console.log(c.bold('KV Store:'));\n console.log(` ${c.cyan('kv add')} <coll> <content> Add item to a collection`);\n console.log(` ${c.cyan('kv search')} <coll> <query> Search a collection`);\n console.log(` ${c.cyan('kv list')} [coll] List collections or items`);\n console.log(` ${c.cyan('kv trim')} <coll> --keep <n> Keep only N most recent`);\n console.log(` ${c.cyan('kv clear')} <coll> Clear all items`);\n console.log('');\n console.log(c.bold('Utility:'));\n console.log(` ${c.cyan('stats')} Show index statistics`);\n console.log(` ${c.cyan('reembed')} Re-embed all vectors`);\n console.log(` ${c.cyan('watch')} Watch files, auto-re-index`);\n console.log(` ${c.cyan('serve')} Start MCP server (stdio)`);\n console.log('');\n console.log(c.bold('Options:'));\n console.log(` ${c.dim('--repo <path>')} Repository path (default: .)`);\n console.log(` ${c.dim('--force')} Force re-index all files`);\n console.log(` ${c.dim('--depth <n>')} Git history depth (default: 500)`);\n console.log(` ${c.dim('--collection <name>')} Filter by collection`);\n console.log(` ${c.dim('--pattern <glob>')} Collection glob (default: **/*.md)`);\n console.log(` ${c.dim('--context <desc>')} Context description`);\n console.log(` ${c.dim('--reranker <name>')} Reranker to use (qwen3)`);\n console.log('');\n console.log(c.bold('Examples:'));\n console.log(c.dim(' brainbank index .'));\n console.log(c.dim(' brainbank kv add errors \"Fixed null pointer in api.ts\"'));\n console.log(c.dim(' brainbank kv search errors \"null pointer\"'));\n console.log(c.dim(' brainbank kv list'));\n console.log(c.dim(' brainbank hsearch \"authentication middleware\"'));\n console.log(c.dim(' brainbank context \"add rate limiting to the API\"'));\n console.log(c.dim(' brainbank serve'));\n}\n","#!/usr/bin/env node\n\n/**\n * BrainBank — CLI Entry Point\n *\n * Dispatcher that routes commands to their handler modules.\n */\n\nimport { args, c } from './utils.ts';\nimport { cmdIndex } from './commands/index-cmd.ts';\nimport { cmdCollection } from './commands/collection.ts';\nimport { cmdKv } from './commands/kv.ts';\nimport { cmdDocs, cmdDocSearch } from './commands/docs.ts';\nimport { cmdSearch, cmdHybridSearch, cmdKeywordSearch } from './commands/search.ts';\nimport { cmdContext } from './commands/context.ts';\nimport { cmdStats, cmdReembed, cmdWatch, cmdServe, showHelp } from './commands/system.ts';\n\nconst command = args[0];\n\nasync function main(): Promise<void> {\n switch (command) {\n case 'index': return cmdIndex();\n case 'collection': return cmdCollection();\n case 'kv': return cmdKv();\n case 'docs': return cmdDocs();\n case 'dsearch': return cmdDocSearch();\n case 'search': return cmdSearch();\n case 'hsearch': return cmdHybridSearch();\n case 'ksearch': return cmdKeywordSearch();\n case 'context': return cmdContext();\n case 'stats': return cmdStats();\n case 'reembed': return cmdReembed();\n case 'watch': return cmdWatch();\n case 'serve': return cmdServe();\n case 'help':\n case '--help':\n case '-h':\n showHelp();\n break;\n default:\n if (command) console.log(c.red(`Unknown command: ${command}\\n`));\n showHelp();\n process.exit(command ? 1 : 0);\n }\n}\n\nmain().catch(err => {\n console.error(c.red(`Error: ${err.message}`));\n if (process.env.BRAINBANK_DEBUG) console.error(err.stack);\n process.exit(1);\n});\n"],"mappings":"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","names":["path","path","brain","coll","path","brain"]}
1
+ {"version":3,"sources":["../src/cli/utils.ts","../src/cli/commands/index-cmd.ts","../src/cli/factory.ts","../src/cli/commands/collection.ts","../src/cli/commands/kv.ts","../src/cli/commands/docs.ts","../src/cli/commands/search.ts","../src/cli/commands/context.ts","../src/cli/commands/system.ts","../src/cli/index.ts"],"sourcesContent":["/**\n * BrainBank CLI — Shared Utilities\n *\n * Colors, argument parsing, and result formatting.\n * No BrainBank imports — pure Node.js / terminal helpers.\n */\n\n// ── Colors ──────────────────────────────────────────\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// ── Argument Parsing ────────────────────────────────\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\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', 'only', 'docs',\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 * stripFlags(['ksearch', 'auth', '--repo', '/path'])\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 if (VALUE_FLAGS.has(name)) i++; // skip next (the value)\n continue;\n }\n result.push(argv[i]);\n }\n return result;\n}\n\n// ── Result Printer ──────────────────────────────────\n\nexport function printResults(results: any[]): void {\n if (results.length === 0) {\n console.log(c.yellow(' No results found.'));\n return;\n }\n\n for (const r of results) {\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 * brainbank index [path] — Index code + git + docs\n */\n\nimport * as path from 'node:path';\nimport { c, args, getFlag, hasFlag } from '@/cli/utils.ts';\nimport { createBrain } from '@/cli/factory.ts';\n\nexport async function cmdIndex(): Promise<void> {\n const repoPath = args[1] || '.';\n const force = hasFlag('force');\n const depth = parseInt(getFlag('depth') || '500', 10);\n const onlyRaw = getFlag('only');\n const docsPath = getFlag('docs');\n const modules = onlyRaw\n ? onlyRaw.split(',').map(s => s.trim()) as ('code' | 'git' | 'docs')[]\n : undefined;\n\n // If --docs is passed, auto-include 'docs' in modules\n if (docsPath && modules && !modules.includes('docs')) {\n modules.push('docs');\n }\n\n console.log(c.bold('\\n━━━ BrainBank Index ━━━'));\n console.log(c.dim(` Repo: ${repoPath}`));\n console.log(c.dim(` Force: ${force}`));\n console.log(c.dim(` Git depth: ${depth}`));\n if (modules) console.log(c.dim(` Modules: ${modules.join(', ')}`));\n if (docsPath) console.log(c.dim(` Docs path: ${docsPath}`));\n\n const brain = await createBrain(repoPath);\n\n // Auto-register docs collection from --docs path\n if (docsPath) {\n const absDocsPath = path.resolve(docsPath);\n const collName = path.basename(absDocsPath);\n try {\n await brain.addCollection({\n name: collName,\n path: absDocsPath,\n pattern: '**/*.md',\n ignore: ['deprecated/**', 'node_modules/**'],\n });\n console.log(c.dim(` Registered docs collection: ${collName}`));\n } catch {\n console.log(c.yellow(` Warning: docs module not loaded, skipping --docs`));\n }\n }\n\n const result = await brain.index({\n modules,\n forceReindex: force,\n gitDepth: depth,\n onProgress: (stage, msg) => {\n process.stdout.write(`\\r ${c.cyan(stage.toUpperCase())} ${msg} `);\n },\n });\n\n console.log('\\n');\n if (result.code) {\n console.log(` ${c.green('Code')}: ${result.code.indexed} indexed, ${result.code.skipped} skipped, ${result.code.chunks ?? 0} chunks`);\n }\n if (result.git) {\n console.log(` ${c.green('Git')}: ${result.git.indexed} indexed, ${result.git.skipped} skipped`);\n }\n if (result.docs) {\n for (const [name, stat] of Object.entries(result.docs)) {\n console.log(` ${c.green('Docs')}: [${name}] ${stat.indexed} indexed, ${stat.skipped} skipped, ${stat.chunks} chunks`);\n }\n }\n\n const stats = brain.stats();\n console.log(`\\n ${c.bold('Totals')}:`);\n if (stats.code) console.log(` Code chunks: ${stats.code.chunks}`);\n if (stats.git) console.log(` Git commits: ${stats.git.commits}`);\n if (stats.git) console.log(` Co-edit pairs: ${stats.git.coEdits}`);\n if (stats.documents) console.log(` Documents: ${stats.documents.documents}`);\n\n brain.close();\n}\n","/**\n * BrainBank CLI — Brain Factory\n *\n * Creates a configured BrainBank instance with built-in indexers,\n * auto-discovered indexers, and config file support.\n */\n\nimport * as path from 'node:path';\nimport * as fs from 'node:fs';\nimport { BrainBank } from '@/brainbank.ts';\nimport { code } from '@/indexers/code/code-plugin.ts';\nimport { git } from '@/indexers/git/git-plugin.ts';\nimport { docs } from '@/indexers/docs/docs-plugin.ts';\nimport type { Indexer } from '@/indexers/base.ts';\nimport { c, getFlag } from './utils.ts';\n\n// ── Types ───────────────────────────────────────────\n\ninterface BrainBankCliConfig {\n /** Custom indexers to register alongside built-in ones. */\n indexers?: Indexer[];\n /** Override which built-in indexers to load. Default: ['code', 'git', 'docs'] */\n builtins?: ('code' | 'git' | 'docs')[];\n /** BrainBank constructor options. */\n brainbank?: Record<string, any>;\n}\n\nconst CONFIG_NAMES = ['config.ts', 'config.js', 'config.mjs'];\nconst INDEXER_EXTENSIONS = ['.ts', '.js', '.mjs'];\n\n// ── Caches ──────────────────────────────────────────\n\nlet _configCache: BrainBankCliConfig | null | undefined = undefined;\nlet _folderIndexersCache: Indexer[] | undefined = undefined;\n\n// ── Config Loader ───────────────────────────────────\n\n/** Load .brainbank/config.ts if present. */\nasync function loadConfig(): Promise<BrainBankCliConfig | null> {\n if (_configCache !== undefined) return _configCache;\n\n const repoPath = getFlag('repo') ?? '.';\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)) {\n try {\n const mod = await import(configPath);\n _configCache = (mod.default ?? mod) as BrainBankCliConfig;\n return _configCache;\n } catch (err: any) {\n console.error(c.red(`Error loading .brainbank/${name}: ${err.message}`));\n process.exit(1);\n }\n }\n }\n\n _configCache = null;\n return null;\n}\n\n// ── Indexer Discovery ───────────────────────────────\n\n/** Auto-discover indexers from .brainbank/indexers/ folder. */\nasync function discoverFolderIndexers(): Promise<Indexer[]> {\n if (_folderIndexersCache !== undefined) return _folderIndexersCache;\n\n const repoPath = getFlag('repo') ?? '.';\n const indexersDir = path.resolve(repoPath, '.brainbank', 'indexers');\n\n if (!fs.existsSync(indexersDir)) {\n _folderIndexersCache = [];\n return [];\n }\n\n const files = fs.readdirSync(indexersDir)\n .filter(f => INDEXER_EXTENSIONS.some(ext => f.endsWith(ext)))\n .sort();\n\n const indexers: Indexer[] = [];\n\n for (const file of files) {\n const filePath = path.join(indexersDir, file);\n try {\n const mod = await import(filePath);\n const indexer = mod.default ?? mod;\n\n if (indexer && typeof indexer === 'object' && indexer.name) {\n indexers.push(indexer as Indexer);\n } else {\n console.error(c.yellow(`⚠ ${file}: must export a default Indexer with a 'name' property, skipping`));\n }\n } catch (err: any) {\n console.error(c.red(`Error loading indexer ${file}: ${err.message}`));\n }\n }\n\n _folderIndexersCache = indexers;\n return indexers;\n}\n\n// ── Multi-repo Detection ────────────────────────────\n\n/** Detect subdirectories that have their own .git repo. */\nfunction detectGitSubdirs(parentPath: string): { name: string; path: string }[] {\n try {\n const entries = fs.readdirSync(parentPath, { withFileTypes: true });\n return entries\n .filter(e =>\n e.isDirectory() &&\n !e.name.startsWith('.') &&\n !e.name.startsWith('node_modules') &&\n fs.existsSync(path.join(parentPath, e.name, '.git')),\n )\n .map(e => ({ name: e.name, path: path.join(parentPath, e.name) }));\n } catch {\n return [];\n }\n}\n\n// ── Factory ─────────────────────────────────────────\n\n/** Create a BrainBank with built-in + discovered + config indexers. */\nexport async function createBrain(repoPath?: string): Promise<BrainBank> {\n const rp = repoPath ?? getFlag('repo') ?? '.';\n const config = await loadConfig();\n const folderIndexers = await discoverFolderIndexers();\n\n const brainOpts: Record<string, any> = { repoPath: rp, ...(config?.brainbank ?? {}) };\n await setupProviders(brainOpts);\n\n const brain = new BrainBank(brainOpts);\n const builtins = config?.builtins ?? ['code', 'git', 'docs'];\n registerBuiltins(brain, rp, builtins);\n\n for (const indexer of folderIndexers) brain.use(indexer);\n if (config?.indexers) {\n for (const indexer of config.indexers) brain.use(indexer);\n }\n\n return brain;\n}\n\n/** Configure reranker and embedding provider on brainOpts. */\nasync function setupProviders(brainOpts: Record<string, any>): Promise<void> {\n const rerankerFlag = getFlag('reranker');\n if (rerankerFlag === 'qwen3') {\n const { Qwen3Reranker } = await import('@brainbank/reranker');\n brainOpts.reranker = new Qwen3Reranker();\n }\n\n if (process.env.BRAINBANK_EMBEDDING === 'openai') {\n const { OpenAIEmbedding } = await import('../providers/embeddings/openai-embedding.ts');\n const provider = new OpenAIEmbedding();\n brainOpts.embeddingProvider = provider;\n brainOpts.embeddingDims = provider.dims;\n } else if (process.env.BRAINBANK_EMBEDDING === 'perplexity') {\n const { PerplexityEmbedding } = await import('../providers/embeddings/perplexity-embedding.ts');\n const provider = new PerplexityEmbedding();\n brainOpts.embeddingProvider = provider;\n brainOpts.embeddingDims = provider.dims;\n } else if (process.env.BRAINBANK_EMBEDDING === 'perplexity-context') {\n const { PerplexityContextEmbedding } = await import('../providers/embeddings/perplexity-context-embedding.ts');\n const provider = new PerplexityContextEmbedding();\n brainOpts.embeddingProvider = provider;\n brainOpts.embeddingDims = provider.dims;\n }\n}\n\n/** Register built-in indexers with multi-repo detection. */\nfunction registerBuiltins(\n brain: BrainBank, rp: string, builtins: ('code' | 'git' | 'docs')[],\n): void {\n const resolvedRp = path.resolve(rp);\n const hasRootGit = fs.existsSync(path.join(resolvedRp, '.git'));\n const gitSubdirs = !hasRootGit ? detectGitSubdirs(resolvedRp) : [];\n\n if (gitSubdirs.length > 0 && (builtins.includes('code') || builtins.includes('git'))) {\n console.log(c.cyan(` Multi-repo: found ${gitSubdirs.length} git repos: ${gitSubdirs.map(d => d.name).join(', ')}`));\n for (const sub of gitSubdirs) {\n if (builtins.includes('code')) brain.use(code({ repoPath: sub.path, name: `code:${sub.name}` }));\n if (builtins.includes('git')) brain.use(git({ repoPath: sub.path, name: `git:${sub.name}` }));\n }\n } else {\n if (builtins.includes('code')) brain.use(code({ repoPath: rp }));\n if (builtins.includes('git')) brain.use(git());\n }\n\n if (builtins.includes('docs')) brain.use(docs());\n}\n","/**\n * brainbank collection add|list|remove — Document collection management\n */\n\nimport { c, args, getFlag, stripFlags } from '@/cli/utils.ts';\nimport { createBrain } from '@/cli/factory.ts';\n\nexport async function cmdCollection(): Promise<void> {\n const pos = stripFlags(args);\n const sub = pos[1];\n\n if (sub === 'add') {\n const path = pos[2];\n const name = getFlag('name');\n const pattern = getFlag('pattern') ?? '**/*.md';\n const context = getFlag('context');\n const ignoreRaw = getFlag('ignore');\n\n if (!path || !name) {\n console.log(c.red('Usage: brainbank collection add <path> --name <name> [--pattern \"**/*.md\"] [--ignore \"glob\"] [--context \"description\"]'));\n process.exit(1);\n }\n\n const brain = await createBrain();\n await brain.addCollection({\n name,\n path,\n pattern,\n ignore: ignoreRaw ? ignoreRaw.split(',') : [],\n context: context ?? undefined,\n });\n console.log(c.green(`✓ Collection '${name}' added: ${path} (${pattern})`));\n if (context) console.log(c.dim(` Context: ${context}`));\n brain.close();\n return;\n }\n\n if (sub === 'list') {\n const brain = await createBrain();\n await brain.initialize();\n const collections = brain.listCollections();\n if (collections.length === 0) {\n console.log(c.yellow(' No collections registered.'));\n } else {\n console.log(c.bold('\\n━━━ Collections ━━━\\n'));\n for (const col of collections) {\n console.log(` ${c.cyan(col.name)} ${c.dim('→')} ${col.path}`);\n console.log(` Pattern: ${col.pattern ?? '**/*.md'}`);\n if (col.context) console.log(` Context: ${c.dim(col.context)}`);\n }\n }\n brain.close();\n return;\n }\n\n if (sub === 'remove') {\n const name = pos[2];\n if (!name) {\n console.log(c.red('Usage: brainbank collection remove <name>'));\n process.exit(1);\n }\n const brain = await createBrain();\n await brain.removeCollection(name);\n console.log(c.green(`✓ Collection '${name}' removed.`));\n brain.close();\n return;\n }\n\n console.log(c.red('Usage: brainbank collection <add|list|remove>'));\n process.exit(1);\n}\n","/**\n * brainbank kv add|search|list|trim|clear — Dynamic KV collection management\n */\n\nimport { c, args, getFlag, stripFlags } from '@/cli/utils.ts';\nimport { createBrain } from '@/cli/factory.ts';\n\nexport async function cmdKv(): Promise<void> {\n const pos = stripFlags(args);\n const sub = pos[1];\n\n // ── add ─────────────────────────────────────────\n if (sub === 'add') {\n const collName = pos[2];\n const content = pos.slice(3).join(' ');\n const metaRaw = getFlag('meta');\n\n if (!collName || !content) {\n console.log(c.red(\"Usage: brainbank kv add <collection> <content> [--meta '{\\\"key\\\":\\\"val\\\"}']\"));\n process.exit(1);\n }\n\n const brain = await createBrain();\n await brain.initialize();\n const coll = brain.collection(collName);\n const meta = metaRaw ? JSON.parse(metaRaw) : {};\n const id = await coll.add(content, meta);\n console.log(c.green(`✓ Added item #${id} to '${collName}'`));\n brain.close();\n return;\n }\n\n // ── search ──────────────────────────────────────\n if (sub === 'search') {\n const collName = pos[2];\n const query = pos.slice(3).join(' ');\n const k = parseInt(getFlag('k') || '5', 10);\n const mode = (getFlag('mode') as any) || 'hybrid';\n\n if (!collName || !query) {\n console.log(c.red('Usage: brainbank kv search <collection> <query> [--k 5] [--mode hybrid|keyword|vector]'));\n process.exit(1);\n }\n\n const brain = await createBrain();\n await brain.initialize();\n const coll = brain.collection(collName);\n const results = await coll.search(query, { k, mode });\n\n if (results.length === 0) {\n console.log(c.yellow(' No results found.'));\n } else {\n console.log(c.bold(`\\n━━━ ${collName}: \"${query}\" ━━━\\n`));\n for (const r of results) {\n const score = Math.round((r.score ?? 0) * 100);\n console.log(` ${c.cyan(`[${score}%]`)} ${r.content}`);\n if (Object.keys(r.metadata).length > 0) {\n console.log(` ${c.dim(JSON.stringify(r.metadata))}`);\n }\n }\n }\n brain.close();\n return;\n }\n\n // ── list ────────────────────────────────────────\n if (sub === 'list') {\n const collName = pos[2];\n const limit = parseInt(getFlag('limit') || '20', 10);\n\n if (!collName) {\n const brain = await createBrain();\n await brain.initialize();\n const names = brain.listCollectionNames();\n if (names.length === 0) {\n console.log(c.yellow(' No KV collections found.'));\n } else {\n console.log(c.bold('\\n━━━ KV Collections ━━━\\n'));\n for (const n of names) {\n const coll = brain.collection(n);\n console.log(` ${c.cyan(n)} — ${coll.count()} items`);\n }\n }\n brain.close();\n return;\n }\n\n const brain = await createBrain();\n await brain.initialize();\n const coll = brain.collection(collName);\n const items = coll.list({ limit });\n if (items.length === 0) {\n console.log(c.yellow(` Collection '${collName}' is empty.`));\n } else {\n console.log(c.bold(`\\n━━━ ${collName} (${coll.count()} items) ━━━\\n`));\n for (const item of items) {\n const age = Math.round((Date.now() / 1000 - item.createdAt) / 60);\n console.log(` #${item.id} ${c.dim(`(${age}m ago)`)} ${item.content.slice(0, 80)}`);\n }\n }\n brain.close();\n return;\n }\n\n // ── trim ────────────────────────────────────────\n if (sub === 'trim') {\n const collName = pos[2];\n const keep = parseInt(getFlag('keep') || '0', 10);\n\n if (!collName || keep <= 0) {\n console.log(c.red('Usage: brainbank kv trim <collection> --keep <n>'));\n process.exit(1);\n }\n\n const brain = await createBrain();\n await brain.initialize();\n const coll = brain.collection(collName);\n const result = await coll.trim({ keep });\n console.log(c.green(`✓ Trimmed ${result.removed} items from '${collName}' (kept ${keep})`));\n brain.close();\n return;\n }\n\n // ── clear ───────────────────────────────────────\n if (sub === 'clear') {\n const collName = pos[2];\n if (!collName) {\n console.log(c.red('Usage: brainbank kv clear <collection>'));\n process.exit(1);\n }\n\n const brain = await createBrain();\n await brain.initialize();\n const coll = brain.collection(collName);\n const before = coll.count();\n coll.clear();\n console.log(c.green(`✓ Cleared ${before} items from '${collName}'`));\n brain.close();\n return;\n }\n\n console.log(c.red('Usage: brainbank kv <add|search|list|trim|clear>'));\n process.exit(1);\n}\n\n","/**\n * brainbank docs — Index document collections\n * brainbank dsearch — Search documents only\n */\n\nimport { c, args, getFlag, stripFlags } from '@/cli/utils.ts';\nimport { createBrain } from '@/cli/factory.ts';\n\nexport async function cmdDocs(): Promise<void> {\n const collection = getFlag('collection');\n const brain = await createBrain();\n\n console.log(c.bold('\\n━━━ BrainBank Docs Index ━━━\\n'));\n\n const opts: { collections?: string[]; onProgress?: any } = {};\n if (collection) opts.collections = [collection];\n opts.onProgress = (col: string, file: string, cur: number, total: number) => {\n process.stdout.write(`\\r ${c.cyan(col)} [${cur}/${total}] ${file} `);\n };\n\n const results = await brain.indexDocs(opts);\n\n console.log('\\n');\n for (const [name, stat] of Object.entries(results)) {\n console.log(` ${c.green(name)}: ${stat.indexed} indexed, ${stat.skipped} skipped, ${stat.chunks} chunks`);\n }\n\n brain.close();\n}\n\nexport async function cmdDocSearch(): Promise<void> {\n const query = stripFlags(args).slice(1).join(' ');\n if (!query) {\n console.log(c.red('Usage: brainbank dsearch <query>'));\n process.exit(1);\n }\n\n const brain = await createBrain();\n const collection = getFlag('collection');\n const k = parseInt(getFlag('k') || '8', 10);\n\n console.log(c.bold(`\\n━━━ BrainBank Doc Search: \"${query}\" ━━━\\n`));\n\n const results = await brain.searchDocs(query, { collection: collection ?? undefined, k });\n\n if (results.length === 0) {\n console.log(c.yellow(' No results found.'));\n brain.close();\n return;\n }\n\n for (const r of results) {\n const score = Math.round(r.score * 100);\n const ctx = r.context ? ` — ${c.dim(r.context)}` : '';\n console.log(`${c.magenta(`[DOC ${score}%]`)} ${c.bold(r.filePath!)} [${(r.metadata as any).collection}]${ctx}`);\n const preview = r.content.split('\\n').slice(0, 4).join('\\n');\n console.log(c.dim(preview));\n console.log('');\n }\n\n brain.close();\n}\n","/**\n * brainbank search — Semantic search (vector)\n * brainbank hsearch — Hybrid search (vector + BM25)\n * brainbank ksearch — Keyword search (BM25)\n */\n\nimport { c, args, stripFlags, printResults } from '@/cli/utils.ts';\nimport { createBrain } from '@/cli/factory.ts';\n\nexport async function cmdSearch(): Promise<void> {\n const query = stripFlags(args).slice(1).join(' ');\n if (!query) {\n console.log(c.red('Usage: brainbank search <query>'));\n process.exit(1);\n }\n\n const brain = await createBrain();\n console.log(c.bold(`\\n━━━ BrainBank Search: \"${query}\" ━━━\\n`));\n\n const results = await brain.search(query);\n printResults(results);\n brain.close();\n}\n\nexport async function cmdHybridSearch(): Promise<void> {\n const query = stripFlags(args).slice(1).join(' ');\n if (!query) {\n console.log(c.red('Usage: brainbank hsearch <query>'));\n process.exit(1);\n }\n\n const brain = await createBrain();\n console.log(c.bold(`\\n━━━ BrainBank Hybrid Search: \"${query}\" ━━━`));\n console.log(c.dim(` Mode: vector + BM25 → Reciprocal Rank Fusion\\n`));\n\n const results = await brain.hybridSearch(query);\n printResults(results);\n brain.close();\n}\n\nexport async function cmdKeywordSearch(): Promise<void> {\n const query = stripFlags(args).slice(1).join(' ');\n if (!query) {\n console.log(c.red('Usage: brainbank ksearch <query>'));\n process.exit(1);\n }\n\n const brain = await createBrain();\n await brain.initialize();\n console.log(c.bold(`\\n━━━ BrainBank Keyword Search: \"${query}\" ━━━`));\n console.log(c.dim(` Mode: BM25 full-text (instant)\\n`));\n\n const results = await brain.searchBM25(query);\n printResults(results);\n brain.close();\n}\n","/**\n * brainbank context <task> — Get formatted context for a task\n * brainbank context add <collection> <path> <description>\n * brainbank context list\n */\n\nimport { c, args, stripFlags } from '@/cli/utils.ts';\nimport { createBrain } from '@/cli/factory.ts';\n\nexport async function cmdContext(): Promise<void> {\n const pos = stripFlags(args);\n const sub = pos[1];\n\n // brainbank context add <collection> <path> <description>\n if (sub === 'add') {\n const collection = pos[2];\n const path = pos[3];\n const desc = pos.slice(4).join(' ');\n\n if (!collection || !path || !desc) {\n console.log(c.red('Usage: brainbank context add <collection> <path> <description>'));\n process.exit(1);\n }\n\n const brain = await createBrain();\n await brain.initialize();\n brain.addContext(collection, path, desc);\n console.log(c.green(`✓ Context added: ${collection}:${path} → \"${desc}\"`));\n brain.close();\n return;\n }\n\n // brainbank context list\n if (sub === 'list') {\n const brain = await createBrain();\n await brain.initialize();\n const contexts = brain.listContexts();\n if (contexts.length === 0) {\n console.log(c.yellow(' No contexts configured.'));\n } else {\n console.log(c.bold('\\n━━━ Contexts ━━━\\n'));\n for (const ctx of contexts) {\n console.log(` ${c.cyan(ctx.collection)}:${ctx.path} → ${c.dim(ctx.context)}`);\n }\n }\n brain.close();\n return;\n }\n\n // brainbank context <task> — get formatted context\n const task = stripFlags(args).slice(1).join(' ');\n if (!task) {\n console.log(c.red('Usage: brainbank context <task description>'));\n console.log(c.dim(' brainbank context add <collection> <path> <description>'));\n console.log(c.dim(' brainbank context list'));\n process.exit(1);\n }\n\n const brain = await createBrain();\n const context = await brain.getContext(task);\n console.log(context);\n brain.close();\n}\n","/**\n * brainbank stats — Show index statistics\n * brainbank reembed — Re-embed all vectors\n * brainbank watch — Watch for file changes\n * brainbank serve — Start MCP server\n */\n\nimport { c } from '@/cli/utils.ts';\nimport { createBrain } from '@/cli/factory.ts';\n\n// ── Stats ───────────────────────────────────────────\n\nexport async function cmdStats(): Promise<void> {\n const brain = await createBrain();\n await brain.initialize();\n\n const s = brain.stats();\n\n console.log(c.bold('\\n━━━ BrainBank Stats ━━━\\n'));\n console.log(` ${c.cyan('Indexers')}: ${brain.indexers.join(', ')}\\n`);\n\n if (s.code) {\n console.log(` ${c.cyan('Code')}`);\n console.log(` Files indexed: ${s.code.files}`);\n console.log(` Code chunks: ${s.code.chunks}`);\n console.log(` HNSW vectors: ${s.code.hnswSize}`);\n console.log('');\n }\n\n if (s.git) {\n console.log(` ${c.cyan('Git History')}`);\n console.log(` Commits: ${s.git.commits}`);\n console.log(` Files tracked: ${s.git.filesTracked}`);\n console.log(` Co-edit pairs: ${s.git.coEdits}`);\n console.log(` HNSW vectors: ${s.git.hnswSize}`);\n console.log('');\n }\n\n if (s.documents) {\n console.log(` ${c.cyan('Documents')}`);\n console.log(` Collections: ${s.documents.collections}`);\n console.log(` Documents: ${s.documents.documents}`);\n console.log(` Chunks: ${s.documents.chunks}`);\n console.log(` HNSW vectors: ${s.documents.hnswSize}`);\n console.log('');\n }\n\n // KV collections\n const kvNames = brain.listCollectionNames();\n if (kvNames.length > 0) {\n console.log(` ${c.cyan('KV Collections')}`);\n for (const name of kvNames) {\n const coll = brain.collection(name);\n console.log(` ${name}: ${coll.count()} items`);\n }\n console.log('');\n }\n\n brain.close();\n}\n\n// ── Re-embed ────────────────────────────────────────\n\nexport async function cmdReembed(): Promise<void> {\n const brain = await createBrain();\n await brain.initialize();\n\n console.log(c.bold('\\n━━━ BrainBank Re-embed ━━━\\n'));\n console.log(c.dim(' Regenerating vectors with current embedding provider...'));\n console.log(c.dim(' Text, FTS, and metadata remain unchanged.\\n'));\n\n const result = await brain.reembed({\n onProgress: (table, current, total) => {\n process.stdout.write(`\\r ${c.cyan(table.padEnd(8))} ${current}/${total}`);\n },\n });\n\n console.log('\\n');\n if (result.code > 0) console.log(` ${c.green('✓')} Code: ${result.code} vectors`);\n if (result.git > 0) console.log(` ${c.green('✓')} Git: ${result.git} vectors`);\n if (result.docs > 0) console.log(` ${c.green('✓')} Docs: ${result.docs} vectors`);\n if (result.kv > 0) console.log(` ${c.green('✓')} KV: ${result.kv} vectors`);\n if (result.notes > 0) console.log(` ${c.green('✓')} Notes: ${result.notes} vectors`);\n if (result.memory > 0) console.log(` ${c.green('✓')} Memory: ${result.memory} vectors`);\n console.log(`\\n ${c.bold('Total')}: ${result.total} vectors regenerated\\n`);\n\n brain.close();\n}\n\n// ── Watch ───────────────────────────────────────────\n\nexport async function cmdWatch(): Promise<void> {\n const brain = await createBrain();\n await brain.initialize();\n\n console.log(c.bold('\\n━━━ BrainBank Watch ━━━\\n'));\n console.log(c.dim(` Watching ${brain.config.repoPath} for changes...`));\n console.log(c.dim(' Press Ctrl+C to stop.\\n'));\n\n const watcher = brain.watch({\n debounceMs: 2000,\n onIndex: (file, indexer) => {\n const ts = new Date().toLocaleTimeString();\n console.log(` ${c.dim(ts)} ${c.green('✓')} ${c.cyan(indexer)}: ${file}`);\n },\n onError: (err) => {\n console.error(` ${c.red('✗')} ${err.message}`);\n },\n });\n\n // Keep process alive, clean up on Ctrl+C\n process.on('SIGINT', () => {\n console.log(c.dim('\\n Stopping watcher...'));\n watcher.close();\n brain.close();\n process.exit(0);\n });\n\n await new Promise(() => {});\n}\n\n// ── Serve ───────────────────────────────────────────\n\nexport async function cmdServe(): Promise<void> {\n await import('@brainbank/mcp');\n}\n\n// ── Help ────────────────────────────────────────────\n\nexport function showHelp(): void {\n console.log(c.bold('\\n━━━ BrainBank — Semantic Knowledge Bank ━━━\\n'));\n console.log(c.bold('Indexing:'));\n console.log(` ${c.cyan('index')} [path] Index code + git history`);\n console.log(` ${c.cyan('collection add')} <path> --name Add a document collection`);\n console.log(` ${c.cyan('collection list')} List collections`);\n console.log(` ${c.cyan('collection remove')} <name> Remove a collection`);\n console.log(` ${c.cyan('docs')} [--collection <name>] Index document collections`);\n console.log('');\n console.log(c.bold('Search:'));\n console.log(` ${c.cyan('search')} <query> Semantic search (vector)`);\n console.log(` ${c.cyan('hsearch')} <query> Hybrid search (${c.bold('best quality')})`);\n console.log(` ${c.cyan('ksearch')} <query> Keyword search (BM25, instant)`);\n console.log(` ${c.cyan('dsearch')} <query> Document search`);\n console.log('');\n console.log(c.bold('Context:'));\n console.log(` ${c.cyan('context')} <task> Get formatted context for a task`);\n console.log(` ${c.cyan('context add')} <col> <path> <desc> Add context metadata`);\n console.log(` ${c.cyan('context list')} List all context metadata`);\n console.log('');\n console.log(c.bold('KV Store:'));\n console.log(` ${c.cyan('kv add')} <coll> <content> Add item to a collection`);\n console.log(` ${c.cyan('kv search')} <coll> <query> Search a collection`);\n console.log(` ${c.cyan('kv list')} [coll] List collections or items`);\n console.log(` ${c.cyan('kv trim')} <coll> --keep <n> Keep only N most recent`);\n console.log(` ${c.cyan('kv clear')} <coll> Clear all items`);\n console.log('');\n console.log(c.bold('Utility:'));\n console.log(` ${c.cyan('stats')} Show index statistics`);\n console.log(` ${c.cyan('reembed')} Re-embed all vectors`);\n console.log(` ${c.cyan('watch')} Watch files, auto-re-index`);\n console.log(` ${c.cyan('serve')} Start MCP server (stdio)`);\n console.log('');\n console.log(c.bold('Options:'));\n console.log(` ${c.dim('--repo <path>')} Repository path (default: .)`);\n console.log(` ${c.dim('--force')} Force re-index all files`);\n console.log(` ${c.dim('--depth <n>')} Git history depth (default: 500)`);\n console.log(` ${c.dim('--collection <name>')} Filter by collection`);\n console.log(` ${c.dim('--pattern <glob>')} Collection glob (default: **/*.md)`);\n console.log(` ${c.dim('--context <desc>')} Context description`);\n console.log(` ${c.dim('--reranker <name>')} Reranker to use (qwen3)`);\n console.log('');\n console.log(c.bold('Examples:'));\n console.log(c.dim(' brainbank index .'));\n console.log(c.dim(' brainbank kv add errors \"Fixed null pointer in api.ts\"'));\n console.log(c.dim(' brainbank kv search errors \"null pointer\"'));\n console.log(c.dim(' brainbank kv list'));\n console.log(c.dim(' brainbank hsearch \"authentication middleware\"'));\n console.log(c.dim(' brainbank context \"add rate limiting to the API\"'));\n console.log(c.dim(' brainbank serve'));\n}\n","#!/usr/bin/env node\n\n/**\n * BrainBank — CLI Entry Point\n *\n * Dispatcher that routes commands to their handler modules.\n */\n\nimport { args, c } from './utils.ts';\nimport { cmdIndex } from './commands/index-cmd.ts';\nimport { cmdCollection } from './commands/collection.ts';\nimport { cmdKv } from './commands/kv.ts';\nimport { cmdDocs, cmdDocSearch } from './commands/docs.ts';\nimport { cmdSearch, cmdHybridSearch, cmdKeywordSearch } from './commands/search.ts';\nimport { cmdContext } from './commands/context.ts';\nimport { cmdStats, cmdReembed, cmdWatch, cmdServe, showHelp } from './commands/system.ts';\n\nconst command = args[0];\n\nasync function main(): Promise<void> {\n switch (command) {\n case 'index': return cmdIndex();\n case 'collection': return cmdCollection();\n case 'kv': return cmdKv();\n case 'docs': return cmdDocs();\n case 'dsearch': return cmdDocSearch();\n case 'search': return cmdSearch();\n case 'hsearch': return cmdHybridSearch();\n case 'ksearch': return cmdKeywordSearch();\n case 'context': return cmdContext();\n case 'stats': return cmdStats();\n case 'reembed': return cmdReembed();\n case 'watch': return cmdWatch();\n case 'serve': return cmdServe();\n case 'help':\n case '--help':\n case '-h':\n showHelp();\n break;\n default:\n if (command) console.log(c.red(`Unknown command: ${command}\\n`));\n showHelp();\n process.exit(command ? 1 : 0);\n }\n}\n\nmain().catch(err => {\n console.error(c.red(`Error: ${err.message}`));\n if (process.env.BRAINBANK_DEBUG) console.error(err.stack);\n process.exit(1);\n});\n"],"mappings":"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","names":["path","path","brain","coll","path","brain"]}
package/dist/index.d.ts CHANGED
@@ -328,6 +328,99 @@ declare class OpenAIEmbedding implements EmbeddingProvider {
328
328
  private _handleApiError;
329
329
  }
330
330
 
331
+ /**
332
+ * BrainBank — Perplexity Standard Embedding Provider
333
+ *
334
+ * Uses Perplexity's embedding API via fetch (no SDK dependency).
335
+ * Models: pplx-embed-v1-0.6b (1024d) and pplx-embed-v1-4b (2560d).
336
+ *
337
+ * Perplexity returns base64-encoded signed int8 vectors by default.
338
+ * This provider decodes them to Float32Array for HNSW compatibility.
339
+ *
340
+ * Usage:
341
+ * const brain = new BrainBank({
342
+ * embeddingProvider: new PerplexityEmbedding({ model: 'pplx-embed-v1-4b' }),
343
+ * });
344
+ */
345
+
346
+ interface PerplexityEmbeddingOptions {
347
+ /** Perplexity API key. Falls back to PERPLEXITY_API_KEY env var. */
348
+ apiKey?: string;
349
+ /** Model name. Default: 'pplx-embed-v1-4b' */
350
+ model?: string;
351
+ /** Vector dimensions (Matryoshka reduction). If omitted, uses model default. */
352
+ dims?: number;
353
+ /** Base URL override. */
354
+ baseUrl?: string;
355
+ /** Request timeout in ms. Default: 30000 */
356
+ timeout?: number;
357
+ }
358
+ declare class PerplexityEmbedding implements EmbeddingProvider {
359
+ readonly dims: number;
360
+ private _apiKey;
361
+ private _model;
362
+ private _baseUrl;
363
+ private _requestDims;
364
+ private _timeout;
365
+ constructor(options?: PerplexityEmbeddingOptions);
366
+ embed(text: string): Promise<Float32Array>;
367
+ embedBatch(texts: string[]): Promise<Float32Array[]>;
368
+ close(): Promise<void>;
369
+ private _request;
370
+ }
371
+
372
+ /**
373
+ * BrainBank — Perplexity Contextualized Embedding Provider
374
+ *
375
+ * Uses Perplexity's contextualized embeddings API for document-aware vectors.
376
+ * Chunks from the same document share context, improving retrieval quality.
377
+ *
378
+ * Models: pplx-embed-context-v1-0.6b (1024d), pplx-embed-context-v1-4b (2560d).
379
+ *
380
+ * Key difference from standard: input is string[][] (docs × chunks) and the
381
+ * response has a nested structure. This provider adapts the flat BrainBank
382
+ * EmbeddingProvider interface to the nested Perplexity API:
383
+ * - embed(text) → wraps as [[text]]
384
+ * - embedBatch(texts) → wraps as [texts] (one "document" of related chunks)
385
+ *
386
+ * Usage:
387
+ * const brain = new BrainBank({
388
+ * embeddingProvider: new PerplexityContextEmbedding(),
389
+ * });
390
+ */
391
+
392
+ interface PerplexityContextEmbeddingOptions {
393
+ /** Perplexity API key. Falls back to PERPLEXITY_API_KEY env var. */
394
+ apiKey?: string;
395
+ /** Model name. Default: 'pplx-embed-context-v1-4b' */
396
+ model?: string;
397
+ /** Vector dimensions (Matryoshka reduction). If omitted, uses model default. */
398
+ dims?: number;
399
+ /** Base URL override. */
400
+ baseUrl?: string;
401
+ /** Request timeout in ms. Default: 30000 */
402
+ timeout?: number;
403
+ }
404
+ declare class PerplexityContextEmbedding implements EmbeddingProvider {
405
+ readonly dims: number;
406
+ private _apiKey;
407
+ private _model;
408
+ private _baseUrl;
409
+ private _requestDims;
410
+ private _timeout;
411
+ constructor(options?: PerplexityContextEmbeddingOptions);
412
+ /** Embed a single text. Wraps as [[text]] for the contextualized API. */
413
+ embed(text: string): Promise<Float32Array>;
414
+ /**
415
+ * Embed multiple texts as chunks of contextualized documents.
416
+ * Splits into sub-documents to stay under Perplexity's 32k token/doc limit.
417
+ */
418
+ embedBatch(texts: string[]): Promise<Float32Array[]>;
419
+ close(): Promise<void>;
420
+ /** Send a contextualized request. Input is string[][] (docs × chunks). */
421
+ private _request;
422
+ }
423
+
331
424
  /**
332
425
  * BrainBank — Math Utilities
333
426
  *
@@ -872,4 +965,4 @@ declare class KeywordSearch implements SearchStrategy {
872
965
  */
873
966
  declare function reciprocalRankFusion(resultSets: SearchResult[][], k?: number, maxResults?: number): SearchResult[];
874
967
 
875
- export { KeywordSearch as BM25Search, BrainBank, BrainBankConfig, CoEditAnalyzer, CoEditSuggestion, CodeChunk, CodeChunker, CodeIndexer, Collection, Consolidator, ContextBuilder, ContextOptions, DEFAULTS, DocsIndexer, DocumentCollection, EmbeddingProvider, GitIndexer, HNSWIndex, IGNORE_DIRS, IndexResult, IndexStats, Indexer, KeywordSearch, LearningPattern, LocalEmbedding, VectorSearch as MultiIndexSearch, type NoteDigest, NoteStore, OpenAIEmbedding, type OpenAIEmbeddingOptions, PatternStore, ProgressCallback, type RecallOptions, type ReembedOptions, type ReembedResult, Reranker, ResolvedConfig, SUPPORTED_EXTENSIONS, SearchHit, type SearchOptions, SearchResult, type SearchStrategy, StageProgressCallback, type StoredNote, VectorIndex, VectorSearch, type WatchOptions, type Watcher, cosineSimilarity, getLanguage, isSupported, normalize, reciprocalRankFusion, resolveConfig, searchMMR };
968
+ export { KeywordSearch as BM25Search, BrainBank, BrainBankConfig, CoEditAnalyzer, CoEditSuggestion, CodeChunk, CodeChunker, CodeIndexer, Collection, Consolidator, ContextBuilder, ContextOptions, DEFAULTS, DocsIndexer, DocumentCollection, EmbeddingProvider, GitIndexer, HNSWIndex, IGNORE_DIRS, IndexResult, IndexStats, Indexer, KeywordSearch, LearningPattern, LocalEmbedding, VectorSearch as MultiIndexSearch, type NoteDigest, NoteStore, OpenAIEmbedding, type OpenAIEmbeddingOptions, PatternStore, PerplexityContextEmbedding, type PerplexityContextEmbeddingOptions, PerplexityEmbedding, type PerplexityEmbeddingOptions, ProgressCallback, type RecallOptions, type ReembedOptions, type ReembedResult, Reranker, ResolvedConfig, SUPPORTED_EXTENSIONS, SearchHit, type SearchOptions, SearchResult, type SearchStrategy, StageProgressCallback, type StoredNote, VectorIndex, VectorSearch, type WatchOptions, type Watcher, cosineSimilarity, getLanguage, isSupported, normalize, reciprocalRankFusion, resolveConfig, searchMMR };
package/dist/index.js CHANGED
@@ -1,3 +1,9 @@
1
+ import {
2
+ PerplexityContextEmbedding
3
+ } from "./chunk-6XOXM7MI.js";
4
+ import {
5
+ PerplexityEmbedding
6
+ } from "./chunk-N2OJRXSB.js";
1
7
  import {
2
8
  NoteStore,
3
9
  notes
@@ -107,6 +113,8 @@ export {
107
113
  NoteStore,
108
114
  OpenAIEmbedding,
109
115
  PatternStore,
116
+ PerplexityContextEmbedding,
117
+ PerplexityEmbedding,
110
118
  SUPPORTED_EXTENSIONS,
111
119
  VectorSearch,
112
120
  code,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types.ts"],"sourcesContent":["/**\n * BrainBank — Type Definitions\n * \n * All interfaces and types for the semantic knowledge bank.\n */\n\n\n\n// ── Configuration ───────────────────────────────────\n\nexport interface BrainBankConfig {\n /** Root path of the repository to index. Default: '.' */\n repoPath?: string;\n /** SQLite database path. Default: '.brainbank/brainbank.db' */\n dbPath?: string;\n\n /** Max git commits to index. Default: 500 */\n gitDepth?: number;\n /** Max file size in bytes to index. Default: 512_000 (500KB) */\n maxFileSize?: number;\n /** Max diff bytes per commit. Default: 8192 */\n maxDiffBytes?: number;\n /** HNSW M parameter (connections per node). Default: 16 */\n hnswM?: number;\n /** HNSW efConstruction (build-time candidates). Default: 200 */\n hnswEfConstruction?: number;\n /** HNSW efSearch (query-time candidates). Default: 50 */\n hnswEfSearch?: number;\n /** Embedding dimensions. Default: 384 */\n embeddingDims?: number;\n /** Max HNSW elements. Default: 2_000_000 */\n maxElements?: number;\n /** Custom embedding provider (default: local WASM model) */\n embeddingProvider?: EmbeddingProvider;\n /** Optional reranker for improved search quality */\n reranker?: Reranker;\n}\n\nexport interface ResolvedConfig {\n repoPath: string;\n dbPath: string;\n gitDepth: number;\n maxFileSize: number;\n maxDiffBytes: number;\n hnswM: number;\n hnswEfConstruction: number;\n hnswEfSearch: number;\n embeddingDims: number;\n maxElements: number;\n embeddingProvider?: EmbeddingProvider;\n reranker?: Reranker;\n}\n\n// ── Embedding Provider ──────────────────────────────\n\nexport interface EmbeddingProvider {\n /** Vector dimensions produced by this provider. */\n readonly dims: number;\n /** Embed a single text string. */\n embed(text: string): Promise<Float32Array>;\n /** Embed multiple texts (batch). */\n embedBatch(texts: string[]): Promise<Float32Array[]>;\n /** Release resources. */\n close(): Promise<void>;\n}\n\n// ── Reranker ────────────────────────────────────────\n\nexport interface Reranker {\n /**\n * Score each document's relevance to the query.\n * @param query - The search query\n * @param documents - Document contents to rank\n * @returns Relevance scores (0.0 - 1.0) in same order as documents\n */\n rank(query: string, documents: string[]): Promise<number[]>;\n /** Release resources (e.g. unload model). */\n close?(): Promise<void>;\n}\n\n// ── Vector Index ────────────────────────────────────\n\nexport interface SearchHit {\n id: number;\n score: number;\n}\n\nexport interface VectorIndex {\n /** Initialize the index. Must be called before add/search. */\n init(): Promise<this>;\n /** Add a vector with an integer ID. Idempotent: duplicate IDs are skipped. */\n add(vector: Float32Array, id: number): void;\n /** Mark a vector as deleted so it no longer appears in searches. */\n remove(id: number): void;\n /** Search for k nearest neighbors. */\n search(query: Float32Array, k: number): SearchHit[];\n /** Clear all vectors and reset to empty state. */\n reinit(): void;\n /** Number of vectors in the index. */\n readonly size: number;\n}\n\n// ── Code Chunking ───────────────────────────────────\n\nexport interface CodeChunk {\n /** Auto-incremented DB id (set after insert) */\n id?: number;\n /** Relative file path from repo root */\n filePath: string;\n /** Chunk type: 'file' | 'function' | 'class' | 'block' */\n chunkType: string;\n /** Function/class name (if detected) */\n name?: string;\n /** Start line (1-indexed) */\n startLine: number;\n /** End line (1-indexed, inclusive) */\n endLine: number;\n /** Raw content of the chunk */\n content: string;\n /** Language identifier */\n language: string;\n}\n\n// ── Git ─────────────────────────────────────────────\n\nexport interface GitCommitRecord {\n id?: number;\n hash: string;\n shortHash: string;\n message: string;\n author: string;\n date: string;\n timestamp: number;\n filesChanged: string[];\n diff?: string;\n additions: number;\n deletions: number;\n isMerge: boolean;\n}\n\n// ── Agent Learning ─────────────────────────────────────────\n\nexport interface LearningPattern {\n id?: number;\n /** Category (e.g. 'api', 'refactor', 'debug') */\n taskType: string;\n /** What was the task */\n task: string;\n /** How it was approached */\n approach: string;\n /** What happened */\n outcome?: string;\n /** 0.0 – 1.0 */\n successRate: number;\n /** Lessons learned */\n critique?: string;\n /** Tokens consumed (optional tracking) */\n tokensUsed?: number;\n /** Latency in ms (optional tracking) */\n latencyMs?: number;\n}\n\nexport interface DistilledStrategy {\n taskType: string;\n strategy: string;\n confidence: number;\n updatedAt: number;\n}\n\n// ── Search Results ──────────────────────────────────\n\nexport type SearchResultType = 'code' | 'commit' | 'pattern' | 'document' | 'collection';\n\n// Typed metadata per result type\n\nexport interface CodeResultMetadata {\n chunkType: string;\n name?: string;\n startLine: number;\n endLine: number;\n language: string;\n searchType?: string;\n}\n\nexport interface CommitResultMetadata {\n hash: string;\n shortHash: string;\n author: string;\n date: string;\n files: string[];\n additions?: number;\n deletions?: number;\n diff?: string;\n searchType?: string;\n}\n\nexport interface PatternResultMetadata {\n taskType: string;\n task: string;\n outcome?: string;\n successRate: number;\n critique?: string;\n searchType?: string;\n}\n\nexport interface DocumentResultMetadata {\n collection?: string;\n title?: string;\n seq?: number;\n path?: string;\n searchType?: string;\n}\n\n// Discriminated union\n\nexport interface CodeResult {\n type: 'code';\n score: number;\n filePath: string;\n content: string;\n context?: string;\n metadata: CodeResultMetadata;\n}\n\nexport interface CommitResult {\n type: 'commit';\n score: number;\n filePath?: string;\n content: string;\n context?: string;\n metadata: CommitResultMetadata;\n}\n\nexport interface PatternResult {\n type: 'pattern';\n score: number;\n filePath?: string;\n content: string;\n context?: string;\n metadata: PatternResultMetadata;\n}\n\nexport interface DocumentResult {\n type: 'document';\n score: number;\n filePath: string;\n content: string;\n context?: string;\n metadata: DocumentResultMetadata;\n}\n\nexport interface CollectionResult {\n type: 'collection';\n score: number;\n filePath?: string;\n content: string;\n context?: string;\n metadata: Record<string, any>;\n}\n\nexport type SearchResult = CodeResult | CommitResult | PatternResult | DocumentResult | CollectionResult;\n\n// ── Type Guards ──────────────────────────────────────\n\n/** Narrow a SearchResult to CodeResult. */\nexport function isCodeResult(r: SearchResult): r is CodeResult {\n return r.type === 'code';\n}\n/** Narrow a SearchResult to CommitResult. */\nexport function isCommitResult(r: SearchResult): r is CommitResult {\n return r.type === 'commit';\n}\n/** Narrow a SearchResult to DocumentResult. */\nexport function isDocumentResult(r: SearchResult): r is DocumentResult {\n return r.type === 'document';\n}\n/** Narrow a SearchResult to PatternResult. */\nexport function isPatternResult(r: SearchResult): r is PatternResult {\n return r.type === 'pattern';\n}\n/** Narrow a SearchResult to CollectionResult. */\nexport function isCollectionResult(r: SearchResult): r is CollectionResult {\n return r.type === 'collection';\n}\n\n// ── Match Helper ─────────────────────────────────────\n\ntype MatchHandlers<T> = {\n code?: (r: CodeResult) => T;\n commit?: (r: CommitResult) => T;\n pattern?: (r: PatternResult) => T;\n document?: (r: DocumentResult) => T;\n collection?: (r: CollectionResult) => T;\n _?: (r: SearchResult) => T;\n};\n\n/**\n * Pattern-match on SearchResult type. Calls the matching handler\n * or the `_` fallback. Returns undefined if no handler matches.\n */\nexport function matchResult<T>(\n result: SearchResult,\n handlers: MatchHandlers<T>,\n): T | undefined {\n switch (result.type) {\n case 'code': return (handlers.code ?? handlers._)?.(result);\n case 'commit': return (handlers.commit ?? handlers._)?.(result);\n case 'pattern': return (handlers.pattern ?? handlers._)?.(result);\n case 'document': return (handlers.document ?? handlers._)?.(result);\n case 'collection': return (handlers.collection ?? handlers._)?.(result);\n }\n}\n\n// ── Context Builder ─────────────────────────────────\n\nexport interface ContextOptions {\n /** Max code chunks to include. Default: 6 */\n codeResults?: number;\n /** Max git commits to include. Default: 5 */\n gitResults?: number;\n /** Max memory patterns to include. Default: 4 */\n patternResults?: number;\n /** Files the agent is about to modify (improves co-edit suggestions) */\n affectedFiles?: string[];\n /** Minimum similarity score threshold. Default: 0.25 */\n minScore?: number;\n /** Use MMR for diversity. Default: true */\n useMMR?: boolean;\n /** MMR lambda (0 = diversity, 1 = relevance). Default: 0.7 */\n mmrLambda?: number;\n}\n\n// ── Document Collections ────────────────────────────\n\nexport interface DocumentCollection {\n /** Collection name (e.g. 'notes', 'docs') */\n name: string;\n /** Directory path to index */\n path: string;\n /** Glob pattern for files (default: all markdown) */\n pattern?: string;\n /** Glob patterns to ignore */\n ignore?: string[];\n /** Context description for this collection */\n context?: string;\n}\n\nexport interface DocChunk {\n id?: number;\n /** Collection name */\n collection: string;\n /** Relative file path within the collection */\n filePath: string;\n /** Document title (first heading or filename) */\n title: string;\n /** Chunk content */\n content: string;\n /** Chunk sequence within the document (0, 1, 2...) */\n seq: number;\n /** Character position in original document */\n pos: number;\n /** Content hash for incremental updates */\n contentHash: string;\n}\n\n// ── Stats ───────────────────────────────────────────\n\nexport interface IndexStats {\n code?: {\n files: number;\n chunks: number;\n hnswSize: number;\n };\n git?: {\n commits: number;\n filesTracked: number;\n coEdits: number;\n hnswSize: number;\n };\n memory?: {\n patterns: number;\n avgSuccess: number;\n hnswSize: number;\n };\n documents?: {\n collections: number;\n documents: number;\n chunks: number;\n hnswSize: number;\n };\n notes?: {\n total: number;\n short: number;\n long: number;\n };\n}\n\n// ── Index Progress ──────────────────────────────────\n\n/** File-level progress (used by indexers). */\nexport type ProgressCallback = (file: string, current: number, total: number) => void;\n\n/** Stage-level progress (used by BrainBank.index() orchestrator). */\nexport type StageProgressCallback = (stage: string, message: string) => void;\n\nexport interface IndexResult {\n indexed: number;\n skipped: number;\n chunks?: number;\n}\n\n// ── Co-Edits ────────────────────────────────────────\n\nexport interface CoEditSuggestion {\n file: string;\n count: number;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyQO,SAAS,aAAa,GAAkC;AAC3D,SAAO,EAAE,SAAS;AACtB;AAFgB;AAIT,SAAS,eAAe,GAAoC;AAC/D,SAAO,EAAE,SAAS;AACtB;AAFgB;AAIT,SAAS,iBAAiB,GAAsC;AACnE,SAAO,EAAE,SAAS;AACtB;AAFgB;AAIT,SAAS,gBAAgB,GAAqC;AACjE,SAAO,EAAE,SAAS;AACtB;AAFgB;AAIT,SAAS,mBAAmB,GAAwC;AACvE,SAAO,EAAE,SAAS;AACtB;AAFgB;AAmBT,SAAS,YACZ,QACA,UACa;AACb,UAAQ,OAAO,MAAM;AAAA,IACjB,KAAK;AAAc,cAAQ,SAAS,QAAc,SAAS,KAAK,MAAM;AAAA,IACtE,KAAK;AAAc,cAAQ,SAAS,UAAc,SAAS,KAAK,MAAM;AAAA,IACtE,KAAK;AAAc,cAAQ,SAAS,WAAc,SAAS,KAAK,MAAM;AAAA,IACtE,KAAK;AAAc,cAAQ,SAAS,YAAc,SAAS,KAAK,MAAM;AAAA,IACtE,KAAK;AAAc,cAAQ,SAAS,cAAc,SAAS,KAAK,MAAM;AAAA,EAC1E;AACJ;AAXgB;","names":[]}
1
+ {"version":3,"sources":["../src/types.ts"],"sourcesContent":["/**\n * BrainBank — Type Definitions\n * \n * All interfaces and types for the semantic knowledge bank.\n */\n\n\n\n// ── Configuration ───────────────────────────────────\n\nexport interface BrainBankConfig {\n /** Root path of the repository to index. Default: '.' */\n repoPath?: string;\n /** SQLite database path. Default: '.brainbank/brainbank.db' */\n dbPath?: string;\n\n /** Max git commits to index. Default: 500 */\n gitDepth?: number;\n /** Max file size in bytes to index. Default: 512_000 (500KB) */\n maxFileSize?: number;\n /** Max diff bytes per commit. Default: 8192 */\n maxDiffBytes?: number;\n /** HNSW M parameter (connections per node). Default: 16 */\n hnswM?: number;\n /** HNSW efConstruction (build-time candidates). Default: 200 */\n hnswEfConstruction?: number;\n /** HNSW efSearch (query-time candidates). Default: 50 */\n hnswEfSearch?: number;\n /** Embedding dimensions. Default: 384 */\n embeddingDims?: number;\n /** Max HNSW elements. Default: 2_000_000 */\n maxElements?: number;\n /** Custom embedding provider (default: local WASM model) */\n embeddingProvider?: EmbeddingProvider;\n /** Optional reranker for improved search quality */\n reranker?: Reranker;\n}\n\nexport interface ResolvedConfig {\n repoPath: string;\n dbPath: string;\n gitDepth: number;\n maxFileSize: number;\n maxDiffBytes: number;\n hnswM: number;\n hnswEfConstruction: number;\n hnswEfSearch: number;\n embeddingDims: number;\n maxElements: number;\n embeddingProvider?: EmbeddingProvider;\n reranker?: Reranker;\n}\n\n// ── Embedding Provider ──────────────────────────────\n\nexport interface EmbeddingProvider {\n /** Vector dimensions produced by this provider. */\n readonly dims: number;\n /** Embed a single text string. */\n embed(text: string): Promise<Float32Array>;\n /** Embed multiple texts (batch). */\n embedBatch(texts: string[]): Promise<Float32Array[]>;\n /** Release resources. */\n close(): Promise<void>;\n}\n\n// ── Reranker ────────────────────────────────────────\n\nexport interface Reranker {\n /**\n * Score each document's relevance to the query.\n * @param query - The search query\n * @param documents - Document contents to rank\n * @returns Relevance scores (0.0 - 1.0) in same order as documents\n */\n rank(query: string, documents: string[]): Promise<number[]>;\n /** Release resources (e.g. unload model). */\n close?(): Promise<void>;\n}\n\n// ── Vector Index ────────────────────────────────────\n\nexport interface SearchHit {\n id: number;\n score: number;\n}\n\nexport interface VectorIndex {\n /** Initialize the index. Must be called before add/search. */\n init(): Promise<this>;\n /** Add a vector with an integer ID. Idempotent: duplicate IDs are skipped. */\n add(vector: Float32Array, id: number): void;\n /** Mark a vector as deleted so it no longer appears in searches. */\n remove(id: number): void;\n /** Search for k nearest neighbors. */\n search(query: Float32Array, k: number): SearchHit[];\n /** Clear all vectors and reset to empty state. */\n reinit(): void;\n /** Number of vectors in the index. */\n readonly size: number;\n}\n\n// ── Code Chunking ───────────────────────────────────\n\nexport interface CodeChunk {\n /** Auto-incremented DB id (set after insert) */\n id?: number;\n /** Relative file path from repo root */\n filePath: string;\n /** Chunk type: 'file' | 'function' | 'class' | 'block' */\n chunkType: string;\n /** Function/class name (if detected) */\n name?: string;\n /** Start line (1-indexed) */\n startLine: number;\n /** End line (1-indexed, inclusive) */\n endLine: number;\n /** Raw content of the chunk */\n content: string;\n /** Language identifier */\n language: string;\n}\n\n// ── Git ─────────────────────────────────────────────\n\nexport interface GitCommitRecord {\n id?: number;\n hash: string;\n shortHash: string;\n message: string;\n author: string;\n date: string;\n timestamp: number;\n filesChanged: string[];\n diff?: string;\n additions: number;\n deletions: number;\n isMerge: boolean;\n}\n\n// ── Agent Learning ─────────────────────────────────────────\n\nexport interface LearningPattern {\n id?: number;\n /** Category (e.g. 'api', 'refactor', 'debug') */\n taskType: string;\n /** What was the task */\n task: string;\n /** How it was approached */\n approach: string;\n /** What happened */\n outcome?: string;\n /** 0.0 – 1.0 */\n successRate: number;\n /** Lessons learned */\n critique?: string;\n /** Tokens consumed (optional tracking) */\n tokensUsed?: number;\n /** Latency in ms (optional tracking) */\n latencyMs?: number;\n}\n\nexport interface DistilledStrategy {\n taskType: string;\n strategy: string;\n confidence: number;\n updatedAt: number;\n}\n\n// ── Search Results ──────────────────────────────────\n\nexport type SearchResultType = 'code' | 'commit' | 'pattern' | 'document' | 'collection';\n\n// Typed metadata per result type\n\nexport interface CodeResultMetadata {\n chunkType: string;\n name?: string;\n startLine: number;\n endLine: number;\n language: string;\n searchType?: string;\n}\n\nexport interface CommitResultMetadata {\n hash: string;\n shortHash: string;\n author: string;\n date: string;\n files: string[];\n additions?: number;\n deletions?: number;\n diff?: string;\n searchType?: string;\n}\n\nexport interface PatternResultMetadata {\n taskType: string;\n task: string;\n outcome?: string;\n successRate: number;\n critique?: string;\n searchType?: string;\n}\n\nexport interface DocumentResultMetadata {\n collection?: string;\n title?: string;\n seq?: number;\n path?: string;\n searchType?: string;\n}\n\n// Discriminated union\n\nexport interface CodeResult {\n type: 'code';\n score: number;\n filePath: string;\n content: string;\n context?: string;\n metadata: CodeResultMetadata;\n}\n\nexport interface CommitResult {\n type: 'commit';\n score: number;\n filePath?: string;\n content: string;\n context?: string;\n metadata: CommitResultMetadata;\n}\n\nexport interface PatternResult {\n type: 'pattern';\n score: number;\n filePath?: string;\n content: string;\n context?: string;\n metadata: PatternResultMetadata;\n}\n\nexport interface DocumentResult {\n type: 'document';\n score: number;\n filePath: string;\n content: string;\n context?: string;\n metadata: DocumentResultMetadata;\n}\n\nexport interface CollectionResult {\n type: 'collection';\n score: number;\n filePath?: string;\n content: string;\n context?: string;\n metadata: Record<string, any>;\n}\n\nexport type SearchResult = CodeResult | CommitResult | PatternResult | DocumentResult | CollectionResult;\n\n// ── Type Guards ──────────────────────────────────────\n\n/** Narrow a SearchResult to CodeResult. */\nexport function isCodeResult(r: SearchResult): r is CodeResult {\n return r.type === 'code';\n}\n/** Narrow a SearchResult to CommitResult. */\nexport function isCommitResult(r: SearchResult): r is CommitResult {\n return r.type === 'commit';\n}\n/** Narrow a SearchResult to DocumentResult. */\nexport function isDocumentResult(r: SearchResult): r is DocumentResult {\n return r.type === 'document';\n}\n/** Narrow a SearchResult to PatternResult. */\nexport function isPatternResult(r: SearchResult): r is PatternResult {\n return r.type === 'pattern';\n}\n/** Narrow a SearchResult to CollectionResult. */\nexport function isCollectionResult(r: SearchResult): r is CollectionResult {\n return r.type === 'collection';\n}\n\n// ── Match Helper ─────────────────────────────────────\n\ntype MatchHandlers<T> = {\n code?: (r: CodeResult) => T;\n commit?: (r: CommitResult) => T;\n pattern?: (r: PatternResult) => T;\n document?: (r: DocumentResult) => T;\n collection?: (r: CollectionResult) => T;\n _?: (r: SearchResult) => T;\n};\n\n/**\n * Pattern-match on SearchResult type. Calls the matching handler\n * or the `_` fallback. Returns undefined if no handler matches.\n */\nexport function matchResult<T>(\n result: SearchResult,\n handlers: MatchHandlers<T>,\n): T | undefined {\n switch (result.type) {\n case 'code': return (handlers.code ?? handlers._)?.(result);\n case 'commit': return (handlers.commit ?? handlers._)?.(result);\n case 'pattern': return (handlers.pattern ?? handlers._)?.(result);\n case 'document': return (handlers.document ?? handlers._)?.(result);\n case 'collection': return (handlers.collection ?? handlers._)?.(result);\n }\n}\n\n// ── Context Builder ─────────────────────────────────\n\nexport interface ContextOptions {\n /** Max code chunks to include. Default: 6 */\n codeResults?: number;\n /** Max git commits to include. Default: 5 */\n gitResults?: number;\n /** Max memory patterns to include. Default: 4 */\n patternResults?: number;\n /** Files the agent is about to modify (improves co-edit suggestions) */\n affectedFiles?: string[];\n /** Minimum similarity score threshold. Default: 0.25 */\n minScore?: number;\n /** Use MMR for diversity. Default: true */\n useMMR?: boolean;\n /** MMR lambda (0 = diversity, 1 = relevance). Default: 0.7 */\n mmrLambda?: number;\n}\n\n// ── Document Collections ────────────────────────────\n\nexport interface DocumentCollection {\n /** Collection name (e.g. 'notes', 'docs') */\n name: string;\n /** Directory path to index */\n path: string;\n /** Glob pattern for files (default: all markdown) */\n pattern?: string;\n /** Glob patterns to ignore */\n ignore?: string[];\n /** Context description for this collection */\n context?: string;\n}\n\nexport interface DocChunk {\n id?: number;\n /** Collection name */\n collection: string;\n /** Relative file path within the collection */\n filePath: string;\n /** Document title (first heading or filename) */\n title: string;\n /** Chunk content */\n content: string;\n /** Chunk sequence within the document (0, 1, 2...) */\n seq: number;\n /** Character position in original document */\n pos: number;\n /** Content hash for incremental updates */\n contentHash: string;\n}\n\n// ── Stats ───────────────────────────────────────────\n\nexport interface IndexStats {\n code?: {\n files: number;\n chunks: number;\n hnswSize: number;\n };\n git?: {\n commits: number;\n filesTracked: number;\n coEdits: number;\n hnswSize: number;\n };\n memory?: {\n patterns: number;\n avgSuccess: number;\n hnswSize: number;\n };\n documents?: {\n collections: number;\n documents: number;\n chunks: number;\n hnswSize: number;\n };\n notes?: {\n total: number;\n short: number;\n long: number;\n };\n}\n\n// ── Index Progress ──────────────────────────────────\n\n/** File-level progress (used by indexers). */\nexport type ProgressCallback = (file: string, current: number, total: number) => void;\n\n/** Stage-level progress (used by BrainBank.index() orchestrator). */\nexport type StageProgressCallback = (stage: string, message: string) => void;\n\nexport interface IndexResult {\n indexed: number;\n skipped: number;\n chunks?: number;\n}\n\n// ── Co-Edits ────────────────────────────────────────\n\nexport interface CoEditSuggestion {\n file: string;\n count: number;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyQO,SAAS,aAAa,GAAkC;AAC3D,SAAO,EAAE,SAAS;AACtB;AAFgB;AAIT,SAAS,eAAe,GAAoC;AAC/D,SAAO,EAAE,SAAS;AACtB;AAFgB;AAIT,SAAS,iBAAiB,GAAsC;AACnE,SAAO,EAAE,SAAS;AACtB;AAFgB;AAIT,SAAS,gBAAgB,GAAqC;AACjE,SAAO,EAAE,SAAS;AACtB;AAFgB;AAIT,SAAS,mBAAmB,GAAwC;AACvE,SAAO,EAAE,SAAS;AACtB;AAFgB;AAmBT,SAAS,YACZ,QACA,UACa;AACb,UAAQ,OAAO,MAAM;AAAA,IACjB,KAAK;AAAc,cAAQ,SAAS,QAAc,SAAS,KAAK,MAAM;AAAA,IACtE,KAAK;AAAc,cAAQ,SAAS,UAAc,SAAS,KAAK,MAAM;AAAA,IACtE,KAAK;AAAc,cAAQ,SAAS,WAAc,SAAS,KAAK,MAAM;AAAA,IACtE,KAAK;AAAc,cAAQ,SAAS,YAAc,SAAS,KAAK,MAAM;AAAA,IACtE,KAAK;AAAc,cAAQ,SAAS,cAAc,SAAS,KAAK,MAAM;AAAA,EAC1E;AACJ;AAXgB;","names":[]}
@@ -0,0 +1,9 @@
1
+ import {
2
+ PerplexityContextEmbedding
3
+ } from "./chunk-6XOXM7MI.js";
4
+ import "./chunk-N2OJRXSB.js";
5
+ import "./chunk-7QVYU63E.js";
6
+ export {
7
+ PerplexityContextEmbedding
8
+ };
9
+ //# sourceMappingURL=perplexity-context-embedding-KSVSZXMD.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,10 @@
1
+ import {
2
+ PerplexityEmbedding,
3
+ decodeBase64Int8
4
+ } from "./chunk-N2OJRXSB.js";
5
+ import "./chunk-7QVYU63E.js";
6
+ export {
7
+ PerplexityEmbedding,
8
+ decodeBase64Int8
9
+ };
10
+ //# sourceMappingURL=perplexity-embedding-227WQY4R.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "brainbank",
3
- "version": "0.3.1",
3
+ "version": "0.4.1",
4
4
  "description": "Pluggable semantic memory for AI agents — hybrid search (vector + BM25) in a single SQLite file. Built-in code, git, and docs indexers. Bring your own.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",