brainbank 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/README.md +19 -9
  2. package/dist/{base-9vfWRHCV.d.ts → base-4SUgeRWT.d.ts} +25 -2
  3. package/dist/{chunk-ZJ5LLMGM.js → chunk-2BEWWQL2.js} +432 -415
  4. package/dist/chunk-2BEWWQL2.js.map +1 -0
  5. package/dist/{chunk-OPQ3ZIPV.js → chunk-5VUYPNH3.js} +47 -3
  6. package/dist/chunk-5VUYPNH3.js.map +1 -0
  7. package/dist/chunk-CCXVL56V.js +120 -0
  8. package/dist/chunk-CCXVL56V.js.map +1 -0
  9. package/dist/{chunk-FEAMUZGJ.js → chunk-E6WQM4DN.js} +3 -3
  10. package/dist/chunk-E6WQM4DN.js.map +1 -0
  11. package/dist/chunk-FI7GWG4W.js +309 -0
  12. package/dist/chunk-FI7GWG4W.js.map +1 -0
  13. package/dist/{chunk-X6645UVR.js → chunk-FINIFKAY.js} +136 -4
  14. package/dist/chunk-FINIFKAY.js.map +1 -0
  15. package/dist/{chunk-4DM3XWO6.js → chunk-MGIFEPYZ.js} +54 -42
  16. package/dist/chunk-MGIFEPYZ.js.map +1 -0
  17. package/dist/{chunk-T2VXF5S5.js → chunk-Y3JKI6QN.js} +152 -137
  18. package/dist/chunk-Y3JKI6QN.js.map +1 -0
  19. package/dist/cli.js +34 -28
  20. package/dist/cli.js.map +1 -1
  21. package/dist/code.d.ts +1 -1
  22. package/dist/code.js +1 -1
  23. package/dist/docs.d.ts +1 -1
  24. package/dist/docs.js +1 -1
  25. package/dist/git.d.ts +1 -1
  26. package/dist/git.js +1 -1
  27. package/dist/index.d.ts +121 -82
  28. package/dist/index.js +66 -15
  29. package/dist/index.js.map +1 -1
  30. package/dist/memory.d.ts +1 -1
  31. package/dist/memory.js +3 -137
  32. package/dist/memory.js.map +1 -1
  33. package/dist/notes.d.ts +1 -1
  34. package/dist/notes.js +4 -49
  35. package/dist/notes.js.map +1 -1
  36. package/dist/{openai-CYDMYX7X.js → openai-embedding-VQZCZQYT.js} +2 -2
  37. package/package.json +1 -1
  38. package/dist/chunk-4DM3XWO6.js.map +0 -1
  39. package/dist/chunk-7JCEW7LT.js +0 -266
  40. package/dist/chunk-7JCEW7LT.js.map +0 -1
  41. package/dist/chunk-FEAMUZGJ.js.map +0 -1
  42. package/dist/chunk-GUT5MSJT.js +0 -99
  43. package/dist/chunk-GUT5MSJT.js.map +0 -1
  44. package/dist/chunk-OPQ3ZIPV.js.map +0 -1
  45. package/dist/chunk-T2VXF5S5.js.map +0 -1
  46. package/dist/chunk-X6645UVR.js.map +0 -1
  47. package/dist/chunk-ZJ5LLMGM.js.map +0 -1
  48. /package/dist/{openai-CYDMYX7X.js.map → openai-embedding-VQZCZQYT.js.map} +0 -0
package/dist/index.d.ts CHANGED
@@ -1,9 +1,11 @@
1
1
  import { EventEmitter } from 'node:events';
2
- import { P as ProgressCallback, B as BrainBankConfig, I as Indexer, C as Collection, S as StageProgressCallback, a as IndexResult, D as DocumentCollection, b as SearchResult, c as ContextOptions, d as CoEditSuggestion, e as IndexStats, R as ResolvedConfig, E as EmbeddingProvider, V as VectorIndex, f as SearchHit, g as CodeChunk, h as Database, H as HNSWIndex, L as LearningPattern, i as Reranker } from './base-9vfWRHCV.js';
3
- export { j as CodeResult, k as CodeResultMetadata, l as CollectionAddOptions, m as CollectionItem, n as CollectionPlugin, o as CollectionResult, p as CollectionSearchOptions, q as CommitResult, r as CommitResultMetadata, s as DistilledStrategy, t as DocChunk, u as DocumentResult, v as DocumentResultMetadata, G as GitCommitRecord, w as IndexablePlugin, x as IndexerContext, y as PatternResult, z as PatternResultMetadata, A as SearchResultType, F as SearchablePlugin, W as WatchablePlugin } from './base-9vfWRHCV.js';
2
+ import { P as ProgressCallback, B as BrainBankConfig, I as Indexer, C as Collection, S as StageProgressCallback, a as IndexResult, D as DocumentCollection, b as SearchResult, c as ContextOptions, d as CoEditSuggestion, e as IndexStats, R as ResolvedConfig, E as EmbeddingProvider, V as VectorIndex, f as SearchHit, g as CodeChunk, h as Database, H as HNSWIndex, L as LearningPattern, i as Reranker } from './base-4SUgeRWT.js';
3
+ export { j as CodeResult, k as CodeResultMetadata, l as CollectionAddOptions, m as CollectionItem, n as CollectionPlugin, o as CollectionResult, p as CollectionSearchOptions, q as CommitResult, r as CommitResultMetadata, s as DistilledStrategy, t as DocChunk, u as DocumentResult, v as DocumentResultMetadata, G as GitCommitRecord, w as IndexablePlugin, x as IndexerContext, y as PatternResult, z as PatternResultMetadata, A as SearchResultType, F as SearchablePlugin, W as WatchablePlugin, J as isCodeResult, K as isCollectionResult, M as isCommitResult, N as isDocumentResult, O as isPatternResult, Q as matchResult } from './base-4SUgeRWT.js';
4
4
  export { code } from './code.js';
5
5
  export { git } from './git.js';
6
6
  export { docs } from './docs.js';
7
+ export { memory } from './memory.js';
8
+ export { notes } from './notes.js';
7
9
  import 'better-sqlite3';
8
10
 
9
11
  /**
@@ -115,7 +117,9 @@ declare class BrainBank extends EventEmitter {
115
117
  * Only initializes registered modules.
116
118
  * Automatically called by index/search methods if not yet initialized.
117
119
  */
118
- initialize(): Promise<void>;
120
+ initialize(options?: {
121
+ force?: boolean;
122
+ }): Promise<void>;
119
123
  private _runInitialize;
120
124
  /**
121
125
  * Get or create a dynamic collection.
@@ -217,11 +221,11 @@ declare class BrainBank extends EventEmitter {
217
221
  codeK?: number;
218
222
  gitK?: number;
219
223
  patternK?: number;
220
- }): SearchResult[];
224
+ }): Promise<SearchResult[]>;
221
225
  /** Rebuild FTS5 indices. */
222
226
  rebuildFTS(): void;
223
227
  /** Get git history for a specific file. */
224
- fileHistory(filePath: string, limit?: number): Promise<any[]>;
228
+ fileHistory(filePath: string, limit?: number): Promise<Record<string, unknown>[]>;
225
229
  /** Get co-edit suggestions for a file. */
226
230
  coEdits(filePath: string, limit?: number): CoEditSuggestion[];
227
231
  /** Get statistics for all loaded modules. */
@@ -243,6 +247,7 @@ declare class BrainBank extends EventEmitter {
243
247
  /** The resolved configuration. */
244
248
  get config(): Readonly<ResolvedConfig>;
245
249
  private _requireInit;
250
+ private _requireDocs;
246
251
  }
247
252
 
248
253
  /**
@@ -275,8 +280,8 @@ declare class LocalEmbedding implements EmbeddingProvider {
275
280
  */
276
281
  embed(text: string): Promise<Float32Array>;
277
282
  /**
278
- * Embed multiple texts.
279
- * Processes sequentially to avoid OOM on large batches.
283
+ * Embed multiple texts using real batch processing.
284
+ * Chunks into groups of BATCH_SIZE to balance throughput vs memory.
280
285
  */
281
286
  embedBatch(texts: string[]): Promise<Float32Array[]>;
282
287
  close(): Promise<void>;
@@ -303,6 +308,8 @@ interface OpenAIEmbeddingOptions {
303
308
  dims?: number;
304
309
  /** Base URL override (for Azure, proxies, etc.) */
305
310
  baseUrl?: string;
311
+ /** Request timeout in ms. Default: 30000 */
312
+ timeout?: number;
306
313
  }
307
314
  declare class OpenAIEmbedding implements EmbeddingProvider {
308
315
  readonly dims: number;
@@ -310,12 +317,15 @@ declare class OpenAIEmbedding implements EmbeddingProvider {
310
317
  private _model;
311
318
  private _baseUrl;
312
319
  private _requestDims;
320
+ private _timeout;
313
321
  constructor(options?: OpenAIEmbeddingOptions);
314
322
  embed(text: string): Promise<Float32Array>;
315
323
  embedBatch(texts: string[]): Promise<Float32Array[]>;
316
324
  close(): Promise<void>;
317
325
  private _isTokenLimitError;
318
326
  private _request;
327
+ /** Handle API errors with token-limit retry logic. */
328
+ private _handleApiError;
319
329
  }
320
330
 
321
331
  /**
@@ -440,11 +450,12 @@ declare class CodeIndexer {
440
450
  private _repoPath;
441
451
  private _maxFileSize;
442
452
  constructor(repoPath: string, deps: CodeIndexerDeps, maxFileSize?: number);
443
- /**
444
- * Index all supported files in the repository.
445
- * Skips unchanged files (same content hash).
446
- */
453
+ /** Index all supported files. Skips unchanged files (same content hash). */
447
454
  index(options?: CodeIndexOptions): Promise<IndexResult>;
455
+ /** Remove old chunks and their HNSW vectors for a file. */
456
+ private _removeOldChunks;
457
+ /** Chunk, embed, and store a single file. Returns chunk count. */
458
+ private _indexFile;
448
459
  private _walkRepo;
449
460
  private _hash;
450
461
  }
@@ -477,11 +488,24 @@ declare class GitIndexer {
477
488
  * Only processes commits not already in the database.
478
489
  */
479
490
  index(options?: GitIndexOptions): Promise<IndexResult>;
480
- /**
481
- * Compute which files tend to be edited together.
482
- * Stored in the co_edits table for later suggestion.
483
- */
491
+ /** Initialize simple-git. Returns null if git is unavailable. */
492
+ private _initGit;
493
+ /** Prepare all SQL statements (hoisted outside loops). */
494
+ private _prepareStatements;
495
+ /** Phase 1: Collect commit data from git (async git calls). */
496
+ private _collectCommits;
497
+ /** Extract diff, stat, and text from a single commit. */
498
+ private _parseCommit;
499
+ /** Phase 3: Insert commits + vectors in a single transaction. */
500
+ private _insertCommits;
501
+ /** Phase 4: Update HNSW index and compute co-edits. */
502
+ private _updateHnsw;
503
+ /** Compute which files tend to be edited together. */
484
504
  private _computeCoEdits;
505
+ /** Query commit_files in chunks to stay under SQLite's 999-variable limit. */
506
+ private _queryCommitFiles;
507
+ /** Group file paths by commit ID. */
508
+ private _groupFilesByCommit;
485
509
  }
486
510
 
487
511
  /**
@@ -512,25 +536,28 @@ declare class DocsIndexer {
512
536
  skipped: number;
513
537
  chunks: number;
514
538
  }>;
515
- /**
516
- * Remove all indexed data for a collection.
517
- */
539
+ /** Walk directory tree and collect matching files. */
540
+ private _walkFiles;
541
+ /** Check if a file matches any ignore patterns. */
542
+ private _isIgnoredFile;
543
+ /** Check if all chunks for a file match the current hash and have vectors. */
544
+ private _isUnchanged;
545
+ /** Remove old chunks and their HNSW vectors for a file. */
546
+ private _removeOldChunks;
547
+ /** Index a single file: chunk, embed, store in DB + HNSW. */
548
+ private _indexFile;
549
+ /** Remove all indexed data for a collection. */
518
550
  removeCollection(collection: string): void;
519
- /**
520
- * Split document into chunks at natural markdown boundaries.
521
- * Uses heading-aware scoring like qmd.
522
- */
551
+ /** Split document into chunks at natural markdown boundaries. */
523
552
  private _smartChunk;
524
- /**
525
- * Find all potential break points in the document with scores.
526
- */
553
+ /** Handle the last chunk: merge if too small, otherwise push. */
554
+ private _pushLastChunk;
555
+ /** Find the best break position within the target window. */
556
+ private _findBestBreak;
557
+ /** Find all potential break points in the document with scores. */
527
558
  private _findBreakPoints;
528
- /**
529
- * Extract document title from first heading or filename.
530
- */
559
+ /** Extract document title from first heading or filename. */
531
560
  private _extractTitle;
532
- /** Skip well-known output/vendor directories when walking docs. */
533
- private _isIgnoredDocDir;
534
561
  }
535
562
 
536
563
  /**
@@ -694,22 +721,17 @@ declare class NoteStore {
694
721
  }
695
722
 
696
723
  /**
697
- * BrainBank — Multi-Index Search
724
+ * BrainBank — Search Types
698
725
  *
699
- * Searches across all three indices (code, git, memory patterns)
700
- * and returns typed results sorted by relevance.
726
+ * Shared interface for all search strategies.
727
+ * Implement SearchStrategy to add a new search backend.
701
728
  */
702
729
 
703
- interface SearchConfig {
704
- db: Database;
705
- codeHnsw?: HNSWIndex;
706
- gitHnsw?: HNSWIndex;
707
- patternHnsw?: HNSWIndex;
708
- codeVecs: Map<number, Float32Array>;
709
- gitVecs: Map<number, Float32Array>;
710
- patternVecs: Map<number, Float32Array>;
711
- embedding: EmbeddingProvider;
712
- reranker?: Reranker;
730
+ /** Any search implementation follows this shape. */
731
+ interface SearchStrategy {
732
+ search(query: string, options?: SearchOptions): Promise<SearchResult[]>;
733
+ /** Rebuild internal indices (e.g. FTS5). Optional. */
734
+ rebuild?(): void;
713
735
  }
714
736
  interface SearchOptions {
715
737
  /** Max code results. Default: 6 */
@@ -725,23 +747,6 @@ interface SearchOptions {
725
747
  /** MMR lambda. Default: 0.7 */
726
748
  mmrLambda?: number;
727
749
  }
728
- declare class MultiIndexSearch {
729
- private _config;
730
- constructor(config: SearchConfig);
731
- /**
732
- * Search across all indices.
733
- * Returns combined results sorted by score.
734
- */
735
- search(query: string, options?: SearchOptions): Promise<SearchResult[]>;
736
- /**
737
- * Re-rank results using position-aware blending.
738
- *
739
- * Top 1-3: 75% retrieval / 25% reranker (preserves exact matches)
740
- * Top 4-10: 60% retrieval / 40% reranker
741
- * Top 11+: 40% retrieval / 60% reranker (trust reranker more)
742
- */
743
- private _rerank;
744
- }
745
750
 
746
751
  /**
747
752
  * BrainBank — Co-Edit Analyzer
@@ -771,43 +776,77 @@ declare class CoEditAnalyzer {
771
776
  declare class ContextBuilder {
772
777
  private _search;
773
778
  private _coEdits?;
774
- constructor(_search: MultiIndexSearch, _coEdits?: CoEditAnalyzer | undefined);
775
- /**
776
- * Build a full context block for a task.
777
- * Returns clean markdown ready for system prompt injection.
778
- */
779
+ constructor(_search: SearchStrategy, _coEdits?: CoEditAnalyzer | undefined);
780
+ /** Build a full context block for a task. Returns markdown for system prompt. */
779
781
  build(task: string, options?: ContextOptions): Promise<string>;
782
+ /** Format code search results grouped by file. */
783
+ private _formatCodeResults;
784
+ /** Format git commit results with diff snippets. */
785
+ private _formatGitResults;
786
+ /** Format co-edit suggestions for affected files. */
787
+ private _formatCoEdits;
788
+ /** Format memory pattern results. */
789
+ private _formatPatternResults;
790
+ }
791
+
792
+ /**
793
+ * BrainBank — Vector Search Strategy
794
+ *
795
+ * Searches across code, git, and memory pattern HNSW indices.
796
+ * Returns typed results sorted by relevance.
797
+ */
798
+
799
+ interface VectorSearchConfig {
800
+ db: Database;
801
+ codeHnsw?: HNSWIndex;
802
+ gitHnsw?: HNSWIndex;
803
+ patternHnsw?: HNSWIndex;
804
+ codeVecs: Map<number, Float32Array>;
805
+ gitVecs: Map<number, Float32Array>;
806
+ patternVecs: Map<number, Float32Array>;
807
+ embedding: EmbeddingProvider;
808
+ reranker?: Reranker;
809
+ }
810
+ declare class VectorSearch implements SearchStrategy {
811
+ private _config;
812
+ constructor(config: VectorSearchConfig);
813
+ /** Search across all indices. Returns combined results sorted by score. */
814
+ search(query: string, options?: SearchOptions): Promise<SearchResult[]>;
815
+ /** Vector search across code chunks. */
816
+ private _searchCode;
817
+ /** Vector search across git commits. */
818
+ private _searchGit;
819
+ /** Vector search across memory patterns. */
820
+ private _searchPatterns;
780
821
  }
781
822
 
782
823
  /**
783
- * BrainBank — BM25 Full-Text Search
824
+ * BrainBank — Keyword Search Strategy
784
825
  *
785
826
  * Keyword search via SQLite FTS5 with BM25 ranking.
786
827
  * Searches across code chunks, git commits, and memory patterns.
787
828
  * Uses Porter stemming + unicode61 tokenizer.
788
829
  */
789
830
 
790
- interface BM25Options {
791
- /** Max code results. Default: 8 */
792
- codeK?: number;
793
- /** Max git results. Default: 5 */
794
- gitK?: number;
795
- /** Max pattern results. Default: 4 */
796
- patternK?: number;
797
- }
798
- declare class BM25Search {
831
+ declare class KeywordSearch implements SearchStrategy {
799
832
  private _db;
800
833
  constructor(_db: Database);
801
834
  /**
802
835
  * Full-text keyword search across all FTS5 indices.
803
836
  * Uses BM25 scoring — lower scores = better matches.
804
- * Query syntax: simple words, OR, NOT, "exact phrases", prefix*
805
- */
806
- search(query: string, options?: BM25Options): SearchResult[];
807
- /**
808
- * Rebuild the FTS index from scratch.
809
- * Call this after bulk imports or if FTS gets out of sync.
810
837
  */
838
+ search(query: string, options?: SearchOptions): Promise<SearchResult[]>;
839
+ /** FTS5 search across code chunks + file-path fallback. */
840
+ private _searchCode;
841
+ /** File-path fallback: match filenames via LIKE. */
842
+ private _searchCodeByPath;
843
+ /** FTS5 search across git commits. */
844
+ private _searchGit;
845
+ /** FTS5 search across memory patterns. */
846
+ private _searchPatterns;
847
+ /** Map a code_chunks row to a CodeResult. */
848
+ private _toCodeResult;
849
+ /** Rebuild the FTS index from scratch. */
811
850
  rebuild(): void;
812
851
  }
813
852
 
@@ -833,4 +872,4 @@ declare class BM25Search {
833
872
  */
834
873
  declare function reciprocalRankFusion(resultSets: SearchResult[][], k?: number, maxResults?: number): SearchResult[];
835
874
 
836
- export { BM25Search, BrainBank, BrainBankConfig, CoEditAnalyzer, CoEditSuggestion, CodeChunk, CodeChunker, CodeIndexer, Collection, Consolidator, ContextBuilder, ContextOptions, DEFAULTS, DocsIndexer, DocumentCollection, EmbeddingProvider, GitIndexer, HNSWIndex, IGNORE_DIRS, IndexResult, IndexStats, Indexer, LearningPattern, LocalEmbedding, MultiIndexSearch, type NoteDigest, NoteStore, OpenAIEmbedding, type OpenAIEmbeddingOptions, PatternStore, ProgressCallback, type RecallOptions, type ReembedOptions, type ReembedResult, Reranker, ResolvedConfig, SUPPORTED_EXTENSIONS, SearchHit, SearchResult, StageProgressCallback, type StoredNote, VectorIndex, type WatchOptions, type Watcher, cosineSimilarity, getLanguage, isSupported, normalize, reciprocalRankFusion, resolveConfig, searchMMR };
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 };
package/dist/index.js CHANGED
@@ -1,22 +1,24 @@
1
1
  import {
2
- NoteStore
3
- } from "./chunk-OPQ3ZIPV.js";
2
+ NoteStore,
3
+ notes
4
+ } from "./chunk-5VUYPNH3.js";
4
5
  import {
5
6
  Consolidator,
6
- PatternStore
7
- } from "./chunk-X6645UVR.js";
7
+ PatternStore,
8
+ memory
9
+ } from "./chunk-FINIFKAY.js";
8
10
  import {
9
- BM25Search,
10
11
  BrainBank,
11
12
  Collection,
12
13
  ContextBuilder,
13
14
  DEFAULTS,
14
15
  HNSWIndex,
16
+ KeywordSearch,
15
17
  LocalEmbedding,
16
- MultiIndexSearch,
18
+ VectorSearch,
17
19
  resolveConfig,
18
20
  searchMMR
19
- } from "./chunk-ZJ5LLMGM.js";
21
+ } from "./chunk-2BEWWQL2.js";
20
22
  import {
21
23
  CodeChunker,
22
24
  CodeIndexer,
@@ -25,29 +27,68 @@ import {
25
27
  code,
26
28
  getLanguage,
27
29
  isSupported
28
- } from "./chunk-4DM3XWO6.js";
30
+ } from "./chunk-MGIFEPYZ.js";
29
31
  import {
30
32
  CoEditAnalyzer,
31
33
  GitIndexer,
32
34
  git
33
- } from "./chunk-7JCEW7LT.js";
35
+ } from "./chunk-FI7GWG4W.js";
34
36
  import {
35
37
  DocsIndexer,
36
38
  docs
37
- } from "./chunk-T2VXF5S5.js";
39
+ } from "./chunk-Y3JKI6QN.js";
38
40
  import {
39
41
  reciprocalRankFusion
40
- } from "./chunk-FEAMUZGJ.js";
42
+ } from "./chunk-E6WQM4DN.js";
41
43
  import {
42
44
  cosineSimilarity,
43
45
  normalize
44
46
  } from "./chunk-QNHBCOKB.js";
45
47
  import {
46
48
  OpenAIEmbedding
47
- } from "./chunk-GUT5MSJT.js";
48
- import "./chunk-7QVYU63E.js";
49
+ } from "./chunk-CCXVL56V.js";
50
+ import {
51
+ __name
52
+ } from "./chunk-7QVYU63E.js";
53
+
54
+ // src/types.ts
55
+ function isCodeResult(r) {
56
+ return r.type === "code";
57
+ }
58
+ __name(isCodeResult, "isCodeResult");
59
+ function isCommitResult(r) {
60
+ return r.type === "commit";
61
+ }
62
+ __name(isCommitResult, "isCommitResult");
63
+ function isDocumentResult(r) {
64
+ return r.type === "document";
65
+ }
66
+ __name(isDocumentResult, "isDocumentResult");
67
+ function isPatternResult(r) {
68
+ return r.type === "pattern";
69
+ }
70
+ __name(isPatternResult, "isPatternResult");
71
+ function isCollectionResult(r) {
72
+ return r.type === "collection";
73
+ }
74
+ __name(isCollectionResult, "isCollectionResult");
75
+ function matchResult(result, handlers) {
76
+ switch (result.type) {
77
+ case "code":
78
+ return (handlers.code ?? handlers._)?.(result);
79
+ case "commit":
80
+ return (handlers.commit ?? handlers._)?.(result);
81
+ case "pattern":
82
+ return (handlers.pattern ?? handlers._)?.(result);
83
+ case "document":
84
+ return (handlers.document ?? handlers._)?.(result);
85
+ case "collection":
86
+ return (handlers.collection ?? handlers._)?.(result);
87
+ }
88
+ }
89
+ __name(matchResult, "matchResult");
49
90
  export {
50
- BM25Search,
91
+ KeywordSearch as BM25Search,
51
92
  BrainBank,
52
93
  CoEditAnalyzer,
53
94
  CodeChunker,
@@ -60,19 +101,29 @@ export {
60
101
  GitIndexer,
61
102
  HNSWIndex,
62
103
  IGNORE_DIRS,
104
+ KeywordSearch,
63
105
  LocalEmbedding,
64
- MultiIndexSearch,
106
+ VectorSearch as MultiIndexSearch,
65
107
  NoteStore,
66
108
  OpenAIEmbedding,
67
109
  PatternStore,
68
110
  SUPPORTED_EXTENSIONS,
111
+ VectorSearch,
69
112
  code,
70
113
  cosineSimilarity,
71
114
  docs,
72
115
  getLanguage,
73
116
  git,
117
+ isCodeResult,
118
+ isCollectionResult,
119
+ isCommitResult,
120
+ isDocumentResult,
121
+ isPatternResult,
74
122
  isSupported,
123
+ matchResult,
124
+ memory,
75
125
  normalize,
126
+ notes,
76
127
  reciprocalRankFusion,
77
128
  resolveConfig,
78
129
  searchMMR
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":[],"sourcesContent":[],"mappings":"","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":[]}
package/dist/memory.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { I as Indexer } from './base-9vfWRHCV.js';
1
+ import { I as Indexer } from './base-4SUgeRWT.js';
2
2
  import 'better-sqlite3';
3
3
 
4
4
  /**
package/dist/memory.js CHANGED
@@ -1,142 +1,8 @@
1
1
  import {
2
- Consolidator,
3
- PatternStore
4
- } from "./chunk-X6645UVR.js";
2
+ memory
3
+ } from "./chunk-FINIFKAY.js";
5
4
  import "./chunk-QNHBCOKB.js";
6
- import {
7
- __name
8
- } from "./chunk-7QVYU63E.js";
9
-
10
- // src/memory/distiller.ts
11
- var StrategyDistiller = class {
12
- constructor(_db) {
13
- this._db = _db;
14
- }
15
- static {
16
- __name(this, "StrategyDistiller");
17
- }
18
- /**
19
- * Distill top patterns for a task type into a strategy.
20
- * Updates the distilled_strategies table.
21
- */
22
- distill(taskType, topK = 10) {
23
- const patterns = this._db.prepare(`
24
- SELECT task, approach, outcome, critique, success_rate
25
- FROM memory_patterns
26
- WHERE task_type = ? AND success_rate >= 0.7
27
- ORDER BY success_rate DESC, created_at DESC
28
- LIMIT ?
29
- `).all(taskType, topK);
30
- if (patterns.length === 0) return null;
31
- const lines = [];
32
- const avgSuccess = patterns.reduce((sum, p) => sum + p.success_rate, 0) / patterns.length;
33
- lines.push(`Strategy for "${taskType}" (${patterns.length} patterns, avg success ${Math.round(avgSuccess * 100)}%):`);
34
- lines.push("");
35
- for (const p of patterns) {
36
- lines.push(`\u2022 ${p.approach} (${Math.round(p.success_rate * 100)}%)`);
37
- if (p.critique) lines.push(` \u2514 ${p.critique}`);
38
- }
39
- const strategy = lines.join("\n");
40
- const confidence = avgSuccess;
41
- const now = Math.floor(Date.now() / 1e3);
42
- this._db.prepare(`
43
- INSERT INTO distilled_strategies (task_type, strategy, confidence, updated_at)
44
- VALUES (?, ?, ?, ?)
45
- ON CONFLICT(task_type) DO UPDATE SET
46
- strategy = excluded.strategy,
47
- confidence = excluded.confidence,
48
- updated_at = excluded.updated_at
49
- `).run(taskType, strategy, confidence, now);
50
- return { taskType, strategy, confidence, updatedAt: now };
51
- }
52
- /**
53
- * Get a distilled strategy for a task type.
54
- */
55
- get(taskType) {
56
- const row = this._db.prepare(
57
- "SELECT * FROM distilled_strategies WHERE task_type = ?"
58
- ).get(taskType);
59
- if (!row) return null;
60
- return {
61
- taskType: row.task_type,
62
- strategy: row.strategy,
63
- confidence: row.confidence,
64
- updatedAt: row.updated_at
65
- };
66
- }
67
- /**
68
- * List all distilled strategies.
69
- */
70
- list() {
71
- const rows = this._db.prepare(
72
- "SELECT * FROM distilled_strategies ORDER BY confidence DESC"
73
- ).all();
74
- return rows.map((r) => ({
75
- taskType: r.task_type,
76
- strategy: r.strategy,
77
- confidence: r.confidence,
78
- updatedAt: r.updated_at
79
- }));
80
- }
81
- };
82
-
83
- // src/indexers/memory/memory-plugin.ts
84
- var MemoryPlugin = class {
85
- static {
86
- __name(this, "MemoryPlugin");
87
- }
88
- name = "memory";
89
- hnsw;
90
- patternStore;
91
- consolidator;
92
- distiller;
93
- vecCache = /* @__PURE__ */ new Map();
94
- _db;
95
- async initialize(ctx) {
96
- this._db = ctx.db;
97
- this.hnsw = await ctx.createHnsw(1e5);
98
- ctx.loadVectors("memory_vectors", "pattern_id", this.hnsw, this.vecCache);
99
- this.patternStore = new PatternStore({
100
- db: ctx.db,
101
- hnsw: this.hnsw,
102
- vectorCache: this.vecCache,
103
- embedding: ctx.embedding
104
- });
105
- this.consolidator = new Consolidator(ctx.db, this.vecCache);
106
- this.distiller = new StrategyDistiller(ctx.db);
107
- }
108
- /** Store a learned pattern. */
109
- async learn(pattern) {
110
- const id = await this.patternStore.learn(pattern);
111
- if (this.patternStore.count > 0 && this.patternStore.count % 50 === 0) {
112
- this.consolidator.consolidate();
113
- }
114
- return id;
115
- }
116
- /** Search for similar patterns. */
117
- async search(query, k = 4) {
118
- return this.patternStore.search(query, k);
119
- }
120
- /** Consolidate: prune old failures + deduplicate. */
121
- consolidate() {
122
- return this.consolidator.consolidate();
123
- }
124
- /** Distill patterns into a strategy. */
125
- distill(taskType) {
126
- return this.distiller.distill(taskType);
127
- }
128
- stats() {
129
- return {
130
- patterns: this.patternStore.count,
131
- avgSuccess: this._db.prepare("SELECT AVG(success_rate) as a FROM memory_patterns").get().a ?? 0,
132
- hnswSize: this.hnsw.size
133
- };
134
- }
135
- };
136
- function memory() {
137
- return new MemoryPlugin();
138
- }
139
- __name(memory, "memory");
5
+ import "./chunk-7QVYU63E.js";
140
6
  export {
141
7
  memory
142
8
  };