indexer-cli 0.2.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.
Files changed (139) hide show
  1. package/README.md +156 -0
  2. package/bin/indexer-cli.js +97 -0
  3. package/dist/_temp_test.d.ts +1 -0
  4. package/dist/_temp_test.js +4 -0
  5. package/dist/_temp_test.js.map +1 -0
  6. package/dist/chunking/adaptive.d.ts +15 -0
  7. package/dist/chunking/adaptive.js +43 -0
  8. package/dist/chunking/adaptive.js.map +1 -0
  9. package/dist/chunking/function.d.ts +6 -0
  10. package/dist/chunking/function.js +96 -0
  11. package/dist/chunking/function.js.map +1 -0
  12. package/dist/chunking/index.d.ts +5 -0
  13. package/dist/chunking/index.js +22 -0
  14. package/dist/chunking/index.js.map +1 -0
  15. package/dist/chunking/module.d.ts +6 -0
  16. package/dist/chunking/module.js +33 -0
  17. package/dist/chunking/module.js.map +1 -0
  18. package/dist/chunking/single.d.ts +4 -0
  19. package/dist/chunking/single.js +19 -0
  20. package/dist/chunking/single.js.map +1 -0
  21. package/dist/chunking/types.d.ts +17 -0
  22. package/dist/chunking/types.js +3 -0
  23. package/dist/chunking/types.js.map +1 -0
  24. package/dist/cli/commands/architecture.d.ts +2 -0
  25. package/dist/cli/commands/architecture.js +162 -0
  26. package/dist/cli/commands/architecture.js.map +1 -0
  27. package/dist/cli/commands/context.d.ts +2 -0
  28. package/dist/cli/commands/context.js +241 -0
  29. package/dist/cli/commands/context.js.map +1 -0
  30. package/dist/cli/commands/deps.d.ts +2 -0
  31. package/dist/cli/commands/deps.js +129 -0
  32. package/dist/cli/commands/deps.js.map +1 -0
  33. package/dist/cli/commands/enrich.d.ts +2 -0
  34. package/dist/cli/commands/ensure-indexed.d.ts +4 -0
  35. package/dist/cli/commands/ensure-indexed.js +168 -0
  36. package/dist/cli/commands/ensure-indexed.js.map +1 -0
  37. package/dist/cli/commands/explain.d.ts +2 -0
  38. package/dist/cli/commands/explain.js +165 -0
  39. package/dist/cli/commands/explain.js.map +1 -0
  40. package/dist/cli/commands/index.d.ts +2 -0
  41. package/dist/cli/commands/index.js +271 -0
  42. package/dist/cli/commands/index.js.map +1 -0
  43. package/dist/cli/commands/init.d.ts +2 -0
  44. package/dist/cli/commands/init.js +132 -0
  45. package/dist/cli/commands/init.js.map +1 -0
  46. package/dist/cli/commands/search.d.ts +2 -0
  47. package/dist/cli/commands/search.js +206 -0
  48. package/dist/cli/commands/search.js.map +1 -0
  49. package/dist/cli/commands/setup.d.ts +2 -0
  50. package/dist/cli/commands/setup.js +425 -0
  51. package/dist/cli/commands/setup.js.map +1 -0
  52. package/dist/cli/commands/skill-template.d.ts +6 -0
  53. package/dist/cli/commands/skill-template.js +72 -0
  54. package/dist/cli/commands/skill-template.js.map +1 -0
  55. package/dist/cli/commands/structure.d.ts +2 -0
  56. package/dist/cli/commands/structure.js +243 -0
  57. package/dist/cli/commands/structure.js.map +1 -0
  58. package/dist/cli/commands/uninstall.d.ts +2 -0
  59. package/dist/cli/commands/uninstall.js +138 -0
  60. package/dist/cli/commands/uninstall.js.map +1 -0
  61. package/dist/cli/entry.d.ts +1 -0
  62. package/dist/cli/entry.js +55 -0
  63. package/dist/cli/entry.js.map +1 -0
  64. package/dist/cli/help-text.d.ts +2 -0
  65. package/dist/cli/help-text.js +9 -0
  66. package/dist/cli/help-text.js.map +1 -0
  67. package/dist/cli/version.d.ts +1 -0
  68. package/dist/cli/version.js +9 -0
  69. package/dist/cli/version.js.map +1 -0
  70. package/dist/core/config.d.ts +21 -0
  71. package/dist/core/config.js +77 -0
  72. package/dist/core/config.js.map +1 -0
  73. package/dist/core/logger.d.ts +19 -0
  74. package/dist/core/logger.js +116 -0
  75. package/dist/core/logger.js.map +1 -0
  76. package/dist/core/types.d.ts +194 -0
  77. package/dist/core/types.js +5 -0
  78. package/dist/core/types.js.map +1 -0
  79. package/dist/core/update-check.d.ts +1 -0
  80. package/dist/core/update-check.js +61 -0
  81. package/dist/core/update-check.js.map +1 -0
  82. package/dist/embedding/ollama.d.ts +29 -0
  83. package/dist/embedding/ollama.js +264 -0
  84. package/dist/embedding/ollama.js.map +1 -0
  85. package/dist/engine/architecture.d.ts +55 -0
  86. package/dist/engine/architecture.js +359 -0
  87. package/dist/engine/architecture.js.map +1 -0
  88. package/dist/engine/dependency-resolver.d.ts +4 -0
  89. package/dist/engine/dependency-resolver.js +69 -0
  90. package/dist/engine/dependency-resolver.js.map +1 -0
  91. package/dist/engine/git.d.ts +11 -0
  92. package/dist/engine/git.js +246 -0
  93. package/dist/engine/git.js.map +1 -0
  94. package/dist/engine/indexer.d.ts +86 -0
  95. package/dist/engine/indexer.js +933 -0
  96. package/dist/engine/indexer.js.map +1 -0
  97. package/dist/engine/scanner.d.ts +1 -0
  98. package/dist/engine/scanner.js +42 -0
  99. package/dist/engine/scanner.js.map +1 -0
  100. package/dist/engine/searcher.d.ts +26 -0
  101. package/dist/engine/searcher.js +70 -0
  102. package/dist/engine/searcher.js.map +1 -0
  103. package/dist/index.d.ts +1 -0
  104. package/dist/index.js +4 -0
  105. package/dist/index.js.map +1 -0
  106. package/dist/languages/csharp.d.ts +25 -0
  107. package/dist/languages/csharp.js +311 -0
  108. package/dist/languages/csharp.js.map +1 -0
  109. package/dist/languages/gdscript.d.ts +25 -0
  110. package/dist/languages/gdscript.js +382 -0
  111. package/dist/languages/gdscript.js.map +1 -0
  112. package/dist/languages/plugin.d.ts +73 -0
  113. package/dist/languages/plugin.js +35 -0
  114. package/dist/languages/plugin.js.map +1 -0
  115. package/dist/languages/python.d.ts +24 -0
  116. package/dist/languages/python.js +292 -0
  117. package/dist/languages/python.js.map +1 -0
  118. package/dist/languages/ruby.d.ts +25 -0
  119. package/dist/languages/ruby.js +328 -0
  120. package/dist/languages/ruby.js.map +1 -0
  121. package/dist/languages/typescript.d.ts +21 -0
  122. package/dist/languages/typescript.js +439 -0
  123. package/dist/languages/typescript.js.map +1 -0
  124. package/dist/storage/sqlite.d.ts +51 -0
  125. package/dist/storage/sqlite.js +726 -0
  126. package/dist/storage/sqlite.js.map +1 -0
  127. package/dist/storage/vectors.d.ts +39 -0
  128. package/dist/storage/vectors.js +450 -0
  129. package/dist/storage/vectors.js.map +1 -0
  130. package/dist/utils/gitignore.d.ts +4 -0
  131. package/dist/utils/gitignore.js +85 -0
  132. package/dist/utils/gitignore.js.map +1 -0
  133. package/dist/utils/hash.d.ts +1 -0
  134. package/dist/utils/hash.js +12 -0
  135. package/dist/utils/hash.js.map +1 -0
  136. package/dist/utils/token-estimator.d.ts +3 -0
  137. package/dist/utils/token-estimator.js +13 -0
  138. package/dist/utils/token-estimator.js.map +1 -0
  139. package/package.json +54 -0
@@ -0,0 +1,933 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.IndexerEngine = exports.createDefaultLanguagePlugins = exports.DEFAULT_LANGUAGE_PLUGIN_IDS = void 0;
4
+ const node_crypto_1 = require("node:crypto");
5
+ const promises_1 = require("node:fs/promises");
6
+ const node_path_1 = require("node:path");
7
+ const plugin_js_1 = require("../languages/plugin.js");
8
+ const typescript_js_1 = require("../languages/typescript.js");
9
+ const python_js_1 = require("../languages/python.js");
10
+ const csharp_js_1 = require("../languages/csharp.js");
11
+ const gdscript_js_1 = require("../languages/gdscript.js");
12
+ const ruby_js_1 = require("../languages/ruby.js");
13
+ const logger_js_1 = require("../core/logger.js");
14
+ const config_js_1 = require("../core/config.js");
15
+ const token_estimator_js_1 = require("../utils/token-estimator.js");
16
+ const hash_js_1 = require("../utils/hash.js");
17
+ const adaptive_js_1 = require("../chunking/adaptive.js");
18
+ const architecture_js_1 = require("./architecture.js");
19
+ const dependency_resolver_js_1 = require("./dependency-resolver.js");
20
+ const scanner_js_1 = require("./scanner.js");
21
+ const logger = new logger_js_1.SystemLogger("indexer-engine");
22
+ exports.DEFAULT_LANGUAGE_PLUGIN_IDS = [
23
+ "typescript",
24
+ "python",
25
+ "csharp",
26
+ "gdscript",
27
+ "ruby",
28
+ ];
29
+ const BUILTIN_LANGUAGE_PLUGIN_FACTORIES = {
30
+ typescript: () => new typescript_js_1.TypeScriptPlugin(),
31
+ python: () => new python_js_1.PythonPlugin(),
32
+ csharp: () => new csharp_js_1.CSharpPlugin(),
33
+ gdscript: () => new gdscript_js_1.GDScriptPlugin(),
34
+ ruby: () => new ruby_js_1.RubyPlugin(),
35
+ };
36
+ function normalizeImportKind(kind) {
37
+ if (kind === "require")
38
+ return "require";
39
+ if (kind === "dynamic_import")
40
+ return "dynamic_import";
41
+ return "import";
42
+ }
43
+ const createDefaultLanguagePlugins = (pluginIds) => {
44
+ const ids = pluginIds && pluginIds.length > 0 ? pluginIds : exports.DEFAULT_LANGUAGE_PLUGIN_IDS;
45
+ const normalizedIds = Array.from(new Set(ids
46
+ .map((value) => value.trim().toLowerCase())
47
+ .filter((value) => value.length > 0)));
48
+ return normalizedIds.map((id) => {
49
+ if (!(id in BUILTIN_LANGUAGE_PLUGIN_FACTORIES)) {
50
+ throw new Error(`Unsupported language plugin id: ${id}`);
51
+ }
52
+ return BUILTIN_LANGUAGE_PLUGIN_FACTORIES[id]();
53
+ });
54
+ };
55
+ exports.createDefaultLanguagePlugins = createDefaultLanguagePlugins;
56
+ class IndexerEngine {
57
+ projectId;
58
+ repoRoot;
59
+ metadata;
60
+ vectors;
61
+ embedder;
62
+ git;
63
+ languagePluginRegistry = new plugin_js_1.LanguagePluginRegistry();
64
+ indexingOptions;
65
+ churnByFile = new Map();
66
+ tokenEstimator = new token_estimator_js_1.TokenEstimator();
67
+ chunker = new adaptive_js_1.AdaptiveChunker();
68
+ architectureGenerator;
69
+ constructor(options) {
70
+ this.projectId = options.projectId;
71
+ this.repoRoot = options.repoRoot;
72
+ this.metadata = options.metadata;
73
+ this.vectors = options.vectors;
74
+ this.embedder = options.embedder;
75
+ this.git = options.git;
76
+ const languagePlugins = options.languagePlugins ?? (0, exports.createDefaultLanguagePlugins)();
77
+ this.languagePluginRegistry.registerMany(languagePlugins);
78
+ const pluginCodeExtensions = Array.from(new Set(this.languagePluginRegistry
79
+ .list()
80
+ .flatMap((plugin) => plugin.fileExtensions.map((ext) => ext.toLowerCase()))));
81
+ this.indexingOptions = {
82
+ codeExtensions: options.indexingOptions?.codeExtensions &&
83
+ options.indexingOptions.codeExtensions.length > 0
84
+ ? options.indexingOptions.codeExtensions.map((ext) => ext.toLowerCase())
85
+ : pluginCodeExtensions,
86
+ skipImportChunksInVectors: options.indexingOptions?.skipImportChunksInVectors ?? false,
87
+ };
88
+ this.architectureGenerator = new architecture_js_1.ArchitectureGenerator(this.metadata, this.languagePluginRegistry.list());
89
+ }
90
+ get metadataWithProgress() {
91
+ return this.metadata;
92
+ }
93
+ getConfiguredOllamaNumCtx() {
94
+ if (config_js_1.config.get("embeddingProvider") !== "ollama") {
95
+ return null;
96
+ }
97
+ const numCtx = config_js_1.config.get("ollamaNumCtx");
98
+ return Number.isFinite(numCtx) && numCtx > 0 ? Math.floor(numCtx) : null;
99
+ }
100
+ isOllamaContextLengthError(error) {
101
+ const message = error instanceof Error ? error.message : String(error ?? "");
102
+ const normalized = message.toLowerCase();
103
+ return (normalized.includes("input length exceeds the context length") ||
104
+ (normalized.includes("context length") &&
105
+ normalized.includes("status=400")));
106
+ }
107
+ trimToTokenBudget(content, tokenBudget) {
108
+ if (tokenBudget <= 0 || content.length === 0) {
109
+ return content;
110
+ }
111
+ let trimmed = content;
112
+ let estimatedTokens = this.tokenEstimator.estimate(trimmed);
113
+ if (estimatedTokens <= tokenBudget) {
114
+ return trimmed;
115
+ }
116
+ const initialRatio = Math.min(1, tokenBudget / Math.max(estimatedTokens, 1));
117
+ const initialLength = Math.max(32, Math.floor(trimmed.length * initialRatio * 0.95));
118
+ trimmed = trimmed.slice(0, initialLength);
119
+ estimatedTokens = this.tokenEstimator.estimate(trimmed);
120
+ while (estimatedTokens > tokenBudget && trimmed.length > 32) {
121
+ const nextLength = Math.max(32, Math.floor(trimmed.length * 0.85));
122
+ if (nextLength >= trimmed.length) {
123
+ break;
124
+ }
125
+ trimmed = trimmed.slice(0, nextLength);
126
+ estimatedTokens = this.tokenEstimator.estimate(trimmed);
127
+ }
128
+ return trimmed;
129
+ }
130
+ async embedWithContextGuard(contents, operation) {
131
+ try {
132
+ return await this.embedder.embed(contents);
133
+ }
134
+ catch (error) {
135
+ const ollamaNumCtx = this.getConfiguredOllamaNumCtx();
136
+ if (!ollamaNumCtx || !this.isOllamaContextLengthError(error)) {
137
+ throw error;
138
+ }
139
+ const retryWithBudget = async (tokenBudget, passName) => {
140
+ const sizeDetails = contents.map((content, index) => {
141
+ const originalTokens = this.tokenEstimator.estimate(content);
142
+ const trimmedContent = this.trimToTokenBudget(content, tokenBudget);
143
+ const trimmedTokens = this.tokenEstimator.estimate(trimmedContent);
144
+ return {
145
+ index,
146
+ content: trimmedContent,
147
+ originalChars: content.length,
148
+ originalBytes: Buffer.byteLength(content, "utf8"),
149
+ originalTokens,
150
+ trimmedChars: trimmedContent.length,
151
+ trimmedBytes: Buffer.byteLength(trimmedContent, "utf8"),
152
+ trimmedTokens,
153
+ };
154
+ });
155
+ logger.warn(`Embedding context overflow during ${operation}`, {
156
+ operation,
157
+ passName,
158
+ embeddingModel: config_js_1.config.get("embeddingModel"),
159
+ numCtx: ollamaNumCtx,
160
+ tokenBudget,
161
+ itemCount: sizeDetails.length,
162
+ trimmedCount: sizeDetails.filter((item) => item.trimmedChars < item.originalChars).length,
163
+ sizes: sizeDetails.map(({ content: _content, ...detail }) => detail),
164
+ });
165
+ return this.embedder.embed(sizeDetails.map((item) => item.content));
166
+ };
167
+ try {
168
+ return await retryWithBudget(Math.max(16, Math.floor(ollamaNumCtx * 0.9)), "first");
169
+ }
170
+ catch (retryError) {
171
+ if (!this.isOllamaContextLengthError(retryError)) {
172
+ throw retryError;
173
+ }
174
+ return retryWithBudget(Math.max(16, Math.floor(ollamaNumCtx * 0.75)), "second");
175
+ }
176
+ }
177
+ }
178
+ shouldIndexChunkInVectors(chunk) {
179
+ return (!this.indexingOptions.skipImportChunksInVectors ||
180
+ chunk.chunkType !== "imports");
181
+ }
182
+ normalizeChunkType(value, chunkContent, primarySymbol) {
183
+ if (typeof value === "string") {
184
+ const normalized = value.trim().toLowerCase();
185
+ if (normalized === "imports")
186
+ return "imports";
187
+ if (normalized === "types")
188
+ return "types";
189
+ if (normalized === "impl")
190
+ return "impl";
191
+ if (normalized === "preamble")
192
+ return "preamble";
193
+ if (normalized === "declaration")
194
+ return "declaration";
195
+ if (normalized === "module_section")
196
+ return "module_section";
197
+ if (normalized === "full_file")
198
+ return "full_file";
199
+ }
200
+ if (primarySymbol) {
201
+ return "impl";
202
+ }
203
+ const trimmed = chunkContent.trim();
204
+ if (!trimmed)
205
+ return "full_file";
206
+ const lines = trimmed
207
+ .split(/\r?\n/)
208
+ .map((line) => line.trim())
209
+ .filter(Boolean);
210
+ if (lines.length > 0 &&
211
+ lines.filter((line) => /^(import\b|from\s+\S+\s+import\b|using\s+\S+\s*;|export\b.+\bfrom\b|const\s+.+\s*=\s*require\()/i.test(line)).length /
212
+ lines.length >=
213
+ 0.8) {
214
+ return "imports";
215
+ }
216
+ if (/(^|\s)(interface|type|enum|protocol|trait|typedef|delegate)\b/i.test(trimmed)) {
217
+ return "types";
218
+ }
219
+ return "impl";
220
+ }
221
+ inferPrimarySymbol(chunk, symbolRecords) {
222
+ const explicitPrimary = typeof chunk.metadata?.primarySymbol === "string"
223
+ ? String(chunk.metadata.primarySymbol).trim()
224
+ : undefined;
225
+ if (explicitPrimary) {
226
+ return explicitPrimary;
227
+ }
228
+ const inChunk = symbolRecords.filter((symbol) => symbol.range.start.line >= chunk.range.startLine &&
229
+ symbol.range.start.line <= chunk.range.endLine);
230
+ if (inChunk.length === 0) {
231
+ return undefined;
232
+ }
233
+ const priority = new Map([
234
+ ["function", 5],
235
+ ["method", 5],
236
+ ["class", 4],
237
+ ["interface", 3],
238
+ ["type", 2],
239
+ ["variable", 1],
240
+ ]);
241
+ return inChunk.sort((a, b) => {
242
+ const aPriority = priority.get(a.kind) ?? 0;
243
+ const bPriority = priority.get(b.kind) ?? 0;
244
+ if (aPriority !== bPriority) {
245
+ return bPriority - aPriority;
246
+ }
247
+ return a.range.start.line - b.range.start.line;
248
+ })[0]?.name;
249
+ }
250
+ splitHeuristicChunks(content, languageId) {
251
+ const lines = content.split(/\r?\n/);
252
+ if (lines.length === 0) {
253
+ return [];
254
+ }
255
+ const isPython = languageId === "python";
256
+ const isCSharp = languageId === "csharp";
257
+ const isGDScript = languageId === "gdscript";
258
+ const isRuby = languageId === "ruby";
259
+ const isJSImport = languageId === "typescript" || languageId === "javascript";
260
+ if (!isPython && !isCSharp && !isGDScript && !isRuby && !isJSImport) {
261
+ return [];
262
+ }
263
+ const chunks = [];
264
+ const importPattern = isPython
265
+ ? /^(import\s+\S+|from\s+\S+\s+import\s+)/
266
+ : isCSharp
267
+ ? /^using\s+[^;]+;/
268
+ : isGDScript
269
+ ? /^(extends\s+\S+|class_name\s+\S+|const\s+\S+\s*=\s*preload\(|var\s+\S+\s*=\s*preload\()/
270
+ : isRuby
271
+ ? /^(require|require_relative|include|extend)\b/
272
+ : /^(import\s+|export\s+.+\s+from\s+|const\s+.+\s*=\s*require\()/;
273
+ let importEnd = 0;
274
+ for (let index = 0; index < lines.length; index += 1) {
275
+ const trimmed = lines[index].trim();
276
+ if (trimmed === "" ||
277
+ trimmed.startsWith("//") ||
278
+ trimmed.startsWith("#") ||
279
+ trimmed.startsWith("/*") ||
280
+ importPattern.test(trimmed)) {
281
+ if (importPattern.test(trimmed)) {
282
+ importEnd = index + 1;
283
+ }
284
+ continue;
285
+ }
286
+ break;
287
+ }
288
+ if (importEnd > 0) {
289
+ const importContent = lines.slice(0, importEnd).join("\n").trim();
290
+ if (importContent) {
291
+ chunks.push({
292
+ content: importContent,
293
+ startLine: 1,
294
+ endLine: importEnd,
295
+ chunkType: "imports",
296
+ });
297
+ }
298
+ }
299
+ const definitions = [];
300
+ const pythonDefPattern = /^(?:async\s+def|def|class)\s+([A-Za-z_][A-Za-z0-9_]*)/;
301
+ const csharpTypePattern = /\b(class|interface|enum|struct|record)\s+([A-Za-z_][A-Za-z0-9_]*)/;
302
+ const csharpMethodPattern = /\b(?:public|private|protected|internal|static|virtual|override|sealed|partial|async|extern|unsafe|abstract|new|readonly|ref|out|in)+\s+[A-Za-z_][A-Za-z0-9_<>,\[\]?]*\s+([A-Za-z_][A-Za-z0-9_]*)\s*\(/;
303
+ const gdClassPattern = /^(?:class_name|class)\s+([A-Za-z_][A-Za-z0-9_]*)/;
304
+ const gdFuncPattern = /^(?:static\s+)?func\s+([A-Za-z_][A-Za-z0-9_]*)\s*\(/;
305
+ const rubyTypePattern = /^(?:class|module)\s+([A-Z][A-Za-z0-9_:]*)/;
306
+ const rubyMethodPattern = /^def\s+(?:self\.)?([A-Za-z_][A-Za-z0-9_]*[!?=]?)/;
307
+ const jsDefPattern = /^(?:export\s+)?(?:async\s+)?(?:function|class|const|let|var)\s+([A-Za-z_][A-Za-z0-9_]*)/;
308
+ for (let index = importEnd; index < lines.length; index += 1) {
309
+ const line = lines[index].trim();
310
+ if (!line)
311
+ continue;
312
+ if (isPython) {
313
+ const match = line.match(pythonDefPattern);
314
+ if (match) {
315
+ definitions.push({
316
+ line: index + 1,
317
+ chunkType: /^class\b/.test(line) ? "types" : "impl",
318
+ primarySymbol: match[1],
319
+ });
320
+ }
321
+ continue;
322
+ }
323
+ if (isCSharp) {
324
+ const typeMatch = line.match(csharpTypePattern);
325
+ if (typeMatch) {
326
+ definitions.push({
327
+ line: index + 1,
328
+ chunkType: typeMatch[1] === "interface" || typeMatch[1] === "enum"
329
+ ? "types"
330
+ : "impl",
331
+ primarySymbol: typeMatch[2],
332
+ });
333
+ continue;
334
+ }
335
+ const methodMatch = line.match(csharpMethodPattern);
336
+ if (methodMatch) {
337
+ definitions.push({
338
+ line: index + 1,
339
+ chunkType: "impl",
340
+ primarySymbol: methodMatch[1],
341
+ });
342
+ }
343
+ continue;
344
+ }
345
+ if (isGDScript) {
346
+ const classMatch = line.match(gdClassPattern);
347
+ if (classMatch) {
348
+ definitions.push({
349
+ line: index + 1,
350
+ chunkType: "types",
351
+ primarySymbol: classMatch[1],
352
+ });
353
+ continue;
354
+ }
355
+ const funcMatch = line.match(gdFuncPattern);
356
+ if (funcMatch) {
357
+ definitions.push({
358
+ line: index + 1,
359
+ chunkType: "impl",
360
+ primarySymbol: funcMatch[1],
361
+ });
362
+ }
363
+ continue;
364
+ }
365
+ if (isRuby) {
366
+ const typeMatch = line.match(rubyTypePattern);
367
+ if (typeMatch) {
368
+ definitions.push({
369
+ line: index + 1,
370
+ chunkType: "types",
371
+ primarySymbol: typeMatch[1],
372
+ });
373
+ continue;
374
+ }
375
+ const methodMatch = line.match(rubyMethodPattern);
376
+ if (methodMatch) {
377
+ definitions.push({
378
+ line: index + 1,
379
+ chunkType: "impl",
380
+ primarySymbol: methodMatch[1],
381
+ });
382
+ }
383
+ continue;
384
+ }
385
+ const jsMatch = line.match(jsDefPattern);
386
+ if (jsMatch) {
387
+ definitions.push({
388
+ line: index + 1,
389
+ chunkType: /^.*\bclass\b/.test(line) ? "types" : "impl",
390
+ primarySymbol: jsMatch[1],
391
+ });
392
+ }
393
+ }
394
+ if (definitions.length === 0) {
395
+ const fallback = lines.slice(importEnd).join("\n").trim();
396
+ if (fallback) {
397
+ chunks.push({
398
+ content: fallback,
399
+ startLine: importEnd + 1,
400
+ endLine: lines.length,
401
+ chunkType: "impl",
402
+ });
403
+ }
404
+ return chunks;
405
+ }
406
+ for (let index = 0; index < definitions.length; index += 1) {
407
+ const current = definitions[index];
408
+ const next = definitions[index + 1];
409
+ const startLine = current.line;
410
+ const endLine = next ? Math.max(startLine, next.line - 1) : lines.length;
411
+ const chunkText = lines
412
+ .slice(startLine - 1, endLine)
413
+ .join("\n")
414
+ .trim();
415
+ if (!chunkText)
416
+ continue;
417
+ chunks.push({
418
+ content: chunkText,
419
+ startLine,
420
+ endLine,
421
+ chunkType: current.chunkType,
422
+ primarySymbol: current.primarySymbol,
423
+ });
424
+ }
425
+ return chunks;
426
+ }
427
+ deriveLanguageChunks(languagePlugin, parsed, languageId, filePath, content, symbolRecords) {
428
+ if (languagePlugin && parsed) {
429
+ const pluginChunks = languagePlugin.splitIntoChunks(parsed, {
430
+ targetTokens: 280,
431
+ maxTokens: 560,
432
+ });
433
+ if (pluginChunks.length > 0) {
434
+ return pluginChunks.map((chunk) => {
435
+ const primarySymbol = this.inferPrimarySymbol(chunk, symbolRecords);
436
+ return {
437
+ content: chunk.content,
438
+ startLine: chunk.range.startLine,
439
+ endLine: chunk.range.endLine,
440
+ chunkType: this.normalizeChunkType(chunk.metadata?.chunkType, chunk.content, primarySymbol),
441
+ primarySymbol,
442
+ };
443
+ });
444
+ }
445
+ }
446
+ const heuristicChunks = this.splitHeuristicChunks(content, languageId);
447
+ if (heuristicChunks.length > 0) {
448
+ return heuristicChunks;
449
+ }
450
+ return this.chunker
451
+ .chunk({ filePath, content, language: languageId })
452
+ .map((chunk) => ({
453
+ content: chunk.content,
454
+ startLine: chunk.startLine,
455
+ endLine: chunk.endLine,
456
+ chunkType: this.normalizeChunkType(chunk.type, chunk.content, chunk.primarySymbol),
457
+ primarySymbol: chunk.primarySymbol,
458
+ }));
459
+ }
460
+ async initialize() {
461
+ await Promise.all([
462
+ this.metadata.initialize(),
463
+ this.vectors.initialize(),
464
+ this.embedder.initialize(),
465
+ ]);
466
+ }
467
+ async close() {
468
+ await Promise.all([
469
+ this.metadata.close(),
470
+ this.vectors.close(),
471
+ this.embedder.close(),
472
+ ]);
473
+ }
474
+ async indexProject(options) {
475
+ const projectId = options.projectId ?? this.projectId;
476
+ const repoRoot = options.repoRoot ?? this.repoRoot;
477
+ const gitRef = options.gitRef ?? (await this.git.getHeadCommit(repoRoot)) ?? "unknown";
478
+ const errors = [];
479
+ await this.loadChurnByFile(repoRoot);
480
+ const latestSnapshot = await this.metadata.getLatestCompletedSnapshot(projectId);
481
+ const shouldDoFullReindex = options.isFullReindex ||
482
+ !latestSnapshot ||
483
+ !options.changedFiles ||
484
+ options.changedFiles.deleted.length +
485
+ options.changedFiles.modified.length +
486
+ options.changedFiles.added.length >
487
+ 20000;
488
+ if (shouldDoFullReindex) {
489
+ return this.performFullReindex(projectId, gitRef, repoRoot, options.onProgress);
490
+ }
491
+ if (!latestSnapshot || !options.changedFiles) {
492
+ throw new Error("Latest snapshot not found for incremental indexing");
493
+ }
494
+ const snapshot = await this.createSnapshot(projectId, gitRef, "indexing");
495
+ const snapshotId = snapshot.id;
496
+ try {
497
+ await this.prepareIncrementalSnapshot({
498
+ projectId,
499
+ prevSnapshotId: latestSnapshot.id,
500
+ newSnapshotId: snapshotId,
501
+ diff: options.changedFiles,
502
+ });
503
+ const filesToIndex = [
504
+ ...options.changedFiles.modified,
505
+ ...options.changedFiles.added,
506
+ ].filter((filePath) => this.indexingOptions.codeExtensions.includes((0, node_path_1.extname)(filePath).toLowerCase()));
507
+ const totalFiles = (await this.metadata.listFiles(projectId, snapshotId))
508
+ .length;
509
+ const knownFiles = new Set((await this.metadata.listFiles(projectId, snapshotId)).map((file) => this.normalizePath(file.path)));
510
+ if (filesToIndex.length === 0) {
511
+ await this.metadata.updateSnapshotProgress(snapshotId, totalFiles, totalFiles);
512
+ await this.architectureGenerator.generate(projectId, snapshotId);
513
+ await this.metadata.updateSnapshotStatus(snapshotId, "completed");
514
+ await this.pruneHistoricalSnapshots(projectId, snapshotId);
515
+ return { snapshotId, filesIndexed: totalFiles, errors: [] };
516
+ }
517
+ await this.indexPreparedFiles({
518
+ projectId,
519
+ repoRoot,
520
+ gitRef,
521
+ snapshotId,
522
+ filesToIndex,
523
+ knownFiles,
524
+ totalFiles,
525
+ onProgress: options.onProgress,
526
+ errors,
527
+ operation: "incremental batch indexing",
528
+ });
529
+ await this.architectureGenerator.generate(projectId, snapshotId);
530
+ if (errors.length > 0) {
531
+ const message = `Incremental indexing completed with ${errors.length} preparation error${errors.length === 1 ? "" : "s"}`;
532
+ await this.metadata.updateSnapshotStatus(snapshotId, "failed", message);
533
+ throw new Error(message);
534
+ }
535
+ await this.metadata.updateSnapshotStatus(snapshotId, "completed");
536
+ await this.metadataWithProgress.updateSnapshotProgress(snapshotId, totalFiles, totalFiles);
537
+ await this.pruneHistoricalSnapshots(projectId, snapshotId);
538
+ return { snapshotId, filesIndexed: filesToIndex.length, errors };
539
+ }
540
+ catch (error) {
541
+ await this.metadata.updateSnapshotStatus(snapshotId, "failed", error instanceof Error ? error.message : String(error));
542
+ throw error;
543
+ }
544
+ }
545
+ async indexFile(options) {
546
+ const data = await this.prepareFileRecords(options);
547
+ const vectorChunks = data.chunkRecords.filter((chunk) => this.shouldIndexChunkInVectors(chunk));
548
+ await Promise.all([
549
+ this.metadata.upsertFile(options.projectId, data.fileRecord),
550
+ this.metadata.replaceChunks(options.projectId, options.snapshotId, options.filePath, data.chunkRecords),
551
+ this.metadata.replaceSymbols(options.projectId, options.snapshotId, options.filePath, data.symbolRecords),
552
+ this.metadata.replaceDependencies(options.projectId, options.snapshotId, options.filePath, data.dependencyRecords),
553
+ this.metadata.upsertFileMetrics(options.projectId, {
554
+ snapshotId: options.snapshotId,
555
+ filePath: options.filePath,
556
+ metrics: data.metrics,
557
+ }),
558
+ (async () => {
559
+ if (vectorChunks.length === 0) {
560
+ return;
561
+ }
562
+ const embeddings = await this.embedWithContextGuard(vectorChunks.map((chunk) => data.chunksContent.get(chunk.chunkId) || ""), "single-file indexing");
563
+ await this.vectors.upsert(vectorChunks.map((chunk, index) => ({
564
+ projectId: options.projectId,
565
+ chunkId: chunk.chunkId,
566
+ snapshotId: options.snapshotId,
567
+ filePath: options.filePath,
568
+ startLine: chunk.startLine,
569
+ endLine: chunk.endLine,
570
+ embedding: embeddings[index],
571
+ contentHash: chunk.contentHash,
572
+ chunkType: chunk.chunkType,
573
+ primarySymbol: chunk.primarySymbol,
574
+ })));
575
+ })(),
576
+ ]);
577
+ }
578
+ async indexPreparedFiles(options) {
579
+ const batchSize = this.getBatchSize();
580
+ let processedCount = 0;
581
+ await this.metadataWithProgress.updateSnapshotProgress(options.snapshotId, 0, options.totalFiles);
582
+ await this.metadata.updateSnapshotProgress(options.snapshotId, 0, options.totalFiles);
583
+ for (let index = 0; index < options.filesToIndex.length; index += batchSize) {
584
+ const batch = options.filesToIndex.slice(index, index + batchSize);
585
+ const preparedData = await Promise.all(batch.map(async (filePath) => {
586
+ try {
587
+ const content = await (0, promises_1.readFile)((0, node_path_1.join)(options.repoRoot, filePath), "utf8");
588
+ return this.prepareFileRecords({
589
+ snapshotId: options.snapshotId,
590
+ projectId: options.projectId,
591
+ filePath,
592
+ content,
593
+ gitRef: options.gitRef,
594
+ knownFiles: options.knownFiles,
595
+ });
596
+ }
597
+ catch (error) {
598
+ const message = error instanceof Error ? error.message : String(error);
599
+ logger.error(`Error preparing file ${filePath}`, { message });
600
+ options.errors.push(`Failed to prepare ${filePath}: ${message}`);
601
+ return null;
602
+ }
603
+ }));
604
+ const validData = preparedData.filter((value) => value !== null);
605
+ if (validData.length > 0) {
606
+ await this.metadata.transaction(async () => {
607
+ for (const data of validData) {
608
+ await this.metadata.upsertFile(options.projectId, data.fileRecord);
609
+ await this.metadata.replaceChunks(options.projectId, options.snapshotId, data.filePath, data.chunkRecords);
610
+ await this.metadata.replaceSymbols(options.projectId, options.snapshotId, data.filePath, data.symbolRecords);
611
+ await this.metadata.replaceDependencies(options.projectId, options.snapshotId, data.filePath, data.dependencyRecords);
612
+ await this.metadata.upsertFileMetrics(options.projectId, {
613
+ snapshotId: options.snapshotId,
614
+ filePath: data.filePath,
615
+ metrics: data.metrics,
616
+ });
617
+ }
618
+ });
619
+ const vectorChunksWithContext = validData.flatMap((data) => data.chunkRecords
620
+ .filter((chunk) => this.shouldIndexChunkInVectors(chunk))
621
+ .map((chunk) => ({
622
+ chunk,
623
+ filePath: data.filePath,
624
+ content: data.chunksContent.get(chunk.chunkId) || "",
625
+ })));
626
+ if (vectorChunksWithContext.length > 0) {
627
+ const embeddings = await this.embedWithContextGuard(vectorChunksWithContext.map((item) => item.content), options.operation);
628
+ await this.vectors.upsert(vectorChunksWithContext.map((item, index) => ({
629
+ projectId: this.projectId,
630
+ chunkId: item.chunk.chunkId,
631
+ snapshotId: options.snapshotId,
632
+ filePath: item.filePath,
633
+ startLine: item.chunk.startLine,
634
+ endLine: item.chunk.endLine,
635
+ embedding: embeddings[index],
636
+ contentHash: item.chunk.contentHash,
637
+ chunkType: item.chunk.chunkType,
638
+ primarySymbol: item.chunk.primarySymbol,
639
+ })));
640
+ }
641
+ }
642
+ processedCount += batch.length;
643
+ options.onProgress?.(Math.min(processedCount, options.totalFiles), options.totalFiles);
644
+ if (processedCount % 100 === 0 || processedCount >= options.totalFiles) {
645
+ await this.metadataWithProgress.updateSnapshotProgress(options.snapshotId, processedCount, options.totalFiles);
646
+ }
647
+ }
648
+ }
649
+ getLanguagePlugin(filePath) {
650
+ return this.languagePluginRegistry.findByFilePath(filePath);
651
+ }
652
+ getLanguageIdFromPath(filePath) {
653
+ const ext = (0, node_path_1.extname)(filePath).toLowerCase();
654
+ switch (ext) {
655
+ case ".ts":
656
+ case ".tsx":
657
+ case ".mts":
658
+ case ".cts":
659
+ case ".js":
660
+ case ".jsx":
661
+ case ".mjs":
662
+ case ".cjs":
663
+ return "typescript";
664
+ case ".py":
665
+ case ".pyi":
666
+ return "python";
667
+ case ".cs":
668
+ return "csharp";
669
+ case ".gd":
670
+ return "gdscript";
671
+ case ".rb":
672
+ return "ruby";
673
+ default:
674
+ return "plaintext";
675
+ }
676
+ }
677
+ normalizePath(filePath) {
678
+ return filePath.replace(/\\/g, "/");
679
+ }
680
+ async loadChurnByFile(repoRoot) {
681
+ try {
682
+ const churn = await this.git.getChurnByFile(repoRoot, { sinceDays: 30 });
683
+ this.churnByFile = new Map(Object.entries(churn).map(([filePath, count]) => {
684
+ const normalized = this.normalizePath(filePath);
685
+ return [
686
+ normalized.startsWith("./") ? normalized.slice(2) : normalized,
687
+ count,
688
+ ];
689
+ }));
690
+ }
691
+ catch (error) {
692
+ logger.warn("Failed to load churn data", {
693
+ message: error instanceof Error ? error.message : String(error),
694
+ });
695
+ this.churnByFile = new Map();
696
+ }
697
+ }
698
+ async scanFiles(rootPath) {
699
+ return (0, scanner_js_1.scanProjectFiles)(rootPath, this.indexingOptions.codeExtensions);
700
+ }
701
+ async prepareFileRecords(options) {
702
+ const { snapshotId, filePath, content, knownFiles } = options;
703
+ const languagePlugin = this.getLanguagePlugin(filePath);
704
+ let languageId = this.getLanguageIdFromPath(filePath);
705
+ let symbolRecords = [];
706
+ let dependencyRecords = [];
707
+ let parsed;
708
+ if (languagePlugin) {
709
+ parsed = languagePlugin.parse({
710
+ path: filePath,
711
+ content,
712
+ languageHint: languagePlugin.id,
713
+ projectRoot: this.repoRoot,
714
+ });
715
+ languageId = parsed.languageId;
716
+ const symbols = languagePlugin.extractSymbols(parsed);
717
+ symbolRecords = symbols.map((symbol) => ({
718
+ snapshotId,
719
+ id: symbol.id,
720
+ filePath,
721
+ kind: symbol.kind,
722
+ name: symbol.name,
723
+ containerName: symbol.containerName,
724
+ exported: symbol.exported,
725
+ range: {
726
+ start: {
727
+ line: symbol.range.startLine,
728
+ character: symbol.range.startCol,
729
+ },
730
+ end: { line: symbol.range.endLine, character: symbol.range.endCol },
731
+ },
732
+ signature: symbol.signature,
733
+ docComment: symbol.docComment,
734
+ metadata: symbol.metadata,
735
+ }));
736
+ const imports = languagePlugin.extractImports(parsed);
737
+ dependencyRecords = imports.map((dependency) => ({
738
+ ...(0, dependency_resolver_js_1.resolveDependency)(dependency.spec, filePath, knownFiles),
739
+ snapshotId,
740
+ id: dependency.id,
741
+ fromPath: filePath,
742
+ toSpecifier: dependency.spec,
743
+ kind: normalizeImportKind(dependency.kind),
744
+ }));
745
+ }
746
+ const chunks = this.deriveLanguageChunks(languagePlugin, parsed, languageId, filePath, content, symbolRecords);
747
+ const chunkRecords = [];
748
+ const chunksContent = new Map();
749
+ for (const chunk of chunks) {
750
+ const chunkId = (0, node_crypto_1.randomUUID)();
751
+ const chunkHash = (0, hash_js_1.computeHash)(chunk.content);
752
+ chunkRecords.push({
753
+ snapshotId,
754
+ chunkId,
755
+ filePath,
756
+ startLine: chunk.startLine,
757
+ endLine: chunk.endLine,
758
+ contentHash: chunkHash,
759
+ tokenEstimate: this.tokenEstimator.estimate(chunk.content),
760
+ chunkType: chunk.chunkType,
761
+ primarySymbol: chunk.primarySymbol,
762
+ hasOverlap: false,
763
+ });
764
+ chunksContent.set(chunkId, chunk.content);
765
+ }
766
+ const churn = this.churnByFile.get(this.normalizePath(filePath)) ?? 0;
767
+ return {
768
+ filePath,
769
+ content,
770
+ fileRecord: {
771
+ snapshotId,
772
+ path: filePath,
773
+ sha256: (0, hash_js_1.computeHash)(content),
774
+ mtimeMs: Date.now(),
775
+ size: content.length,
776
+ languageId,
777
+ },
778
+ chunkRecords,
779
+ chunksContent,
780
+ symbolRecords,
781
+ dependencyRecords,
782
+ metrics: {
783
+ complexity: 0,
784
+ maintainability: 100,
785
+ churn,
786
+ testCoverage: undefined,
787
+ },
788
+ };
789
+ }
790
+ async createSnapshot(projectId, gitRef, status) {
791
+ const snapshot = await this.metadata.createSnapshot(projectId, {
792
+ headCommit: gitRef,
793
+ indexedAt: Date.now(),
794
+ });
795
+ await this.metadata.updateSnapshotStatus(snapshot.id, status);
796
+ return { id: snapshot.id };
797
+ }
798
+ async prepareIncrementalSnapshot(options) {
799
+ const prevFiles = await this.metadata.listFiles(options.projectId, options.prevSnapshotId);
800
+ const modifiedSet = new Set(options.diff.modified);
801
+ const deletedSet = new Set(options.diff.deleted);
802
+ const unchangedFiles = prevFiles
803
+ .filter((file) => !modifiedSet.has(file.path) && !deletedSet.has(file.path))
804
+ .map((file) => file.path);
805
+ if (unchangedFiles.length === 0) {
806
+ return;
807
+ }
808
+ await this.metadata.copyUnchangedFileData(options.projectId, options.prevSnapshotId, options.newSnapshotId, unchangedFiles);
809
+ await this.vectors.copyVectors(options.projectId, options.prevSnapshotId, options.newSnapshotId, [
810
+ ...new Set([
811
+ ...options.diff.modified,
812
+ ...options.diff.deleted,
813
+ ...options.diff.added,
814
+ ]),
815
+ ]);
816
+ }
817
+ isTransientVectorDeleteError(error) {
818
+ const message = error instanceof Error ? error.message : String(error);
819
+ return ((message.includes("LanceError(IO)") &&
820
+ (message.includes("Not found:") ||
821
+ message.includes("Did not find any data files") ||
822
+ message.includes("/vectors.lance/data/"))) ||
823
+ message.includes("Commit conflict for version"));
824
+ }
825
+ async deleteProjectVectorsWithRetry(projectId) {
826
+ const delays = [0, 300, 1200];
827
+ for (let attempt = 0; attempt < delays.length; attempt += 1) {
828
+ if (delays[attempt] > 0) {
829
+ await new Promise((resolve) => setTimeout(resolve, delays[attempt]));
830
+ }
831
+ try {
832
+ await this.vectors.deleteByProject(projectId);
833
+ return;
834
+ }
835
+ catch (error) {
836
+ if (!this.isTransientVectorDeleteError(error) ||
837
+ attempt === delays.length - 1) {
838
+ throw error;
839
+ }
840
+ }
841
+ }
842
+ }
843
+ async deleteSnapshotVectorsWithRetry(projectId, snapshotId) {
844
+ const delays = [0, 300, 1200];
845
+ for (let attempt = 0; attempt < delays.length; attempt += 1) {
846
+ if (delays[attempt] > 0) {
847
+ await new Promise((resolve) => setTimeout(resolve, delays[attempt]));
848
+ }
849
+ try {
850
+ await this.vectors.deleteBySnapshot(projectId, snapshotId);
851
+ return;
852
+ }
853
+ catch (error) {
854
+ if (!this.isTransientVectorDeleteError(error) ||
855
+ attempt === delays.length - 1) {
856
+ throw error;
857
+ }
858
+ }
859
+ }
860
+ }
861
+ async pruneHistoricalSnapshots(projectId, keepSnapshotId) {
862
+ const staleSnapshotIds = await this.listStaleSnapshotIds(projectId, keepSnapshotId);
863
+ if (staleSnapshotIds.length === 0) {
864
+ return;
865
+ }
866
+ for (const snapshotId of staleSnapshotIds) {
867
+ await this.deleteSnapshotVectorsWithRetry(projectId, snapshotId);
868
+ }
869
+ await this.metadata.clearProjectMetadata(projectId, keepSnapshotId, {
870
+ preserveActiveIndexing: true,
871
+ });
872
+ }
873
+ async listStaleSnapshotIds(projectId, keepSnapshotId) {
874
+ const staleSnapshotIds = [];
875
+ const pageSize = 100;
876
+ for (let offset = 0;; offset += pageSize) {
877
+ const snapshots = await this.metadata.listSnapshots(projectId, {
878
+ limit: pageSize,
879
+ offset,
880
+ });
881
+ for (const snapshot of snapshots) {
882
+ if (snapshot.id !== keepSnapshotId) {
883
+ staleSnapshotIds.push(snapshot.id);
884
+ }
885
+ }
886
+ if (snapshots.length < pageSize) {
887
+ return staleSnapshotIds;
888
+ }
889
+ }
890
+ }
891
+ async performFullReindex(projectId, gitRef, repoRoot, onProgress) {
892
+ const snapshot = await this.createSnapshot(projectId, gitRef, "indexing");
893
+ const snapshotId = snapshot.id;
894
+ const errors = [];
895
+ try {
896
+ await this.metadata.clearProjectMetadata(projectId, snapshotId);
897
+ await this.deleteProjectVectorsWithRetry(projectId);
898
+ const filesToIndex = await this.scanFiles(repoRoot);
899
+ if (filesToIndex.length === 0) {
900
+ await this.metadata.updateSnapshotProgress(snapshotId, 0, 0);
901
+ await this.architectureGenerator.generate(projectId, snapshotId);
902
+ await this.metadata.updateSnapshotStatus(snapshotId, "completed");
903
+ return { snapshotId, filesIndexed: 0, errors: [] };
904
+ }
905
+ await this.indexPreparedFiles({
906
+ projectId,
907
+ repoRoot,
908
+ gitRef,
909
+ snapshotId,
910
+ filesToIndex,
911
+ knownFiles: new Set(filesToIndex.map((filePath) => this.normalizePath(filePath))),
912
+ totalFiles: filesToIndex.length,
913
+ onProgress,
914
+ errors,
915
+ operation: "full reindex batch indexing",
916
+ });
917
+ await this.architectureGenerator.generate(projectId, snapshotId);
918
+ await this.metadata.updateSnapshotStatus(snapshotId, "completed");
919
+ await this.metadataWithProgress.updateSnapshotProgress(snapshotId, filesToIndex.length, filesToIndex.length);
920
+ return { snapshotId, filesIndexed: filesToIndex.length, errors };
921
+ }
922
+ catch (error) {
923
+ await this.metadata.updateSnapshotStatus(snapshotId, "failed", error instanceof Error ? error.message : String(error));
924
+ throw error;
925
+ }
926
+ }
927
+ getBatchSize() {
928
+ const value = config_js_1.config.get("indexBatchSize");
929
+ return Number.isFinite(value) && value > 0 ? value : 50;
930
+ }
931
+ }
932
+ exports.IndexerEngine = IndexerEngine;
933
+ //# sourceMappingURL=indexer.js.map