brainbank 0.1.3 → 0.1.4

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 (167) hide show
  1. package/README.md +84 -1107
  2. package/assets/architecture.png +0 -0
  3. package/bin/brainbank +8 -1
  4. package/bin/brainbank-mcp +19 -0
  5. package/dist/chunk-3UIWA32X.js +3341 -0
  6. package/dist/chunk-3UIWA32X.js.map +1 -0
  7. package/dist/chunk-3YBCD6DI.js +117 -0
  8. package/dist/chunk-3YBCD6DI.js.map +1 -0
  9. package/dist/chunk-DAGVUEXL.js +258 -0
  10. package/dist/chunk-DAGVUEXL.js.map +1 -0
  11. package/dist/chunk-DMFMTOHF.js +123 -0
  12. package/dist/chunk-DMFMTOHF.js.map +1 -0
  13. package/dist/chunk-FQYKWB2Q.js +136 -0
  14. package/dist/chunk-FQYKWB2Q.js.map +1 -0
  15. package/dist/chunk-IMJJ2VEM.js +74 -0
  16. package/dist/chunk-IMJJ2VEM.js.map +1 -0
  17. package/dist/chunk-M744PCJQ.js +43 -0
  18. package/dist/chunk-M744PCJQ.js.map +1 -0
  19. package/dist/chunk-NNDY7P2R.js +211 -0
  20. package/dist/chunk-NNDY7P2R.js.map +1 -0
  21. package/dist/chunk-O3J6ZIXK.js +82 -0
  22. package/dist/chunk-O3J6ZIXK.js.map +1 -0
  23. package/dist/chunk-RDQYDLYZ.js +69 -0
  24. package/dist/chunk-RDQYDLYZ.js.map +1 -0
  25. package/dist/chunk-WCQVDF3K.js +14 -0
  26. package/dist/cli.js +2713 -325
  27. package/dist/cli.js.map +1 -1
  28. package/dist/haiku-pruner-5KVT5AI2.js +8 -0
  29. package/dist/http-server-2ZQ6I43B.js +9 -0
  30. package/dist/index.d.ts +1886 -626
  31. package/dist/index.js +319 -46
  32. package/dist/index.js.map +1 -1
  33. package/dist/local-embedding-NZQTILGV.js +8 -0
  34. package/dist/mcp.d.ts +2 -0
  35. package/dist/mcp.js +386 -0
  36. package/dist/mcp.js.map +1 -0
  37. package/dist/openai-embedding-ZP5TSUJG.js +8 -0
  38. package/dist/perplexity-context-embedding-GI5PHE6X.js +9 -0
  39. package/dist/perplexity-context-embedding-GI5PHE6X.js.map +1 -0
  40. package/dist/perplexity-embedding-KZRYGJRC.js +10 -0
  41. package/dist/perplexity-embedding-KZRYGJRC.js.map +1 -0
  42. package/dist/plugin-IKQ6IRSJ.js +32 -0
  43. package/dist/plugin-IKQ6IRSJ.js.map +1 -0
  44. package/dist/resolve-ASGLBNUC.js +10 -0
  45. package/dist/resolve-ASGLBNUC.js.map +1 -0
  46. package/dist/stats-tui-AD3AMYGV.js +1904 -0
  47. package/dist/stats-tui-AD3AMYGV.js.map +1 -0
  48. package/package.json +38 -53
  49. package/src/brainbank.ts +617 -0
  50. package/src/cli/commands/collection.ts +77 -0
  51. package/src/cli/commands/context.ts +59 -0
  52. package/src/cli/commands/daemon.ts +100 -0
  53. package/src/cli/commands/docs.ts +71 -0
  54. package/src/cli/commands/files.ts +69 -0
  55. package/src/cli/commands/help.ts +82 -0
  56. package/src/cli/commands/index.ts +478 -0
  57. package/src/cli/commands/kv.ts +140 -0
  58. package/src/cli/commands/mcp-export.ts +273 -0
  59. package/src/cli/commands/mcp.ts +6 -0
  60. package/src/cli/commands/query.ts +167 -0
  61. package/src/cli/commands/reembed.ts +30 -0
  62. package/src/cli/commands/reindex.ts +40 -0
  63. package/src/cli/commands/scan.ts +336 -0
  64. package/src/cli/commands/search.ts +203 -0
  65. package/src/cli/commands/stats.ts +68 -0
  66. package/src/cli/commands/status.ts +47 -0
  67. package/src/cli/commands/watch.ts +47 -0
  68. package/src/cli/factory/brain-context.ts +43 -0
  69. package/src/cli/factory/builtin-registration.ts +87 -0
  70. package/src/cli/factory/config-loader.ts +77 -0
  71. package/src/cli/factory/index.ts +69 -0
  72. package/src/cli/factory/plugin-loader.ts +324 -0
  73. package/src/cli/index.ts +76 -0
  74. package/src/cli/server-client.ts +186 -0
  75. package/src/cli/tui/index-tui.tsx +667 -0
  76. package/src/cli/tui/stats-data.ts +523 -0
  77. package/src/cli/tui/stats-search.ts +262 -0
  78. package/src/cli/tui/stats-tui.tsx +1465 -0
  79. package/src/cli/tui/tree-scanner.ts +650 -0
  80. package/src/cli/utils.ts +137 -0
  81. package/src/config.ts +48 -0
  82. package/src/constants.ts +21 -0
  83. package/src/db/adapter.ts +112 -0
  84. package/src/db/metadata.ts +130 -0
  85. package/src/db/migrations.ts +66 -0
  86. package/src/db/sqlite-adapter.ts +218 -0
  87. package/src/db/tracker.ts +91 -0
  88. package/src/engine/index-api.ts +81 -0
  89. package/src/engine/reembed.ts +206 -0
  90. package/src/engine/search-api.ts +218 -0
  91. package/src/index.ts +150 -0
  92. package/src/lib/fts.ts +57 -0
  93. package/src/lib/languages.ts +179 -0
  94. package/src/lib/logger.ts +126 -0
  95. package/src/lib/math.ts +87 -0
  96. package/src/lib/provider-key.ts +20 -0
  97. package/src/lib/prune.ts +72 -0
  98. package/src/lib/rrf.ts +133 -0
  99. package/src/lib/write-lock.ts +108 -0
  100. package/src/mcp/mcp-server.ts +268 -0
  101. package/src/mcp/workspace-factory.ts +68 -0
  102. package/src/mcp/workspace-pool.ts +224 -0
  103. package/src/plugin.ts +381 -0
  104. package/src/providers/embeddings/embedding-worker-thread.ts +95 -0
  105. package/src/providers/embeddings/embedding-worker.ts +141 -0
  106. package/src/providers/embeddings/local-embedding.ts +115 -0
  107. package/src/providers/embeddings/openai-embedding.ts +167 -0
  108. package/src/providers/embeddings/perplexity-context-embedding.ts +195 -0
  109. package/src/providers/embeddings/perplexity-embedding.ts +165 -0
  110. package/src/providers/embeddings/resolve.ts +34 -0
  111. package/src/providers/pruners/haiku-expander.ts +178 -0
  112. package/src/providers/pruners/haiku-pruner.ts +263 -0
  113. package/src/providers/vector/hnsw-index.ts +174 -0
  114. package/src/providers/vector/hnsw-loader.ts +129 -0
  115. package/src/search/bm25-boost.ts +76 -0
  116. package/src/search/context-builder.ts +209 -0
  117. package/src/search/keyword/composite-bm25-search.ts +47 -0
  118. package/src/search/query-decomposer.ts +124 -0
  119. package/src/search/types.ts +37 -0
  120. package/src/search/vector/composite-vector-search.ts +105 -0
  121. package/src/search/vector/mmr.ts +64 -0
  122. package/src/services/collection.ts +384 -0
  123. package/src/services/daemon.ts +87 -0
  124. package/src/services/http-server.ts +344 -0
  125. package/src/services/kv-service.ts +64 -0
  126. package/src/services/plugin-registry.ts +77 -0
  127. package/src/services/watch.ts +340 -0
  128. package/src/services/webhook-server.ts +100 -0
  129. package/src/types.ts +509 -0
  130. package/dist/chunk-2P3EGY6S.js +0 -37
  131. package/dist/chunk-2P3EGY6S.js.map +0 -1
  132. package/dist/chunk-3GAIDXRW.js +0 -105
  133. package/dist/chunk-3GAIDXRW.js.map +0 -1
  134. package/dist/chunk-4ZKBQ33J.js +0 -56
  135. package/dist/chunk-4ZKBQ33J.js.map +0 -1
  136. package/dist/chunk-7QVYU63E.js +0 -7
  137. package/dist/chunk-GOUBW7UA.js +0 -373
  138. package/dist/chunk-GOUBW7UA.js.map +0 -1
  139. package/dist/chunk-MJ3Y24H6.js +0 -185
  140. package/dist/chunk-MJ3Y24H6.js.map +0 -1
  141. package/dist/chunk-N6ZMBFDE.js +0 -224
  142. package/dist/chunk-N6ZMBFDE.js.map +0 -1
  143. package/dist/chunk-RAEBYV75.js +0 -709
  144. package/dist/chunk-RAEBYV75.js.map +0 -1
  145. package/dist/chunk-TW5NTYYZ.js +0 -2066
  146. package/dist/chunk-TW5NTYYZ.js.map +0 -1
  147. package/dist/chunk-Z5SU54HP.js +0 -171
  148. package/dist/chunk-Z5SU54HP.js.map +0 -1
  149. package/dist/code.d.ts +0 -31
  150. package/dist/code.js +0 -8
  151. package/dist/docs.d.ts +0 -19
  152. package/dist/docs.js +0 -8
  153. package/dist/git.d.ts +0 -31
  154. package/dist/git.js +0 -8
  155. package/dist/memory.d.ts +0 -19
  156. package/dist/memory.js +0 -146
  157. package/dist/memory.js.map +0 -1
  158. package/dist/notes.d.ts +0 -19
  159. package/dist/notes.js +0 -57
  160. package/dist/notes.js.map +0 -1
  161. package/dist/openai-PCTYLOWI.js +0 -8
  162. package/dist/types-Da_zLLOl.d.ts +0 -474
  163. /package/dist/{chunk-7QVYU63E.js.map → chunk-WCQVDF3K.js.map} +0 -0
  164. /package/dist/{code.js.map → haiku-pruner-5KVT5AI2.js.map} +0 -0
  165. /package/dist/{docs.js.map → http-server-2ZQ6I43B.js.map} +0 -0
  166. /package/dist/{git.js.map → local-embedding-NZQTILGV.js.map} +0 -0
  167. /package/dist/{openai-PCTYLOWI.js.map → openai-embedding-ZP5TSUJG.js.map} +0 -0
@@ -1,709 +0,0 @@
1
- import {
2
- __name
3
- } from "./chunk-7QVYU63E.js";
4
-
5
- // src/indexers/code-indexer.ts
6
- import fs from "fs";
7
- import path2 from "path";
8
-
9
- // src/indexers/chunker.ts
10
- import { createRequire } from "module";
11
- var require2 = createRequire(import.meta.url);
12
- function tryGrammar(pkg, nodeTypes, accessor) {
13
- return () => {
14
- try {
15
- const mod = require2(pkg);
16
- return { grammar: accessor ? mod[accessor] : mod, nodeTypes };
17
- } catch {
18
- return null;
19
- }
20
- };
21
- }
22
- __name(tryGrammar, "tryGrammar");
23
- var GRAMMARS = {
24
- // ── Web ──────────────────────────────────────────
25
- typescript: tryGrammar("tree-sitter-typescript", {
26
- class: ["class_declaration"],
27
- interface: ["interface_declaration", "type_alias_declaration"],
28
- function: ["function_declaration", "method_definition"],
29
- variable: ["lexical_declaration"]
30
- }, "typescript"),
31
- javascript: tryGrammar("tree-sitter-javascript", {
32
- class: ["class_declaration"],
33
- function: ["function_declaration", "method_definition"],
34
- variable: ["lexical_declaration"]
35
- }),
36
- html: tryGrammar("tree-sitter-html", {}),
37
- css: tryGrammar("tree-sitter-css", {}),
38
- // ── Systems ──────────────────────────────────────
39
- go: tryGrammar("tree-sitter-go", {
40
- function: ["function_declaration", "method_declaration"],
41
- struct: ["type_declaration"]
42
- }),
43
- rust: tryGrammar("tree-sitter-rust", {
44
- function: ["function_item"],
45
- struct: ["struct_item"],
46
- impl: ["impl_item"]
47
- }),
48
- c: tryGrammar("tree-sitter-c", {
49
- function: ["function_definition"],
50
- struct: ["struct_specifier"]
51
- }),
52
- cpp: tryGrammar("tree-sitter-cpp", {
53
- class: ["class_specifier"],
54
- function: ["function_definition"]
55
- }),
56
- swift: tryGrammar("tree-sitter-swift", {
57
- class: ["class_declaration"],
58
- function: ["function_declaration"],
59
- struct: ["struct_declaration"]
60
- }),
61
- // ── JVM ──────────────────────────────────────────
62
- java: tryGrammar("tree-sitter-java", {
63
- class: ["class_declaration"],
64
- interface: ["interface_declaration"],
65
- method: ["method_declaration"]
66
- }),
67
- kotlin: tryGrammar("tree-sitter-kotlin", {
68
- class: ["class_declaration"],
69
- function: ["function_declaration"]
70
- }),
71
- scala: tryGrammar("tree-sitter-scala", {
72
- class: ["class_definition"],
73
- function: ["function_definition"]
74
- }),
75
- // ── Scripting ────────────────────────────────────
76
- python: tryGrammar("tree-sitter-python", {
77
- class: ["class_definition"],
78
- function: ["function_definition"]
79
- }),
80
- ruby: tryGrammar("tree-sitter-ruby", {
81
- class: ["class"],
82
- method: ["method", "singleton_method"]
83
- }),
84
- php: tryGrammar("tree-sitter-php", {
85
- class: ["class_declaration"],
86
- function: ["function_definition", "method_declaration"]
87
- }, "php"),
88
- lua: tryGrammar("tree-sitter-lua", {
89
- function: ["function_declaration"]
90
- }),
91
- bash: tryGrammar("tree-sitter-bash", {
92
- function: ["function_definition"]
93
- }),
94
- elixir: tryGrammar("tree-sitter-elixir", {
95
- function: ["call"]
96
- // defmodule, def, defp
97
- }),
98
- // ── .NET ─────────────────────────────────────────
99
- c_sharp: tryGrammar("tree-sitter-c-sharp", {
100
- class: ["class_declaration"],
101
- interface: ["interface_declaration"],
102
- method: ["method_declaration"]
103
- })
104
- };
105
- var CodeChunker = class {
106
- static {
107
- __name(this, "CodeChunker");
108
- }
109
- MAX;
110
- MIN;
111
- OVERLAP;
112
- _parser = null;
113
- _langCache = /* @__PURE__ */ new Map();
114
- constructor(config = {}) {
115
- this.MAX = config.maxLines ?? 80;
116
- this.MIN = config.minLines ?? 3;
117
- this.OVERLAP = config.overlap ?? 5;
118
- }
119
- /** Lazy-init tree-sitter parser. */
120
- _ensureParser() {
121
- if (!this._parser) {
122
- try {
123
- const Parser = require2("tree-sitter");
124
- this._parser = new Parser();
125
- } catch {
126
- this._parser = false;
127
- }
128
- }
129
- return this._parser || null;
130
- }
131
- /** Load a language grammar (cached). */
132
- _loadGrammar(language) {
133
- if (this._langCache.has(language)) return this._langCache.get(language);
134
- const factory = GRAMMARS[language];
135
- const grammar = factory ? factory() : null;
136
- this._langCache.set(language, grammar);
137
- return grammar;
138
- }
139
- /**
140
- * Split file content into semantic chunks using tree-sitter AST.
141
- * Falls back to sliding window if grammar isn't available.
142
- */
143
- async chunk(filePath, content, language) {
144
- const lines = content.split("\n");
145
- if (lines.length <= this.MAX) {
146
- return [{
147
- filePath,
148
- chunkType: "file",
149
- startLine: 1,
150
- endLine: lines.length,
151
- content: content.trim(),
152
- language
153
- }];
154
- }
155
- const parser = this._ensureParser();
156
- const langConfig = this._loadGrammar(language);
157
- if (parser && langConfig) {
158
- try {
159
- parser.setLanguage(langConfig.grammar);
160
- const tree = parser.parse(content);
161
- const chunks = this._extractChunks(filePath, lines, tree.rootNode, langConfig, language);
162
- if (chunks.length > 0) {
163
- return chunks.filter((c) => c.content.length > 20);
164
- }
165
- } catch {
166
- }
167
- }
168
- return this._chunkGeneric(filePath, lines, language);
169
- }
170
- /** Walk AST and extract top-level semantic blocks. */
171
- _extractChunks(filePath, lines, rootNode, langConfig, language) {
172
- const chunks = [];
173
- const seen = /* @__PURE__ */ new Set();
174
- for (let i = 0; i < rootNode.childCount; i++) {
175
- const child = rootNode.child(i);
176
- this._processNode(filePath, lines, child, langConfig, language, chunks, seen);
177
- }
178
- return chunks;
179
- }
180
- /** Classify and process a single AST node. */
181
- _processNode(filePath, lines, node, langConfig, language, chunks, seen) {
182
- const type = node.type;
183
- if (type === "export_statement") {
184
- for (let i = 0; i < node.childCount; i++) {
185
- const child = node.child(i);
186
- const category2 = this._categorize(child.type, langConfig);
187
- if (category2) {
188
- this._processDeclaration(filePath, lines, node, child, category2, langConfig, language, chunks, seen);
189
- return;
190
- }
191
- }
192
- const nodeLines = node.endPosition.row - node.startPosition.row + 1;
193
- if (nodeLines >= this.MIN) {
194
- this._addChunk(filePath, lines, node, "function", this._extractName(node), language, chunks, seen);
195
- }
196
- return;
197
- }
198
- if (type === "decorated_definition") {
199
- for (let i = 0; i < node.childCount; i++) {
200
- const child = node.child(i);
201
- const category2 = this._categorize(child.type, langConfig);
202
- if (category2) {
203
- this._processDeclaration(filePath, lines, node, child, category2, langConfig, language, chunks, seen);
204
- return;
205
- }
206
- }
207
- }
208
- const category = this._categorize(type, langConfig);
209
- if (category) {
210
- this._processDeclaration(filePath, lines, node, node, category, langConfig, language, chunks, seen);
211
- }
212
- }
213
- /** Check which category a node type belongs to. */
214
- _categorize(nodeType, langConfig) {
215
- for (const [category, types] of Object.entries(langConfig.nodeTypes)) {
216
- if (types && types.includes(nodeType)) return category;
217
- }
218
- return null;
219
- }
220
- /** Process a matched declaration: class → split by methods, else → chunk directly. */
221
- _processDeclaration(filePath, lines, outerNode, innerNode, category, langConfig, language, chunks, seen) {
222
- const nodeLines = outerNode.endPosition.row - outerNode.startPosition.row + 1;
223
- const name = this._extractName(innerNode);
224
- const chunkType = this._toChunkType(category);
225
- if ((category === "class" || category === "struct" || category === "impl") && nodeLines > this.MAX) {
226
- this._splitClassIntoMethods(filePath, lines, outerNode, innerNode, name, langConfig, language, chunks, seen);
227
- return;
228
- }
229
- if (nodeLines > this.MAX) {
230
- chunks.push(...this._splitLargeBlock(
231
- filePath,
232
- lines,
233
- outerNode.startPosition.row,
234
- outerNode.endPosition.row,
235
- name,
236
- chunkType,
237
- language
238
- ));
239
- return;
240
- }
241
- if (nodeLines >= this.MIN) {
242
- this._addChunk(filePath, lines, outerNode, chunkType, name, language, chunks, seen);
243
- }
244
- }
245
- /** Split a large class into individual method chunks. */
246
- _splitClassIntoMethods(filePath, lines, outerNode, classNode, className, langConfig, language, chunks, seen) {
247
- const body = this._findClassBody(classNode);
248
- if (!body) {
249
- chunks.push(...this._splitLargeBlock(
250
- filePath,
251
- lines,
252
- outerNode.startPosition.row,
253
- outerNode.endPosition.row,
254
- className,
255
- "class",
256
- language
257
- ));
258
- return;
259
- }
260
- const methodTypes = /* @__PURE__ */ new Set([
261
- ...langConfig.nodeTypes.function || [],
262
- ...langConfig.nodeTypes.method || []
263
- ]);
264
- let methodsFound = false;
265
- for (let i = 0; i < body.childCount; i++) {
266
- const child = body.child(i);
267
- let methodNode = child;
268
- if (child.type === "decorated_definition") {
269
- for (let j = 0; j < child.childCount; j++) {
270
- if (methodTypes.has(child.child(j).type)) {
271
- methodNode = child.child(j);
272
- break;
273
- }
274
- }
275
- }
276
- if (methodTypes.has(methodNode.type) || methodTypes.has(child.type)) {
277
- const methodName = this._extractName(methodNode);
278
- const nodeToChunk = child.type === "decorated_definition" ? child : methodNode;
279
- const methodLineCount = nodeToChunk.endPosition.row - nodeToChunk.startPosition.row + 1;
280
- if (methodLineCount >= this.MIN) {
281
- methodsFound = true;
282
- const fullName = `${className}.${methodName}`;
283
- if (methodLineCount > this.MAX) {
284
- chunks.push(...this._splitLargeBlock(
285
- filePath,
286
- lines,
287
- nodeToChunk.startPosition.row,
288
- nodeToChunk.endPosition.row,
289
- fullName,
290
- "method",
291
- language
292
- ));
293
- } else {
294
- this._addChunk(filePath, lines, nodeToChunk, "method", fullName, language, chunks, seen);
295
- }
296
- }
297
- }
298
- }
299
- if (!methodsFound) {
300
- chunks.push(...this._splitLargeBlock(
301
- filePath,
302
- lines,
303
- outerNode.startPosition.row,
304
- outerNode.endPosition.row,
305
- className,
306
- "class",
307
- language
308
- ));
309
- }
310
- }
311
- /** Find the class body node. */
312
- _findClassBody(classNode) {
313
- const bodyTypes = ["class_body", "block", "declaration_list", "body"];
314
- for (let i = 0; i < classNode.childCount; i++) {
315
- const child = classNode.child(i);
316
- if (bodyTypes.includes(child.type)) return child;
317
- }
318
- return null;
319
- }
320
- /** Extract name from an AST node. */
321
- _extractName(node) {
322
- if (typeof node.childForFieldName === "function") {
323
- const nameNode = node.childForFieldName("name");
324
- if (nameNode) return nameNode.text;
325
- }
326
- for (let i = 0; i < node.namedChildCount; i++) {
327
- const child = node.namedChild(i);
328
- if (["identifier", "type_identifier", "property_identifier"].includes(child.type)) {
329
- return child.text;
330
- }
331
- }
332
- if (node.type === "lexical_declaration" || node.type === "variable_declaration") {
333
- for (let i = 0; i < node.namedChildCount; i++) {
334
- const child = node.namedChild(i);
335
- if (child.type === "variable_declarator") {
336
- const nameNode = child.childForFieldName("name");
337
- if (nameNode) return nameNode.text;
338
- }
339
- }
340
- }
341
- return "anonymous";
342
- }
343
- /** Map category to chunk type. */
344
- _toChunkType(category) {
345
- if (category === "class" || category === "struct" || category === "impl") return "class";
346
- if (category === "interface") return "interface";
347
- if (category === "variable") return "function";
348
- return category;
349
- }
350
- /** Add a node as a chunk, avoiding duplicates. */
351
- _addChunk(filePath, lines, node, chunkType, name, language, chunks, seen) {
352
- const start = node.startPosition.row;
353
- const end = node.endPosition.row;
354
- const key = `${start}-${end}`;
355
- if (seen.has(key)) return;
356
- seen.add(key);
357
- const content = lines.slice(start, end + 1).join("\n").trim();
358
- if (content.length <= 20) return;
359
- chunks.push({
360
- filePath,
361
- chunkType,
362
- name,
363
- startLine: start + 1,
364
- endLine: end + 1,
365
- content,
366
- language
367
- });
368
- }
369
- // ── Fallback: Generic sliding window ────────────
370
- _chunkGeneric(filePath, lines, language) {
371
- const chunks = [];
372
- const step = this.MAX - this.OVERLAP;
373
- for (let s = 0; s < lines.length; s += step) {
374
- const e = Math.min(s + this.MAX, lines.length);
375
- const content = lines.slice(s, e).join("\n").trim();
376
- if (content.length > 20) {
377
- chunks.push({
378
- filePath,
379
- chunkType: "block",
380
- startLine: s + 1,
381
- endLine: e,
382
- content,
383
- language
384
- });
385
- }
386
- if (e >= lines.length) break;
387
- }
388
- return chunks;
389
- }
390
- /** Split a large block into overlapping sub-chunks. */
391
- _splitLargeBlock(filePath, lines, start, end, name, type, language) {
392
- const chunks = [];
393
- const step = this.MAX - this.OVERLAP;
394
- let part = 1;
395
- for (let s = start; s <= end; s += step) {
396
- const e = Math.min(s + this.MAX, end + 1);
397
- const content = lines.slice(s, e).join("\n").trim();
398
- if (content.length > 20) {
399
- chunks.push({
400
- filePath,
401
- chunkType: type,
402
- name: `${name} (part ${part++})`,
403
- startLine: s + 1,
404
- endLine: e,
405
- content,
406
- language
407
- });
408
- }
409
- if (e > end) break;
410
- }
411
- return chunks;
412
- }
413
- };
414
-
415
- // src/indexers/languages.ts
416
- import path from "path";
417
- var SUPPORTED_EXTENSIONS = {
418
- // TypeScript / JavaScript
419
- ".ts": "typescript",
420
- ".tsx": "typescript",
421
- ".js": "javascript",
422
- ".jsx": "javascript",
423
- ".mjs": "javascript",
424
- ".cjs": "javascript",
425
- // Systems
426
- ".go": "go",
427
- ".rs": "rust",
428
- ".cpp": "cpp",
429
- ".cc": "cpp",
430
- ".c": "c",
431
- ".h": "c",
432
- ".hpp": "cpp",
433
- // JVM
434
- ".java": "java",
435
- ".kt": "kotlin",
436
- ".scala": "scala",
437
- // Scripting
438
- ".py": "python",
439
- ".rb": "ruby",
440
- ".php": "php",
441
- ".lua": "lua",
442
- ".sh": "bash",
443
- ".bash": "bash",
444
- ".zsh": "bash",
445
- // Web
446
- ".html": "html",
447
- ".css": "css",
448
- ".scss": "scss",
449
- ".less": "less",
450
- ".svelte": "svelte",
451
- ".vue": "vue",
452
- // Data / Config
453
- ".json": "json",
454
- ".yaml": "yaml",
455
- ".yml": "yaml",
456
- ".toml": "toml",
457
- ".xml": "xml",
458
- ".graphql": "graphql",
459
- ".gql": "graphql",
460
- // Docs
461
- ".md": "markdown",
462
- ".mdx": "markdown",
463
- // Database
464
- ".sql": "sql",
465
- ".prisma": "prisma",
466
- // Other
467
- ".swift": "swift",
468
- ".dart": "dart",
469
- ".r": "r",
470
- ".ex": "elixir",
471
- ".exs": "elixir",
472
- ".erl": "erlang",
473
- ".zig": "zig"
474
- };
475
- var IGNORE_DIRS = /* @__PURE__ */ new Set([
476
- // Package managers
477
- "node_modules",
478
- "bower_components",
479
- ".pnpm",
480
- // Build output
481
- "dist",
482
- "build",
483
- "out",
484
- ".next",
485
- ".nuxt",
486
- ".output",
487
- ".svelte-kit",
488
- // Version control
489
- ".git",
490
- ".hg",
491
- ".svn",
492
- // IDE / Editor
493
- ".idea",
494
- ".vscode",
495
- // Runtime / Cache
496
- "__pycache__",
497
- ".pytest_cache",
498
- "venv",
499
- ".venv",
500
- ".env",
501
- ".tox",
502
- // Coverage / Test artifacts
503
- "coverage",
504
- ".nyc_output",
505
- "htmlcov",
506
- // Compiled
507
- "target",
508
- // Rust, Java
509
- ".cargo",
510
- "vendor",
511
- // Go, PHP
512
- // AI / Model cache
513
- ".model-cache",
514
- ".brainbank",
515
- // OS
516
- ".DS_Store"
517
- ]);
518
- var IGNORE_FILES = /* @__PURE__ */ new Set([
519
- "package-lock.json",
520
- "yarn.lock",
521
- "pnpm-lock.yaml",
522
- "bun.lockb",
523
- "Cargo.lock",
524
- "Gemfile.lock",
525
- "poetry.lock",
526
- "composer.lock",
527
- "go.sum"
528
- ]);
529
- function isSupported(filePath) {
530
- const ext = path.extname(filePath).toLowerCase();
531
- return ext in SUPPORTED_EXTENSIONS;
532
- }
533
- __name(isSupported, "isSupported");
534
- function getLanguage(filePath) {
535
- const ext = path.extname(filePath).toLowerCase();
536
- return SUPPORTED_EXTENSIONS[ext];
537
- }
538
- __name(getLanguage, "getLanguage");
539
- function isIgnoredDir(dirName) {
540
- return IGNORE_DIRS.has(dirName) || dirName.startsWith(".");
541
- }
542
- __name(isIgnoredDir, "isIgnoredDir");
543
- function isIgnoredFile(fileName) {
544
- return IGNORE_FILES.has(fileName);
545
- }
546
- __name(isIgnoredFile, "isIgnoredFile");
547
-
548
- // src/indexers/code-indexer.ts
549
- var CodeIndexer = class {
550
- static {
551
- __name(this, "CodeIndexer");
552
- }
553
- _chunker = new CodeChunker();
554
- _deps;
555
- _repoPath;
556
- _maxFileSize;
557
- constructor(repoPath, deps, maxFileSize = 512e3) {
558
- this._deps = deps;
559
- this._repoPath = repoPath;
560
- this._maxFileSize = maxFileSize;
561
- }
562
- /**
563
- * Index all supported files in the repository.
564
- * Skips unchanged files (same content hash).
565
- */
566
- async index(options = {}) {
567
- const { forceReindex = false, onProgress } = options;
568
- const files = this._walkRepo(this._repoPath);
569
- let indexed = 0, skipped = 0, totalChunks = 0;
570
- for (let i = 0; i < files.length; i++) {
571
- const filePath = files[i];
572
- const rel = path2.relative(this._repoPath, filePath);
573
- onProgress?.(rel, i + 1, files.length);
574
- let content;
575
- try {
576
- content = fs.readFileSync(filePath, "utf-8");
577
- } catch {
578
- continue;
579
- }
580
- const hash = this._hash(content);
581
- const existing = this._deps.db.prepare(
582
- "SELECT file_hash FROM indexed_files WHERE file_path = ?"
583
- ).get(rel);
584
- if (!forceReindex && existing?.file_hash === hash) {
585
- skipped++;
586
- continue;
587
- }
588
- if (existing) {
589
- this._deps.db.prepare("DELETE FROM code_chunks WHERE file_path = ?").run(rel);
590
- }
591
- const ext = path2.extname(filePath).toLowerCase();
592
- const language = SUPPORTED_EXTENSIONS[ext] ?? "text";
593
- const chunks = await this._chunker.chunk(rel, content, language);
594
- for (const chunk of chunks) {
595
- const text = [
596
- `File: ${rel}`,
597
- chunk.name ? `${chunk.chunkType}: ${chunk.name}` : chunk.chunkType,
598
- chunk.content
599
- ].join("\n");
600
- const vec = await this._deps.embedding.embed(text);
601
- const result = this._deps.db.prepare(
602
- `INSERT INTO code_chunks (file_path, chunk_type, name, start_line, end_line, content, language, file_hash)
603
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)`
604
- ).run(rel, chunk.chunkType, chunk.name ?? null, chunk.startLine, chunk.endLine, chunk.content, language, hash);
605
- const id = Number(result.lastInsertRowid);
606
- this._deps.db.prepare(
607
- "INSERT INTO code_vectors (chunk_id, embedding) VALUES (?, ?)"
608
- ).run(id, Buffer.from(vec.buffer));
609
- this._deps.hnsw.add(vec, id);
610
- this._deps.vectorCache.set(id, vec);
611
- totalChunks++;
612
- }
613
- this._deps.db.prepare(
614
- "INSERT OR REPLACE INTO indexed_files (file_path, file_hash) VALUES (?, ?)"
615
- ).run(rel, hash);
616
- indexed++;
617
- }
618
- return { indexed, skipped, chunks: totalChunks };
619
- }
620
- // ── File Walker ─────────────────────────────────
621
- _walkRepo(dir, files = []) {
622
- let entries;
623
- try {
624
- entries = fs.readdirSync(dir, { withFileTypes: true });
625
- } catch {
626
- return files;
627
- }
628
- for (const entry of entries) {
629
- if (entry.isDirectory()) {
630
- if (isIgnoredDir(entry.name)) continue;
631
- this._walkRepo(path2.join(dir, entry.name), files);
632
- } else if (entry.isFile()) {
633
- if (isIgnoredFile(entry.name)) continue;
634
- const ext = path2.extname(entry.name).toLowerCase();
635
- if (!(ext in SUPPORTED_EXTENSIONS)) continue;
636
- const full = path2.join(dir, entry.name);
637
- try {
638
- if (fs.statSync(full).size <= this._maxFileSize) {
639
- files.push(full);
640
- }
641
- } catch {
642
- }
643
- }
644
- }
645
- return files;
646
- }
647
- // ── FNV-1a Hash ─────────────────────────────────
648
- _hash(content) {
649
- let h = 2166136261;
650
- for (let i = 0; i < content.length; i++) {
651
- h ^= content.charCodeAt(i);
652
- h = h * 16777619 >>> 0;
653
- }
654
- return h.toString(16);
655
- }
656
- };
657
-
658
- // src/plugins/code.ts
659
- var CodeModuleImpl = class {
660
- constructor(opts = {}) {
661
- this.opts = opts;
662
- this.name = opts.name ?? "code";
663
- }
664
- static {
665
- __name(this, "CodeModuleImpl");
666
- }
667
- name;
668
- hnsw;
669
- indexer;
670
- vecCache = /* @__PURE__ */ new Map();
671
- async initialize(ctx) {
672
- const shared = await ctx.getOrCreateSharedHnsw("code");
673
- this.hnsw = shared.hnsw;
674
- this.vecCache = shared.vecCache;
675
- if (shared.isNew) {
676
- ctx.loadVectors("code_vectors", "chunk_id", this.hnsw, this.vecCache);
677
- }
678
- const repoPath = this.opts.repoPath ?? ctx.config.repoPath;
679
- this.indexer = new CodeIndexer(repoPath, {
680
- db: ctx.db,
681
- hnsw: this.hnsw,
682
- vectorCache: this.vecCache,
683
- embedding: ctx.embedding
684
- }, this.opts.maxFileSize ?? ctx.config.maxFileSize);
685
- }
686
- async index(options = {}) {
687
- return this.indexer.index(options);
688
- }
689
- stats() {
690
- return { hnswSize: this.hnsw.size };
691
- }
692
- };
693
- function code(opts) {
694
- return new CodeModuleImpl(opts);
695
- }
696
- __name(code, "code");
697
-
698
- export {
699
- SUPPORTED_EXTENSIONS,
700
- IGNORE_DIRS,
701
- isSupported,
702
- getLanguage,
703
- isIgnoredDir,
704
- isIgnoredFile,
705
- CodeChunker,
706
- CodeIndexer,
707
- code
708
- };
709
- //# sourceMappingURL=chunk-RAEBYV75.js.map