ultracode 5.4.0 → 5.6.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 (151) hide show
  1. package/dist/chunks/analysis-tool-handlers-GH5FDEWW.js +817 -0
  2. package/dist/chunks/analysis-tool-handlers-IXP4MWZX.js +817 -0
  3. package/dist/chunks/analysis-tool-handlers-LC2BTQYK.js +13 -0
  4. package/dist/chunks/analysis-tool-handlers-QYFKQPFL.js +817 -0
  5. package/dist/chunks/autodoc-tool-handlers-2HF6ERYN.js +1112 -0
  6. package/dist/chunks/autodoc-tool-handlers-4OGQJ7C3.js +1112 -0
  7. package/dist/chunks/autodoc-tool-handlers-N736CB56.js +138 -0
  8. package/dist/chunks/autodoc-tool-handlers-NQYBY6U4.js +1112 -0
  9. package/dist/chunks/branch-tool-handlers-KW3H4FJK.js +276 -0
  10. package/dist/chunks/branch-tool-handlers-QOUDZKJ2.js +276 -0
  11. package/dist/chunks/branch-tool-handlers-RB2U36KI.js +2 -0
  12. package/dist/chunks/branch-tool-handlers-ZHJM6PDK.js +276 -0
  13. package/dist/chunks/chunk-2Z6OQPYC.js +656 -0
  14. package/dist/chunks/chunk-3MQ7LRPN.js +322 -0
  15. package/dist/chunks/chunk-4W6QYGXZ.js +10 -0
  16. package/dist/chunks/chunk-533NFGUG.js +1 -0
  17. package/dist/chunks/chunk-5NUPOPWM.js +1 -0
  18. package/dist/chunks/chunk-AK4HIPA2.js +322 -0
  19. package/dist/chunks/chunk-B3H5NS3I.js +656 -0
  20. package/dist/chunks/chunk-DPTZHDST.js +4 -0
  21. package/dist/chunks/chunk-E5HQWLU5.js +322 -0
  22. package/dist/chunks/chunk-EOH25B5P.js +572 -0
  23. package/dist/chunks/chunk-ESV6F6E3.js +3179 -0
  24. package/dist/chunks/chunk-FPELPFER.js +924 -0
  25. package/dist/chunks/chunk-G6J42I55.js +161 -0
  26. package/dist/chunks/chunk-GCQE7ZYW.js +1 -0
  27. package/dist/chunks/chunk-GTIF6MOX.js +1 -0
  28. package/dist/chunks/chunk-I6STSSAK.js +2 -0
  29. package/dist/chunks/chunk-J2WBGTK2.js +4697 -0
  30. package/dist/chunks/chunk-KAYOX5EB.js +4697 -0
  31. package/dist/chunks/chunk-KPMTACOT.js +656 -0
  32. package/dist/chunks/chunk-L376GZ44.js +3179 -0
  33. package/dist/chunks/chunk-LCTOTHDA.js +15 -0
  34. package/dist/chunks/chunk-LEDJ7GVQ.js +316 -0
  35. package/dist/chunks/chunk-LH4OUKNZ.js +277 -0
  36. package/dist/chunks/chunk-O6IE2MEZ.js +161 -0
  37. package/dist/chunks/chunk-OEXPCY3F.js +316 -0
  38. package/dist/chunks/chunk-OMXOLFDN.js +924 -0
  39. package/dist/chunks/chunk-PLPBXWOU.js +3179 -0
  40. package/dist/chunks/chunk-PWLE5DN2.js +572 -0
  41. package/dist/chunks/chunk-PY43JPWL.js +447 -0
  42. package/dist/chunks/chunk-Q3B4EB7A.js +15 -0
  43. package/dist/chunks/chunk-Q5LPVLXA.js +337 -0
  44. package/dist/chunks/chunk-QIRZHZK2.js +5 -0
  45. package/dist/chunks/chunk-ROQ27LSL.js +924 -0
  46. package/dist/chunks/chunk-S5Q7BD6J.js +572 -0
  47. package/dist/chunks/chunk-SAMX3HJQ.js +337 -0
  48. package/dist/chunks/chunk-SV3WKUNV.js +1 -0
  49. package/dist/chunks/chunk-TCHCDCDO.js +167 -0
  50. package/dist/chunks/chunk-TR3HS7U6.js +316 -0
  51. package/dist/chunks/chunk-TUWE6FCW.js +167 -0
  52. package/dist/chunks/chunk-TVOTA7EE.js +277 -0
  53. package/dist/chunks/chunk-VS44D772.js +337 -0
  54. package/dist/chunks/chunk-WIE3G5ES.js +167 -0
  55. package/dist/chunks/chunk-XG3ACLWR.js +5 -0
  56. package/dist/chunks/chunk-XJ2Z5QQO.js +1 -0
  57. package/dist/chunks/chunk-XK2NY7RB.js +277 -0
  58. package/dist/chunks/chunk-Y4F7NZFZ.js +4700 -0
  59. package/dist/chunks/chunk-YS75L3ZS.js +161 -0
  60. package/dist/chunks/chunk-ZVG5HHI3.js +15 -0
  61. package/dist/chunks/dev-agent-DDDIVWOF.js +1 -0
  62. package/dist/chunks/dev-agent-E2VCFKXN.js +1624 -0
  63. package/dist/chunks/dev-agent-KJNSU5KQ.js +1624 -0
  64. package/dist/chunks/dev-agent-NDERYIPV.js +1624 -0
  65. package/dist/chunks/faiss-provider-7R4BQDIV.js +12 -0
  66. package/dist/chunks/faiss-provider-7ZFRSDN5.js +12 -0
  67. package/dist/chunks/faiss-provider-SXB7FTLB.js +1 -0
  68. package/dist/chunks/faiss-provider-TKLBEUSH.js +12 -0
  69. package/dist/chunks/file-tool-handlers-5DODQXGF.js +1027 -0
  70. package/dist/chunks/file-tool-handlers-KGHLE4KR.js +1027 -0
  71. package/dist/chunks/file-tool-handlers-KTOQ4NFS.js +12 -0
  72. package/dist/chunks/file-tool-handlers-V4SFUDQB.js +1027 -0
  73. package/dist/chunks/graph-metrics-tool-handlers-3AV4X4ZY.js +65 -0
  74. package/dist/chunks/graph-metrics-tool-handlers-3VMDQHJ6.js +65 -0
  75. package/dist/chunks/graph-metrics-tool-handlers-BZ6E6YHF.js +1 -0
  76. package/dist/chunks/graph-metrics-tool-handlers-IYBGSXL7.js +65 -0
  77. package/dist/chunks/graph-storage-factory-2CQ2RPDV.js +13 -0
  78. package/dist/chunks/graph-storage-factory-C5SMMYL6.js +13 -0
  79. package/dist/chunks/graph-storage-factory-EEO2V3GJ.js +1 -0
  80. package/dist/chunks/graph-storage-factory-WBCTXP34.js +13 -0
  81. package/dist/chunks/history-tool-handlers-AS7OQFZI.js +1 -0
  82. package/dist/chunks/history-tool-handlers-FSNJYXV2.js +208 -0
  83. package/dist/chunks/history-tool-handlers-JZAH4EIQ.js +208 -0
  84. package/dist/chunks/history-tool-handlers-KCSCXZ7T.js +208 -0
  85. package/dist/chunks/incremental-updater-A2EL4QXU.js +14 -0
  86. package/dist/chunks/incremental-updater-EQIKBVY2.js +14 -0
  87. package/dist/chunks/incremental-updater-JFGRPH3B.js +14 -0
  88. package/dist/chunks/incremental-updater-S5BAAGHP.js +1 -0
  89. package/dist/chunks/indexer-agent-ASKY7JPG.js +1 -0
  90. package/dist/chunks/indexer-agent-NKAOF323.js +21 -0
  91. package/dist/chunks/indexer-agent-PJN5IOKQ.js +21 -0
  92. package/dist/chunks/indexer-agent-WRJFWKZX.js +21 -0
  93. package/dist/chunks/indexing-pipeline-D4P2O72Z.js +249 -0
  94. package/dist/chunks/indexing-pipeline-L7C543N4.js +1 -0
  95. package/dist/chunks/indexing-pipeline-NHPRN3AB.js +249 -0
  96. package/dist/chunks/indexing-pipeline-ZAXCZU22.js +249 -0
  97. package/dist/chunks/layered-faiss-provider-62CNW54X.js +1 -0
  98. package/dist/chunks/layered-faiss-provider-O7L77GFX.js +12 -0
  99. package/dist/chunks/layered-faiss-provider-RVHLHLPK.js +12 -0
  100. package/dist/chunks/layered-faiss-provider-YT7EDIJI.js +12 -0
  101. package/dist/chunks/merge-agent-3RF7VFF5.js +2481 -0
  102. package/dist/chunks/merge-agent-JCKTCBCE.js +2481 -0
  103. package/dist/chunks/merge-agent-VCL7OXPN.js +2481 -0
  104. package/dist/chunks/merge-agent-ZGK24WVF.js +11 -0
  105. package/dist/chunks/merge-tool-handlers-GV2LOIKU.js +277 -0
  106. package/dist/chunks/merge-tool-handlers-TYDWU5X2.js +277 -0
  107. package/dist/chunks/merge-tool-handlers-U7X2ZO2M.js +1 -0
  108. package/dist/chunks/merge-tool-handlers-YH62ZLPJ.js +277 -0
  109. package/dist/chunks/pattern-tool-handlers-76NF5JDS.js +13 -0
  110. package/dist/chunks/pattern-tool-handlers-IJAGEIVD.js +1549 -0
  111. package/dist/chunks/pattern-tool-handlers-VA5WYA62.js +1549 -0
  112. package/dist/chunks/pattern-tool-handlers-WQ6UBMJS.js +1549 -0
  113. package/dist/chunks/query-agent-36ADGCFZ.js +1 -0
  114. package/dist/chunks/query-agent-H22CR5N5.js +191 -0
  115. package/dist/chunks/query-agent-K2UGZS4M.js +191 -0
  116. package/dist/chunks/query-agent-YJCEHOXD.js +191 -0
  117. package/dist/chunks/semantic-agent-AC7CBEDE.js +6381 -0
  118. package/dist/chunks/semantic-agent-HK5X6CKU.js +6381 -0
  119. package/dist/chunks/semantic-agent-KONIKEGW.js +6381 -0
  120. package/dist/chunks/semantic-agent-LH6IZ2L7.js +137 -0
  121. package/dist/chunks/semantic-tool-handlers-5LMSH2U7.js +3 -0
  122. package/dist/chunks/semantic-tool-handlers-735UMO7Y.js +817 -0
  123. package/dist/chunks/semantic-tool-handlers-BNUYPP7X.js +817 -0
  124. package/dist/chunks/semantic-tool-handlers-MYZPEUD2.js +817 -0
  125. package/dist/chunks/snapshot-tool-handlers-6SIHZT2F.js +201 -0
  126. package/dist/chunks/snapshot-tool-handlers-DS4P3KOT.js +201 -0
  127. package/dist/chunks/snapshot-tool-handlers-JYHRFPC7.js +201 -0
  128. package/dist/chunks/snapshot-tool-handlers-YEHMAT3L.js +1 -0
  129. package/dist/chunks/storage-paths-A3C7WHHG.js +8 -0
  130. package/dist/chunks/storage-paths-HDYH7WPM.js +1 -0
  131. package/dist/chunks/storage-paths-IMFRHBWF.js +8 -0
  132. package/dist/chunks/storage-paths-P3PUSMUD.js +8 -0
  133. package/dist/chunks/taint-tool-handlers-CWESOOMQ.js +68 -0
  134. package/dist/chunks/taint-tool-handlers-OG3NVVP3.js +1 -0
  135. package/dist/chunks/taint-tool-handlers-ON3G3FA7.js +68 -0
  136. package/dist/chunks/taint-tool-handlers-P4P5J6DB.js +68 -0
  137. package/dist/chunks/tracing-tool-handlers-4BDCXTZZ.js +3935 -0
  138. package/dist/chunks/tracing-tool-handlers-6FPNM7HX.js +3935 -0
  139. package/dist/chunks/tracing-tool-handlers-LQTQ5SKK.js +89 -0
  140. package/dist/chunks/tracing-tool-handlers-XRQX2DTS.js +3935 -0
  141. package/dist/chunks/validation-tool-handlers-DZUG7KYY.js +2 -0
  142. package/dist/chunks/validation-tool-handlers-O6TGFSH5.js +555 -0
  143. package/dist/chunks/validation-tool-handlers-RREUYKIR.js +555 -0
  144. package/dist/chunks/validation-tool-handlers-XPWSMS37.js +555 -0
  145. package/dist/index.js +13 -13
  146. package/dist/roslyn-addon/.build-hash +1 -1
  147. package/dist/roslyn-addon/ILGPU.Algorithms.dll +0 -0
  148. package/dist/roslyn-addon/ILGPU.dll +0 -0
  149. package/dist/roslyn-addon/UltraCode.CSharp.deps.json +35 -0
  150. package/dist/roslyn-addon/UltraCode.CSharp.dll +0 -0
  151. package/package.json +1 -1
@@ -0,0 +1,572 @@
1
+ import { getGpuClient } from './chunk-ROQ27LSL.js';
2
+ import { simdL2Normalize } from './chunk-QN237S7C.js';
3
+ import { getBaseMetaPathByHash } from './chunk-O6IE2MEZ.js';
4
+ import { init_storage_paths, normalizeBranchName, getFaissIndexPathByHash } from './chunk-LH4OUKNZ.js';
5
+ import { init_logging, log } from './chunk-VCCBEJQ5.js';
6
+ import { existsSync, mkdirSync, writeFileSync, readFileSync, unlinkSync } from 'fs';
7
+ import { dirname } from 'path';
8
+
9
+ // src/semantic/faiss/faiss-provider.ts
10
+ init_logging();
11
+ init_storage_paths();
12
+ var DEFAULT_CONFIG = {
13
+ dimensions: 768,
14
+ indexType: "hnsw",
15
+ hnswM: 32,
16
+ hnswEfConstruction: 200,
17
+ hnswEfSearch: 64,
18
+ autoSaveThreshold: 5e3,
19
+ // Save after 5000 new embeddings
20
+ persistPath: ""
21
+ };
22
+ var FaissProvider = class {
23
+ config;
24
+ client = null;
25
+ isInitialized = false;
26
+ // Track unsaved changes for auto-save
27
+ unsavedCount = 0;
28
+ lastSaveTime = 0;
29
+ // Background save state (avoid blocking pipeline)
30
+ pendingSave = null;
31
+ saveScheduled = false;
32
+ // Project context (FAISS index is per-project, per-branch)
33
+ projectHash = "default";
34
+ branchName = "main";
35
+ // ID set for existence checks (content stored in LibSQL, not here)
36
+ idSet = /* @__PURE__ */ new Set();
37
+ // Mutex for initialize() to prevent race condition with concurrent calls
38
+ initializePromise = null;
39
+ constructor(config = {}) {
40
+ this.config = { ...DEFAULT_CONFIG, ...config };
41
+ }
42
+ /**
43
+ * Set project context for per-project FAISS index
44
+ * If context changes while initialized, saves current index and loads new one
45
+ */
46
+ async setProjectContext(projectHash, branchName = "main") {
47
+ const normalizedBranch = normalizeBranchName(branchName);
48
+ const newPersistPath = getFaissIndexPathByHash(projectHash, normalizedBranch);
49
+ if (this.projectHash === projectHash && this.branchName === normalizedBranch) {
50
+ return;
51
+ }
52
+ if (this.isInitialized && this.client) {
53
+ log.i("FAISS", "Switching project context", {
54
+ from: { projectHash: this.projectHash, branchName: this.branchName },
55
+ to: { projectHash, branchName: normalizedBranch }
56
+ });
57
+ if (this.unsavedCount > 0) {
58
+ await this.save();
59
+ }
60
+ this.saveIdSet();
61
+ this.projectHash = projectHash;
62
+ this.branchName = normalizedBranch;
63
+ this.config.persistPath = newPersistPath;
64
+ this.idSet.clear();
65
+ this.unsavedCount = 0;
66
+ const loadPath = existsSync(newPersistPath) ? newPersistPath : void 0;
67
+ const indexConfig = {
68
+ dimensions: this.config.dimensions,
69
+ indexType: this.config.indexType,
70
+ metric: "l2",
71
+ hnswM: this.config.hnswM,
72
+ hnswEfConstruction: this.config.hnswEfConstruction,
73
+ hnswEfSearch: this.config.hnswEfSearch
74
+ };
75
+ await this.client.faissInitialize(indexConfig, loadPath);
76
+ if (loadPath) {
77
+ this.loadIdSet();
78
+ }
79
+ const stats = await this.client.faissGetStats();
80
+ log.i("FAISS", "Switched to new context", {
81
+ projectHash,
82
+ branchName: normalizedBranch,
83
+ vectors: stats.totalVectors,
84
+ idSetSize: this.idSet.size
85
+ });
86
+ } else {
87
+ this.projectHash = projectHash;
88
+ this.branchName = normalizedBranch;
89
+ this.config.persistPath = newPersistPath;
90
+ log.d("FAISS", "Project context set", {
91
+ projectHash: this.projectHash,
92
+ branchName: this.branchName,
93
+ persistPath: this.config.persistPath
94
+ });
95
+ }
96
+ }
97
+ // ===========================================================================
98
+ // Lifecycle
99
+ // ===========================================================================
100
+ async initialize() {
101
+ if (this.isInitialized) return true;
102
+ if (this.initializePromise) {
103
+ return this.initializePromise;
104
+ }
105
+ this.initializePromise = this.initializeInternal();
106
+ return this.initializePromise;
107
+ }
108
+ async initializeInternal() {
109
+ try {
110
+ log.i("FAISS", "Initializing...");
111
+ this.client = getGpuClient();
112
+ const started = await this.client.start();
113
+ if (!started) {
114
+ log.e("FAISS", "Failed to start Faiss client");
115
+ return false;
116
+ }
117
+ const indexConfig = {
118
+ dimensions: this.config.dimensions,
119
+ indexType: this.config.indexType,
120
+ metric: "l2",
121
+ hnswM: this.config.hnswM,
122
+ hnswEfConstruction: this.config.hnswEfConstruction,
123
+ hnswEfSearch: this.config.hnswEfSearch
124
+ };
125
+ let loadPath = existsSync(this.config.persistPath) ? this.config.persistPath : void 0;
126
+ if (loadPath) {
127
+ const savedMeta = this.loadIndexMetadata();
128
+ if (savedMeta && savedMeta.dimensions !== this.config.dimensions) {
129
+ log.w("FAISS", "Dimension mismatch - dropping old index", {
130
+ savedDimensions: savedMeta.dimensions,
131
+ configDimensions: this.config.dimensions,
132
+ indexPath: loadPath
133
+ });
134
+ this.deleteIndexFiles();
135
+ loadPath = void 0;
136
+ }
137
+ }
138
+ await this.client.faissInitialize(indexConfig, loadPath);
139
+ if (loadPath) {
140
+ this.loadIdSet();
141
+ }
142
+ this.isInitialized = true;
143
+ this.lastSaveTime = Date.now();
144
+ const stats = await this.client.faissGetStats();
145
+ log.i("FAISS", "Initialized", {
146
+ indexType: this.config.indexType,
147
+ dimensions: this.config.dimensions,
148
+ vectors: stats.totalVectors,
149
+ loaded: !!loadPath,
150
+ idSetSize: this.idSet.size
151
+ });
152
+ return true;
153
+ } catch (error) {
154
+ log.e("FAISS", "Initialization failed", { error: error.message });
155
+ return false;
156
+ }
157
+ }
158
+ async close() {
159
+ if (this.unsavedCount > 0) {
160
+ await this.save();
161
+ }
162
+ if (this.client && this.isInitialized) {
163
+ await this.client.stop();
164
+ }
165
+ this.idSet.clear();
166
+ this.isInitialized = false;
167
+ }
168
+ // ===========================================================================
169
+ // Insert Operations
170
+ // ===========================================================================
171
+ /**
172
+ * Add single embedding to Faiss
173
+ */
174
+ async add(embedding) {
175
+ if (!this.client || !this.isInitialized) {
176
+ throw new Error("FaissProvider not initialized");
177
+ }
178
+ await this.client.faissAdd([embedding.id], Array.from(embedding.vector));
179
+ this.idSet.add(embedding.id);
180
+ this.unsavedCount++;
181
+ if (this.unsavedCount >= this.config.autoSaveThreshold) {
182
+ await this.save();
183
+ }
184
+ }
185
+ /**
186
+ * Batch add embeddings to Faiss
187
+ */
188
+ async addBatch(embeddings) {
189
+ if (!this.client || !this.isInitialized) {
190
+ throw new Error("FaissProvider not initialized");
191
+ }
192
+ if (embeddings.length === 0) return;
193
+ const pStart = performance.now();
194
+ const pLog = (phase) => {
195
+ const elapsed = (performance.now() - pStart).toFixed(1);
196
+ log.i("FAISS", phase, { elapsedMs: elapsed });
197
+ };
198
+ const dim = this.config.dimensions;
199
+ const count = embeddings.length;
200
+ const ids = new Array(count);
201
+ const vectors = new Float32Array(count * dim);
202
+ for (let i = 0; i < count; i++) {
203
+ const emb = embeddings[i];
204
+ ids[i] = emb.id;
205
+ const normalized = simdL2Normalize(emb.vector);
206
+ vectors.set(normalized, i * dim);
207
+ this.idSet.add(emb.id);
208
+ }
209
+ pLog("F1_PREPARE_VECTORS");
210
+ await this.client.faissAdd(ids, vectors);
211
+ pLog("F2_FAISS_ADD");
212
+ this.unsavedCount += count;
213
+ log.d("FAISS", "Added embeddings", {
214
+ count,
215
+ unsaved: this.unsavedCount
216
+ });
217
+ if (this.unsavedCount >= this.config.autoSaveThreshold && !this.saveScheduled) {
218
+ this.saveScheduled = true;
219
+ this.pendingSave = this.save().catch((err) => log.w("FAISS", "Background save failed", { error: err.message })).finally(() => {
220
+ this.saveScheduled = false;
221
+ this.pendingSave = null;
222
+ });
223
+ }
224
+ }
225
+ /**
226
+ * Wait for any pending background save to complete
227
+ */
228
+ async waitForPendingSave() {
229
+ if (this.pendingSave) {
230
+ await this.pendingSave;
231
+ }
232
+ }
233
+ // ===========================================================================
234
+ // Search Operations
235
+ // ===========================================================================
236
+ /**
237
+ * Search for similar vectors in Faiss
238
+ * Returns only id + score. Content must be fetched from LibSQL separately.
239
+ */
240
+ async search(queryVector, limit = 10) {
241
+ if (!this.client || !this.isInitialized) {
242
+ throw new Error("FaissProvider not initialized");
243
+ }
244
+ const normalizedQuery = simdL2Normalize(queryVector);
245
+ const faissResults = await this.client.faissSearch(normalizedQuery, limit);
246
+ return faissResults.map((r) => ({
247
+ id: r.id,
248
+ similarity: r.score,
249
+ content: ""
250
+ // Content stored in LibSQL, not in Faiss
251
+ }));
252
+ }
253
+ /**
254
+ * Batch search for multiple query vectors
255
+ * Returns only id + score. Content must be fetched from LibSQL separately.
256
+ */
257
+ async batchSearch(queryVectors, limit = 10) {
258
+ if (!this.client || !this.isInitialized) {
259
+ throw new Error("FaissProvider not initialized");
260
+ }
261
+ const dim = this.config.dimensions;
262
+ const count = queryVectors.length;
263
+ const flatVectors = new Float32Array(count * dim);
264
+ for (let i = 0; i < count; i++) {
265
+ const normalized = simdL2Normalize(queryVectors[i]);
266
+ flatVectors.set(normalized, i * dim);
267
+ }
268
+ const faissResults = await this.client.faissBatchSearch(flatVectors, count, limit);
269
+ return faissResults.map(
270
+ (queryResults) => queryResults.map((r) => ({
271
+ id: r.id,
272
+ similarity: r.score,
273
+ content: ""
274
+ // Content stored in LibSQL, not in Faiss
275
+ }))
276
+ );
277
+ }
278
+ // ===========================================================================
279
+ // Persistence
280
+ // ===========================================================================
281
+ /**
282
+ * Save Faiss index and content cache to disk
283
+ */
284
+ async save() {
285
+ if (!this.client || !this.isInitialized) {
286
+ throw new Error("FaissProvider not initialized");
287
+ }
288
+ if (this.unsavedCount === 0) return;
289
+ try {
290
+ const dir = dirname(this.config.persistPath);
291
+ if (!existsSync(dir)) {
292
+ mkdirSync(dir, { recursive: true });
293
+ }
294
+ await this.client.faissSave(this.config.persistPath);
295
+ this.saveIdSet();
296
+ this.saveIndexMetadata();
297
+ const savedCount = this.unsavedCount;
298
+ this.unsavedCount = 0;
299
+ this.lastSaveTime = Date.now();
300
+ log.i("FAISS", "Index saved", {
301
+ path: this.config.persistPath,
302
+ savedCount,
303
+ idSetSize: this.idSet.size
304
+ });
305
+ } catch (error) {
306
+ log.e("FAISS", "Failed to save index", { error: error.message });
307
+ throw error;
308
+ }
309
+ }
310
+ /**
311
+ * Get ID set file path
312
+ */
313
+ getIdSetPath() {
314
+ return `${this.config.persistPath}.ids.json`;
315
+ }
316
+ /**
317
+ * Save ID set to disk (lightweight - just IDs, no content)
318
+ */
319
+ saveIdSet() {
320
+ if (!this.config.persistPath) {
321
+ return;
322
+ }
323
+ const idSetPath = this.getIdSetPath();
324
+ try {
325
+ const ids = Array.from(this.idSet);
326
+ writeFileSync(idSetPath, JSON.stringify(ids), "utf-8");
327
+ log.d("FAISS", "ID set saved", { path: idSetPath, size: this.idSet.size });
328
+ } catch (error) {
329
+ log.w("FAISS", "Failed to save ID set", { error: error.message });
330
+ }
331
+ }
332
+ /**
333
+ * Load ID set from disk
334
+ */
335
+ loadIdSet() {
336
+ const idSetPath = this.getIdSetPath();
337
+ if (!existsSync(idSetPath)) {
338
+ const legacyPath = `${this.config.persistPath}.content.json`;
339
+ if (existsSync(legacyPath)) {
340
+ try {
341
+ const data = readFileSync(legacyPath, "utf-8");
342
+ const cacheObj = JSON.parse(data);
343
+ this.idSet.clear();
344
+ for (const id of Object.keys(cacheObj)) {
345
+ this.idSet.add(id);
346
+ }
347
+ log.i("FAISS", "Migrated IDs from legacy content cache", { size: this.idSet.size });
348
+ this.saveIdSet();
349
+ return;
350
+ } catch {
351
+ }
352
+ }
353
+ log.d("FAISS", "No ID set file found", { path: idSetPath });
354
+ return;
355
+ }
356
+ try {
357
+ const data = readFileSync(idSetPath, "utf-8");
358
+ const ids = JSON.parse(data);
359
+ this.idSet.clear();
360
+ for (const id of ids) {
361
+ this.idSet.add(id);
362
+ }
363
+ log.i("FAISS", "ID set loaded", { path: idSetPath, size: this.idSet.size });
364
+ } catch (error) {
365
+ log.w("FAISS", "Failed to load ID set", { error: error.message });
366
+ }
367
+ }
368
+ /**
369
+ * Get index metadata file path
370
+ */
371
+ getMetadataPath() {
372
+ return `${this.config.persistPath}.meta.json`;
373
+ }
374
+ /**
375
+ * Save index metadata (dimensions, etc.)
376
+ * Also creates faiss-base.meta.json on first save to mark base branch
377
+ */
378
+ saveIndexMetadata() {
379
+ if (!this.config.persistPath) return;
380
+ const metaPath = this.getMetadataPath();
381
+ try {
382
+ const meta = {
383
+ dimensions: this.config.dimensions,
384
+ indexType: this.config.indexType,
385
+ savedAt: Date.now()
386
+ };
387
+ writeFileSync(metaPath, JSON.stringify(meta), "utf-8");
388
+ log.d("FAISS", "Index metadata saved", { path: metaPath, dimensions: meta.dimensions });
389
+ this.ensureBaseMetadata();
390
+ } catch (error) {
391
+ log.w("FAISS", "Failed to save index metadata", { error: error.message });
392
+ }
393
+ }
394
+ /**
395
+ * Ensure faiss-base.meta.json exists (create on first indexing)
396
+ * This marks which branch is the base for layered index support
397
+ */
398
+ ensureBaseMetadata() {
399
+ const baseMetaPath = getBaseMetaPathByHash(this.projectHash);
400
+ if (existsSync(baseMetaPath)) {
401
+ return;
402
+ }
403
+ try {
404
+ const baseMeta = {
405
+ baseBranch: this.branchName,
406
+ vectorCount: this.idSet.size,
407
+ createdAt: Date.now(),
408
+ updatedAt: Date.now(),
409
+ dimensions: this.config.dimensions,
410
+ indexType: this.config.indexType
411
+ };
412
+ const dir = dirname(baseMetaPath);
413
+ if (!existsSync(dir)) {
414
+ mkdirSync(dir, { recursive: true });
415
+ }
416
+ writeFileSync(baseMetaPath, JSON.stringify(baseMeta, null, 2), "utf-8");
417
+ log.i("FAISS", "Base metadata created", {
418
+ branch: this.branchName,
419
+ path: baseMetaPath,
420
+ vectors: this.idSet.size
421
+ });
422
+ } catch (error) {
423
+ log.w("FAISS", "Failed to create base metadata", { error: error.message });
424
+ }
425
+ }
426
+ /**
427
+ * Load index metadata
428
+ */
429
+ loadIndexMetadata() {
430
+ const metaPath = this.getMetadataPath();
431
+ if (!existsSync(metaPath)) {
432
+ return null;
433
+ }
434
+ try {
435
+ const data = readFileSync(metaPath, "utf-8");
436
+ return JSON.parse(data);
437
+ } catch (error) {
438
+ log.w("FAISS", "Failed to load index metadata", { error: error.message });
439
+ return null;
440
+ }
441
+ }
442
+ /**
443
+ * Delete all index files (index, ID set, metadata)
444
+ */
445
+ deleteIndexFiles() {
446
+ const filesToDelete = [this.config.persistPath, this.getIdSetPath(), this.getMetadataPath()];
447
+ for (const filePath of filesToDelete) {
448
+ if (filePath && existsSync(filePath)) {
449
+ try {
450
+ unlinkSync(filePath);
451
+ log.d("FAISS", "Deleted index file", { path: filePath });
452
+ } catch (error) {
453
+ log.w("FAISS", "Failed to delete file", { path: filePath, error: error.message });
454
+ }
455
+ }
456
+ }
457
+ this.idSet.clear();
458
+ this.unsavedCount = 0;
459
+ }
460
+ /**
461
+ * Force flush and save (compatibility method)
462
+ */
463
+ async flush() {
464
+ await this.waitForPendingSave();
465
+ const count = this.unsavedCount;
466
+ if (count > 0) {
467
+ await this.save();
468
+ }
469
+ return count;
470
+ }
471
+ /**
472
+ * Flush and save (alias for vector-store compatibility)
473
+ */
474
+ async flushAndSave() {
475
+ await this.waitForPendingSave();
476
+ await this.save();
477
+ }
478
+ // ===========================================================================
479
+ // Index Maintenance
480
+ // ===========================================================================
481
+ /**
482
+ * Train IVF/PQ indexes (required before adding vectors)
483
+ */
484
+ async train(trainingVectors) {
485
+ if (!this.client || !this.isInitialized) {
486
+ throw new Error("FaissProvider not initialized");
487
+ }
488
+ const flatVectors = [];
489
+ for (const v of trainingVectors) {
490
+ flatVectors.push(...Array.from(v));
491
+ }
492
+ await this.client.faissTrain(new Float32Array(flatVectors), trainingVectors.length);
493
+ log.i("FAISS", "Trained index", { vectorCount: trainingVectors.length });
494
+ }
495
+ // ===========================================================================
496
+ // Statistics
497
+ // ===========================================================================
498
+ async getStats() {
499
+ const faissStats = this.client ? await this.client.getStats() : null;
500
+ return {
501
+ totalVectors: faissStats?.totalVectors ?? 0,
502
+ unsavedCount: this.unsavedCount,
503
+ lastSaveTime: this.lastSaveTime,
504
+ idSetSize: this.idSet.size,
505
+ faissStats
506
+ };
507
+ }
508
+ isReady() {
509
+ return this.isInitialized && this.client?.isRunning() === true;
510
+ }
511
+ /**
512
+ * Get total vector count
513
+ */
514
+ async getVectorCount() {
515
+ const stats = await this.getStats();
516
+ return stats.totalVectors;
517
+ }
518
+ /**
519
+ * Check which IDs already exist in the ID set
520
+ * Used for incremental indexing to skip already-indexed entities
521
+ */
522
+ getExistingIds(ids) {
523
+ const existing = /* @__PURE__ */ new Set();
524
+ for (const id of ids) {
525
+ if (this.idSet.has(id)) {
526
+ existing.add(id);
527
+ }
528
+ }
529
+ return existing;
530
+ }
531
+ /**
532
+ * Check if an ID exists in the ID set
533
+ */
534
+ hasId(id) {
535
+ return this.idSet.has(id);
536
+ }
537
+ /**
538
+ * Remove embeddings by IDs (for re-indexing changed files)
539
+ */
540
+ async remove(ids) {
541
+ if (!this.client || !this.isInitialized) {
542
+ throw new Error("FaissProvider not initialized");
543
+ }
544
+ await this.client.faissRemove(ids);
545
+ for (const id of ids) {
546
+ this.idSet.delete(id);
547
+ }
548
+ log.d("FAISS", "Removed embeddings", { count: ids.length });
549
+ }
550
+ };
551
+ var faissProvider = null;
552
+ function getFaissProvider(config) {
553
+ if (!faissProvider) {
554
+ faissProvider = new FaissProvider(config);
555
+ }
556
+ return faissProvider;
557
+ }
558
+ async function initializeFaissProvider(config) {
559
+ const provider = getFaissProvider(config);
560
+ const success = await provider.initialize();
561
+ return success ? provider : null;
562
+ }
563
+ async function shutdownFaissProvider() {
564
+ if (faissProvider) {
565
+ await faissProvider.close();
566
+ faissProvider = null;
567
+ }
568
+ }
569
+
570
+ export { FaissProvider, getFaissProvider, initializeFaissProvider, shutdownFaissProvider };
571
+ //# sourceMappingURL=chunk-EOH25B5P.js.map
572
+ //# sourceMappingURL=chunk-EOH25B5P.js.map