@yugenlab/vaayu 0.1.9 → 0.1.11

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 (43) hide show
  1. package/chunks/{agentic-tool-loop-2FZK72JO.js → agentic-tool-loop-O3NUV7KG.js} +1 -1
  2. package/chunks/{chunk-UZ6OIVEC.js → chunk-2OBLQJYJ.js} +1 -1
  3. package/chunks/{chunk-PJEYJQ2C.js → chunk-3AYSJ7WB.js} +30 -18
  4. package/chunks/{chunk-U62ABYKD.js → chunk-67DXWEKG.js} +3 -3
  5. package/chunks/{chunk-6556EKOB.js → chunk-7AYYXHYZ.js} +25 -24
  6. package/chunks/{chunk-IGBRBFXX.js → chunk-7XV5ISV7.js} +7 -5
  7. package/chunks/{chunk-JAWZ7ANC.js → chunk-A3HOZBC5.js} +11 -7
  8. package/chunks/{chunk-LVE2EOOH.js → chunk-D46QTN3G.js} +126 -136
  9. package/chunks/{chunk-PRXQW76U.js → chunk-EG37M4QL.js} +17 -6
  10. package/chunks/{chunk-7UOXFHEB.js → chunk-F6RNEGFX.js} +480 -432
  11. package/chunks/{chunk-MJ74G5RB.js → chunk-G2QREGXK.js} +2 -2
  12. package/chunks/{chunk-DOQMEQ5S.js → chunk-JZTFJE7M.js} +39 -39
  13. package/chunks/{chunk-S2HDNNC7.js → chunk-LJUEMPLG.js} +638 -679
  14. package/chunks/{chunk-C76USAC5.js → chunk-QFGAB4XD.js} +13 -5
  15. package/chunks/{chunk-D3RVJGO7.js → chunk-QV4GPIPT.js} +118 -135
  16. package/chunks/{chunk-YJRXLRTE.js → chunk-V2ZIKDN4.js} +9 -8
  17. package/chunks/{chunk-YSC77CKZ.js → chunk-VCUJES75.js} +3276 -3526
  18. package/chunks/{chunk-OBYBBGHA.js → chunk-W4PVGBUH.js} +190 -189
  19. package/chunks/chunk-Z576WVLG.js +434 -0
  20. package/chunks/{chunk-NHRBVSN3.js → chunk-ZYY6N3SP.js} +117 -110
  21. package/chunks/{consolidation-indexer-CD6DS2HO.js → consolidation-indexer-VIWOP6VO.js} +8 -8
  22. package/chunks/{day-consolidation-U3X6P4ZG.js → day-consolidation-HMHSXIOM.js} +8 -4
  23. package/chunks/{src-ZAKUL232.js → dist-CY5NX2IK.js} +17 -17
  24. package/chunks/graphrag-T2QWNX57.js +14 -0
  25. package/chunks/{hierarchical-temporal-search-ETXYYJZK.js → hierarchical-temporal-search-U6DG74IR.js} +2 -2
  26. package/chunks/hybrid-search-BYTXCOXP.js +20 -0
  27. package/chunks/{memory-store-A6WOWLWC.js → memory-store-LEERUQGL.js} +3 -3
  28. package/chunks/periodic-consolidation-D6SSKZ7H.js +11 -0
  29. package/chunks/{postgres-WLH3D5HG.js → postgres-7GZDDX77.js} +2 -2
  30. package/chunks/{recall-IUPQCBYP.js → recall-LNRQVATQ.js} +7 -7
  31. package/chunks/search-BIODUW2P.js +19 -0
  32. package/chunks/{session-store-NDUDYAC7.js → session-store-O3TS7DUY.js} +5 -5
  33. package/chunks/{sqlite-DHUQGPR5.js → sqlite-7BC4DJTN.js} +2 -2
  34. package/chunks/vasana-engine-BJFHJVGM.js +30 -0
  35. package/gateway.js +31671 -24786
  36. package/package.json +1 -1
  37. package/pair-cli.js +1 -1
  38. package/chunks/chunk-TEQKXGIK.js +0 -752
  39. package/chunks/graphrag-LAZSXLLI.js +0 -14
  40. package/chunks/hybrid-search-TX6T3KYH.js +0 -20
  41. package/chunks/periodic-consolidation-4MACZE6S.js +0 -11
  42. package/chunks/search-HHSVHBXC.js +0 -19
  43. package/chunks/vasana-engine-G6BPOFX7.js +0 -10
@@ -6,28 +6,25 @@ import {
6
6
  STOP_WORDS,
7
7
  cosineSimilarity,
8
8
  textMatchScore
9
- } from "./chunk-JAWZ7ANC.js";
9
+ } from "./chunk-A3HOZBC5.js";
10
10
  import {
11
11
  initGraphSchema
12
- } from "./chunk-YJRXLRTE.js";
12
+ } from "./chunk-V2ZIKDN4.js";
13
13
  import {
14
14
  DatabaseManager
15
- } from "./chunk-U62ABYKD.js";
15
+ } from "./chunk-67DXWEKG.js";
16
16
  import {
17
17
  getChitraguptaHome
18
- } from "./chunk-UZ6OIVEC.js";
18
+ } from "./chunk-2OBLQJYJ.js";
19
19
 
20
- // ../chitragupta/packages/smriti/src/graphrag.ts
21
- import fs from "fs";
22
- import path from "path";
23
-
24
- // ../chitragupta/packages/smriti/src/graphrag-pagerank.ts
20
+ // ../chitragupta/packages/smriti/dist/graphrag-pagerank.js
25
21
  var PAGERANK_DAMPING = 0.85;
26
22
  var PAGERANK_EPSILON = 1e-4;
27
23
  var PAGERANK_MAX_ITERATIONS = 100;
28
24
  function computePageRank(graph) {
29
25
  const N = graph.nodes.length;
30
- if (N === 0) return /* @__PURE__ */ new Map();
26
+ if (N === 0)
27
+ return /* @__PURE__ */ new Map();
31
28
  const ranks = /* @__PURE__ */ new Map();
32
29
  const nodeIds = /* @__PURE__ */ new Set();
33
30
  for (const node of graph.nodes) {
@@ -67,162 +64,24 @@ function computePageRank(graph) {
67
64
  const rank = baseFactor + PAGERANK_DAMPING * (incomingRank + danglingRank / N);
68
65
  newRanks.set(node.id, rank);
69
66
  const delta = Math.abs(rank - (ranks.get(node.id) ?? 0));
70
- if (delta > maxDelta) maxDelta = delta;
67
+ if (delta > maxDelta)
68
+ maxDelta = delta;
71
69
  }
72
70
  for (const [id, rank] of newRanks) {
73
71
  ranks.set(id, rank);
74
72
  }
75
- if (maxDelta < PAGERANK_EPSILON) break;
73
+ if (maxDelta < PAGERANK_EPSILON)
74
+ break;
76
75
  }
77
76
  return ranks;
78
77
  }
79
78
 
80
- // ../chitragupta/packages/smriti/src/graphrag-pagerank-personalized.ts
81
- function buildTopicBias(nodeIds, nodeContents, topic) {
82
- const bias = /* @__PURE__ */ new Map();
83
- const n = nodeIds.length;
84
- if (!topic || n === 0) {
85
- const uniform = 1 / Math.max(n, 1);
86
- for (const id of nodeIds) bias.set(id, uniform);
87
- return bias;
88
- }
89
- const queryTerms = tokenizeSimple(topic);
90
- const queryTf = termFrequency(queryTerms);
91
- let totalSim = 0;
92
- const similarities = new Array(n);
93
- for (let i = 0; i < n; i++) {
94
- const content = nodeContents.get(nodeIds[i]) ?? "";
95
- const docTerms = tokenizeSimple(content);
96
- const docTf = termFrequency(docTerms);
97
- const sim = tfCosineSimilarity(queryTf, docTf);
98
- similarities[i] = sim;
99
- totalSim += sim;
100
- }
101
- if (totalSim === 0) {
102
- const uniform = 1 / n;
103
- for (const id of nodeIds) bias.set(id, uniform);
104
- return bias;
105
- }
106
- for (let i = 0; i < n; i++) {
107
- bias.set(nodeIds[i], similarities[i] / totalSim);
108
- }
109
- return bias;
110
- }
111
- function tokenizeSimple(text) {
112
- return text.toLowerCase().replace(/[^a-z0-9\s]/g, " ").split(/\s+/).filter((t) => t.length >= 2);
113
- }
114
- function termFrequency(tokens) {
115
- const tf = /* @__PURE__ */ new Map();
116
- for (const t of tokens) {
117
- tf.set(t, (tf.get(t) ?? 0) + 1);
118
- }
119
- return tf;
120
- }
121
- function tfCosineSimilarity(a, b) {
122
- let dot = 0;
123
- let normA = 0;
124
- let normB = 0;
125
- for (const [term, freqA] of a) {
126
- normA += freqA * freqA;
127
- const freqB = b.get(term);
128
- if (freqB !== void 0) dot += freqA * freqB;
129
- }
130
- for (const freqB of b.values()) {
131
- normB += freqB * freqB;
132
- }
133
- const denom = Math.sqrt(normA) * Math.sqrt(normB);
134
- return denom === 0 ? 0 : dot / denom;
135
- }
136
- function computePersonalizedPageRank(graph, topicBias, opts) {
137
- const damping = opts?.damping ?? 0.85;
138
- const epsilon = opts?.epsilon ?? 1e-6;
139
- const maxIter = opts?.maxIterations ?? 150;
140
- const useGS = opts?.useGaussSeidel ?? true;
141
- const N = graph.nodes.length;
142
- if (N === 0) return /* @__PURE__ */ new Map();
143
- const nodeIds = graph.nodes.map((n) => n.id);
144
- const nodeIdSet = new Set(nodeIds);
145
- const outDegree = /* @__PURE__ */ new Map();
146
- const inLinks = /* @__PURE__ */ new Map();
147
- for (const id of nodeIds) {
148
- outDegree.set(id, 0);
149
- inLinks.set(id, []);
150
- }
151
- for (const edge of graph.edges) {
152
- if (nodeIdSet.has(edge.source) && nodeIdSet.has(edge.target)) {
153
- outDegree.set(edge.source, (outDegree.get(edge.source) ?? 0) + 1);
154
- inLinks.get(edge.target).push(edge.source);
155
- }
156
- }
157
- let bias;
158
- if (typeof topicBias === "string") {
159
- const nodeContents = /* @__PURE__ */ new Map();
160
- for (const node of graph.nodes) {
161
- nodeContents.set(node.id, node.content);
162
- }
163
- bias = buildTopicBias(nodeIds, nodeContents, topicBias);
164
- } else if (topicBias instanceof Map) {
165
- bias = topicBias;
166
- } else {
167
- const uniform = 1 / N;
168
- bias = new Map(nodeIds.map((id) => [id, uniform]));
169
- }
170
- const ranks = /* @__PURE__ */ new Map();
171
- for (const id of nodeIds) {
172
- ranks.set(id, 1 / N);
173
- }
174
- const danglingNodes = [];
175
- for (const id of nodeIds) {
176
- if ((outDegree.get(id) ?? 0) === 0) danglingNodes.push(id);
177
- }
178
- for (let iter = 0; iter < maxIter; iter++) {
179
- let danglingSum = 0;
180
- for (const id of danglingNodes) {
181
- danglingSum += ranks.get(id) ?? 0;
182
- }
183
- const danglingContrib = damping * danglingSum / N;
184
- let maxDelta = 0;
185
- if (useGS) {
186
- for (const id of nodeIds) {
187
- const biasVal = bias.get(id) ?? 1 / N;
188
- let incomingSum = 0;
189
- for (const src of inLinks.get(id) ?? []) {
190
- const srcRank = ranks.get(src) ?? 0;
191
- const srcOut = outDegree.get(src) ?? 1;
192
- incomingSum += srcRank / srcOut;
193
- }
194
- const newRank = (1 - damping) * biasVal + damping * incomingSum + danglingContrib;
195
- const oldRank = ranks.get(id) ?? 0;
196
- const delta = Math.abs(newRank - oldRank);
197
- if (delta > maxDelta) maxDelta = delta;
198
- ranks.set(id, newRank);
199
- }
200
- } else {
201
- const newRanks = /* @__PURE__ */ new Map();
202
- for (const id of nodeIds) {
203
- const biasVal = bias.get(id) ?? 1 / N;
204
- let incomingSum = 0;
205
- for (const src of inLinks.get(id) ?? []) {
206
- const srcRank = ranks.get(src) ?? 0;
207
- const srcOut = outDegree.get(src) ?? 1;
208
- incomingSum += srcRank / srcOut;
209
- }
210
- const newRank = (1 - damping) * biasVal + damping * incomingSum + danglingContrib;
211
- newRanks.set(id, newRank);
212
- const delta = Math.abs(newRank - (ranks.get(id) ?? 0));
213
- if (delta > maxDelta) maxDelta = delta;
214
- }
215
- for (const [id, rank] of newRanks) ranks.set(id, rank);
216
- }
217
- if (maxDelta < epsilon) break;
218
- }
219
- return ranks;
220
- }
79
+ // ../chitragupta/packages/smriti/dist/graphrag-pagerank-incremental.js
221
80
  var IncrementalPageRank = class {
222
81
  ranks = /* @__PURE__ */ new Map();
223
82
  outDegree = /* @__PURE__ */ new Map();
224
83
  inLinks = /* @__PURE__ */ new Map();
225
- /** Forward adjacency list: source Set<target>. Avoids O(E) reverse lookup in getOutNeighbors(). */
84
+ /** Forward adjacency list: source -> Set<target>. Avoids O(E) reverse lookup in getOutNeighbors(). */
226
85
  outLinks = /* @__PURE__ */ new Map();
227
86
  nodeSet = /* @__PURE__ */ new Set();
228
87
  damping;
@@ -299,7 +158,8 @@ var IncrementalPageRank = class {
299
158
  if (oldDeg > 0) {
300
159
  const shareDelta = prU * (1 / newDeg - 1 / oldDeg);
301
160
  for (const neighbor of this.getOutNeighbors(source)) {
302
- if (neighbor === target) continue;
161
+ if (neighbor === target)
162
+ continue;
303
163
  const prev = residuals.get(neighbor) ?? 0;
304
164
  residuals.set(neighbor, prev + this.damping * shareDelta);
305
165
  }
@@ -313,11 +173,14 @@ var IncrementalPageRank = class {
313
173
  * @param target - Target node ID.
314
174
  */
315
175
  removeEdge(source, target) {
316
- if (!this.nodeSet.has(source) || !this.nodeSet.has(target)) return;
176
+ if (!this.nodeSet.has(source) || !this.nodeSet.has(target))
177
+ return;
317
178
  const inSet = this.inLinks.get(target);
318
- if (!inSet || !inSet.has(source)) return;
179
+ if (!inSet || !inSet.has(source))
180
+ return;
319
181
  const oldDeg = this.outDegree.get(source) ?? 0;
320
- if (oldDeg <= 0) return;
182
+ if (oldDeg <= 0)
183
+ return;
321
184
  const newDeg = oldDeg - 1;
322
185
  this.outDegree.set(source, newDeg);
323
186
  inSet.delete(source);
@@ -338,7 +201,7 @@ var IncrementalPageRank = class {
338
201
  getRanks() {
339
202
  return new Map(this.ranks);
340
203
  }
341
- // ─── Private ──────────────────────────────────────────────────────
204
+ // --- Private ---------------------------------------------------------
342
205
  /**
343
206
  * Propagate residuals through the graph until all are below epsilon.
344
207
  *
@@ -360,7 +223,8 @@ var IncrementalPageRank = class {
360
223
  maxNode = node;
361
224
  }
362
225
  }
363
- if (maxNode === null || maxResidual < this.epsilon) break;
226
+ if (maxNode === null || maxResidual < this.epsilon)
227
+ break;
364
228
  const res = residuals.get(maxNode);
365
229
  this.ranks.set(maxNode, (this.ranks.get(maxNode) ?? 0) + res);
366
230
  residuals.delete(maxNode);
@@ -384,7 +248,158 @@ var IncrementalPageRank = class {
384
248
  }
385
249
  };
386
250
 
387
- // ../chitragupta/packages/smriti/src/graphrag-extraction.ts
251
+ // ../chitragupta/packages/smriti/dist/graphrag-pagerank-personalized.js
252
+ function buildTopicBias(nodeIds, nodeContents, topic) {
253
+ const bias = /* @__PURE__ */ new Map();
254
+ const n = nodeIds.length;
255
+ if (!topic || n === 0) {
256
+ const uniform = 1 / Math.max(n, 1);
257
+ for (const id of nodeIds)
258
+ bias.set(id, uniform);
259
+ return bias;
260
+ }
261
+ const queryTerms = tokenizeSimple(topic);
262
+ const queryTf = termFrequency(queryTerms);
263
+ let totalSim = 0;
264
+ const similarities = new Array(n);
265
+ for (let i = 0; i < n; i++) {
266
+ const content = nodeContents.get(nodeIds[i]) ?? "";
267
+ const docTerms = tokenizeSimple(content);
268
+ const docTf = termFrequency(docTerms);
269
+ const sim = tfCosineSimilarity(queryTf, docTf);
270
+ similarities[i] = sim;
271
+ totalSim += sim;
272
+ }
273
+ if (totalSim === 0) {
274
+ const uniform = 1 / n;
275
+ for (const id of nodeIds)
276
+ bias.set(id, uniform);
277
+ return bias;
278
+ }
279
+ for (let i = 0; i < n; i++) {
280
+ bias.set(nodeIds[i], similarities[i] / totalSim);
281
+ }
282
+ return bias;
283
+ }
284
+ function tokenizeSimple(text) {
285
+ return text.toLowerCase().replace(/[^a-z0-9\s]/g, " ").split(/\s+/).filter((t) => t.length >= 2);
286
+ }
287
+ function termFrequency(tokens) {
288
+ const tf = /* @__PURE__ */ new Map();
289
+ for (const t of tokens) {
290
+ tf.set(t, (tf.get(t) ?? 0) + 1);
291
+ }
292
+ return tf;
293
+ }
294
+ function tfCosineSimilarity(a, b) {
295
+ let dot = 0;
296
+ let normA = 0;
297
+ let normB = 0;
298
+ for (const [term, freqA] of a) {
299
+ normA += freqA * freqA;
300
+ const freqB = b.get(term);
301
+ if (freqB !== void 0)
302
+ dot += freqA * freqB;
303
+ }
304
+ for (const freqB of b.values()) {
305
+ normB += freqB * freqB;
306
+ }
307
+ const denom = Math.sqrt(normA) * Math.sqrt(normB);
308
+ return denom === 0 ? 0 : dot / denom;
309
+ }
310
+ function computePersonalizedPageRank(graph, topicBias, opts) {
311
+ const damping = opts?.damping ?? 0.85;
312
+ const epsilon = opts?.epsilon ?? 1e-6;
313
+ const maxIter = opts?.maxIterations ?? 150;
314
+ const useGS = opts?.useGaussSeidel ?? true;
315
+ const N = graph.nodes.length;
316
+ if (N === 0)
317
+ return /* @__PURE__ */ new Map();
318
+ const nodeIds = graph.nodes.map((n) => n.id);
319
+ const nodeIdSet = new Set(nodeIds);
320
+ const outDegree = /* @__PURE__ */ new Map();
321
+ const inLinks = /* @__PURE__ */ new Map();
322
+ for (const id of nodeIds) {
323
+ outDegree.set(id, 0);
324
+ inLinks.set(id, []);
325
+ }
326
+ for (const edge of graph.edges) {
327
+ if (nodeIdSet.has(edge.source) && nodeIdSet.has(edge.target)) {
328
+ outDegree.set(edge.source, (outDegree.get(edge.source) ?? 0) + 1);
329
+ inLinks.get(edge.target).push(edge.source);
330
+ }
331
+ }
332
+ let bias;
333
+ if (typeof topicBias === "string") {
334
+ const nodeContents = /* @__PURE__ */ new Map();
335
+ for (const node of graph.nodes) {
336
+ nodeContents.set(node.id, node.content);
337
+ }
338
+ bias = buildTopicBias(nodeIds, nodeContents, topicBias);
339
+ } else if (topicBias instanceof Map) {
340
+ bias = topicBias;
341
+ } else {
342
+ const uniform = 1 / N;
343
+ bias = new Map(nodeIds.map((id) => [id, uniform]));
344
+ }
345
+ const ranks = /* @__PURE__ */ new Map();
346
+ for (const id of nodeIds) {
347
+ ranks.set(id, 1 / N);
348
+ }
349
+ const danglingNodes = [];
350
+ for (const id of nodeIds) {
351
+ if ((outDegree.get(id) ?? 0) === 0)
352
+ danglingNodes.push(id);
353
+ }
354
+ for (let iter = 0; iter < maxIter; iter++) {
355
+ let danglingSum = 0;
356
+ for (const id of danglingNodes) {
357
+ danglingSum += ranks.get(id) ?? 0;
358
+ }
359
+ const danglingContrib = damping * danglingSum / N;
360
+ let maxDelta = 0;
361
+ if (useGS) {
362
+ for (const id of nodeIds) {
363
+ const biasVal = bias.get(id) ?? 1 / N;
364
+ let incomingSum = 0;
365
+ for (const src of inLinks.get(id) ?? []) {
366
+ const srcRank = ranks.get(src) ?? 0;
367
+ const srcOut = outDegree.get(src) ?? 1;
368
+ incomingSum += srcRank / srcOut;
369
+ }
370
+ const newRank = (1 - damping) * biasVal + damping * incomingSum + danglingContrib;
371
+ const oldRank = ranks.get(id) ?? 0;
372
+ const delta = Math.abs(newRank - oldRank);
373
+ if (delta > maxDelta)
374
+ maxDelta = delta;
375
+ ranks.set(id, newRank);
376
+ }
377
+ } else {
378
+ const newRanks = /* @__PURE__ */ new Map();
379
+ for (const id of nodeIds) {
380
+ const biasVal = bias.get(id) ?? 1 / N;
381
+ let incomingSum = 0;
382
+ for (const src of inLinks.get(id) ?? []) {
383
+ const srcRank = ranks.get(src) ?? 0;
384
+ const srcOut = outDegree.get(src) ?? 1;
385
+ incomingSum += srcRank / srcOut;
386
+ }
387
+ const newRank = (1 - damping) * biasVal + damping * incomingSum + danglingContrib;
388
+ newRanks.set(id, newRank);
389
+ const delta = Math.abs(newRank - (ranks.get(id) ?? 0));
390
+ if (delta > maxDelta)
391
+ maxDelta = delta;
392
+ }
393
+ for (const [id, rank] of newRanks)
394
+ ranks.set(id, rank);
395
+ }
396
+ if (maxDelta < epsilon)
397
+ break;
398
+ }
399
+ return ranks;
400
+ }
401
+
402
+ // ../chitragupta/packages/smriti/dist/graphrag-extraction.js
388
403
  var CHUNK_TARGET_TOKENS = 350;
389
404
  var CHUNK_MIN_TOKENS = 200;
390
405
  var CHUNK_MAX_TOKENS = 500;
@@ -398,7 +413,8 @@ function estimateTokens(text) {
398
413
  }
399
414
  function semanticChunk(text) {
400
415
  const sentences = splitSentences(text);
401
- if (sentences.length === 0) return [];
416
+ if (sentences.length === 0)
417
+ return [];
402
418
  const totalTokens = estimateTokens(text);
403
419
  if (totalTokens <= CHUNK_MAX_TOKENS) {
404
420
  return [{ text, startSentence: 0, endSentence: sentences.length - 1 }];
@@ -427,7 +443,8 @@ function semanticChunk(text) {
427
443
  overlapTokens += estimateTokens(sentences[overlapStart]);
428
444
  }
429
445
  startIdx = Math.max(overlapStart, startIdx + 1);
430
- if (startIdx >= endIdx) break;
446
+ if (startIdx >= endIdx)
447
+ break;
431
448
  }
432
449
  return chunks;
433
450
  }
@@ -485,8 +502,10 @@ function keywordExtractEntities(text) {
485
502
  const entities = [];
486
503
  const sorted = [...freq.entries()].sort((a, b) => b[1] - a[1]);
487
504
  for (const [word, count] of sorted) {
488
- if (count < 2) break;
489
- if (entities.length >= 20) break;
505
+ if (count < 2)
506
+ break;
507
+ if (entities.length >= 20)
508
+ break;
490
509
  entities.push({
491
510
  name: word,
492
511
  type: "concept",
@@ -496,7 +515,7 @@ function keywordExtractEntities(text) {
496
515
  return entities;
497
516
  }
498
517
 
499
- // ../chitragupta/packages/smriti/src/ner-extractor.ts
518
+ // ../chitragupta/packages/smriti/dist/ner-extractor.js
500
519
  var DEFAULT_ENDPOINT = "http://localhost:8501";
501
520
  var DEFAULT_MODEL = "gliner-large-v2.1";
502
521
  var DEFAULT_MIN_CONFIDENCE = 0.5;
@@ -590,10 +609,7 @@ var TECHNOLOGY_WORDS = [
590
609
  "yarn",
591
610
  "zod"
592
611
  ];
593
- var TECHNOLOGY_PATTERN = new RegExp(
594
- `\\b(${TECHNOLOGY_WORDS.join("|")})\\b`,
595
- "gi"
596
- );
612
+ var TECHNOLOGY_PATTERN = new RegExp(`\\b(${TECHNOLOGY_WORDS.join("|")})\\b`, "gi");
597
613
  var TOOL_WORDS = [
598
614
  "read",
599
615
  "write",
@@ -609,10 +625,7 @@ var TOOL_WORDS = [
609
625
  "webfetch",
610
626
  "websearch"
611
627
  ];
612
- var TOOL_PATTERN = new RegExp(
613
- `\\b(${TOOL_WORDS.join("|")})\\b`,
614
- "gi"
615
- );
628
+ var TOOL_PATTERN = new RegExp(`\\b(${TOOL_WORDS.join("|")})\\b`, "gi");
616
629
  var ERROR_PATTERN = /\b((?:[A-Z]\w*Error)\b|(?:ENOENT|EACCES|ECONNREFUSED|ETIMEDOUT|EPERM)\b|(?:failed\s+to\s+\w+)|(?:error:\s*\S+))/gi;
617
630
  var DECISION_PATTERN = /\b((?:decided|chose|selected|opted|switched|migrated|moved)\s+to\s+\w[\w\s]{0,30})/gi;
618
631
  var ACTION_PATTERN = /\b((?:created|deleted|removed|modified|updated|installed|uninstalled|deployed|fixed|refactored|renamed|merged|rebased|reverted|committed|pushed|pulled)\s+\w[\w\s]{0,30})/gi;
@@ -641,7 +654,8 @@ var NERExtractor = class {
641
654
  * and `useHeuristic` is enabled.
642
655
  */
643
656
  async extract(text) {
644
- if (!text || text.trim().length === 0) return [];
657
+ if (!text || text.trim().length === 0)
658
+ return [];
645
659
  const glinerUp = await this.isGLiNERAvailable();
646
660
  if (glinerUp) {
647
661
  try {
@@ -668,7 +682,8 @@ var NERExtractor = class {
668
682
  * Caches the result after the first successful probe.
669
683
  */
670
684
  async isGLiNERAvailable() {
671
- if (this.glinerAvailable !== null) return this.glinerAvailable;
685
+ if (this.glinerAvailable !== null)
686
+ return this.glinerAvailable;
672
687
  try {
673
688
  const response = await fetch(this.endpoint, {
674
689
  method: "GET",
@@ -734,10 +749,12 @@ var NERExtractor = class {
734
749
  const coveredSpans = [];
735
750
  const addMatch = (match, type, groupIndex = 1) => {
736
751
  const captured = match[groupIndex];
737
- if (!captured) return;
752
+ if (!captured)
753
+ return;
738
754
  const start = match.index + match[0].indexOf(captured);
739
755
  const end = start + captured.length;
740
- if (this.spanOverlaps([start, end], coveredSpans)) return;
756
+ if (this.spanOverlaps([start, end], coveredSpans))
757
+ return;
741
758
  coveredSpans.push([start, end]);
742
759
  entities.push({
743
760
  text: captured.trim(),
@@ -785,9 +802,7 @@ var NERExtractor = class {
785
802
  */
786
803
  postProcess(entities) {
787
804
  const typeSet = new Set(this.entityTypes);
788
- let filtered = entities.filter(
789
- (e) => typeSet.has(e.type) && e.confidence >= this.minConfidence
790
- );
805
+ let filtered = entities.filter((e) => typeSet.has(e.type) && e.confidence >= this.minConfidence);
791
806
  const seen = /* @__PURE__ */ new Map();
792
807
  for (const entity of filtered) {
793
808
  const key = `${entity.type}::${entity.text.toLowerCase().trim()}`;
@@ -798,14 +813,15 @@ var NERExtractor = class {
798
813
  }
799
814
  filtered = [...seen.values()];
800
815
  filtered.sort((a, b) => {
801
- if (b.confidence !== a.confidence) return b.confidence - a.confidence;
816
+ if (b.confidence !== a.confidence)
817
+ return b.confidence - a.confidence;
802
818
  return a.span[0] - b.span[0];
803
819
  });
804
820
  return filtered.slice(0, this.maxEntities);
805
821
  }
806
822
  };
807
823
 
808
- // ../chitragupta/packages/smriti/src/bitemporal.ts
824
+ // ../chitragupta/packages/smriti/dist/bitemporal.js
809
825
  function nowISO() {
810
826
  return (/* @__PURE__ */ new Date()).toISOString();
811
827
  }
@@ -846,14 +862,19 @@ function expireEdge(edge, validUntil) {
846
862
  function queryEdgesAtTime(edges, asOfValid, asOfRecord) {
847
863
  return edges.filter((e) => {
848
864
  const vFrom = e.validFrom ?? EPOCH_ISO;
849
- if (vFrom > asOfValid) return false;
850
- if (e.validUntil !== void 0 && e.validUntil <= asOfValid) return false;
865
+ if (vFrom > asOfValid)
866
+ return false;
867
+ if (e.validUntil !== void 0 && e.validUntil <= asOfValid)
868
+ return false;
851
869
  if (asOfRecord !== void 0) {
852
870
  const rAt = e.recordedAt ?? EPOCH_ISO;
853
- if (rAt > asOfRecord) return false;
854
- if (e.supersededAt !== void 0 && e.supersededAt <= asOfRecord) return false;
871
+ if (rAt > asOfRecord)
872
+ return false;
873
+ if (e.supersededAt !== void 0 && e.supersededAt <= asOfRecord)
874
+ return false;
855
875
  } else {
856
- if (e.supersededAt !== void 0) return false;
876
+ if (e.supersededAt !== void 0)
877
+ return false;
857
878
  }
858
879
  return true;
859
880
  });
@@ -864,19 +885,21 @@ function getEdgeHistory(edges, source, target) {
864
885
  function temporalDecay(edge, now, halfLifeMs) {
865
886
  const referenceTime = edge.validUntil !== void 0 ? new Date(edge.validUntil).getTime() : new Date(edge.validFrom ?? EPOCH_ISO).getTime();
866
887
  const elapsed = now - referenceTime;
867
- if (elapsed <= 0) return edge.weight;
888
+ if (elapsed <= 0)
889
+ return edge.weight;
868
890
  const decay = Math.exp(-Math.LN2 * elapsed / halfLifeMs);
869
891
  return edge.weight * decay;
870
892
  }
871
893
  function compactEdges(edges, retentionMs) {
872
894
  const cutoff = Date.now() - retentionMs;
873
895
  return edges.filter((e) => {
874
- if (e.supersededAt === void 0) return true;
896
+ if (e.supersededAt === void 0)
897
+ return true;
875
898
  return new Date(e.supersededAt).getTime() > cutoff;
876
899
  });
877
900
  }
878
901
 
879
- // ../chitragupta/packages/smriti/src/graphrag-builder.ts
902
+ // ../chitragupta/packages/smriti/dist/graphrag-builder.js
880
903
  function scopeToId(scope) {
881
904
  switch (scope.type) {
882
905
  case "global":
@@ -921,7 +944,8 @@ async function createSessionNode(ctx, session) {
921
944
  async function extractConceptsFromNodes(ctx, nodes, edges) {
922
945
  const entityIndex = /* @__PURE__ */ new Map();
923
946
  for (const node of nodes) {
924
- if (!node.content || node.type === "concept") continue;
947
+ if (!node.content || node.type === "concept")
948
+ continue;
925
949
  const entities = await ctx.extractEntities(node.content);
926
950
  for (const entity of entities) {
927
951
  const key = entity.name.toLowerCase();
@@ -937,9 +961,11 @@ async function extractConceptsFromNodes(ctx, nodes, edges) {
937
961
  }
938
962
  }
939
963
  for (const [key, data] of entityIndex) {
940
- if (data.sourceIds.length < 2) continue;
964
+ if (data.sourceIds.length < 2)
965
+ continue;
941
966
  const conceptId = `concept-${key.replace(/\s+/g, "-")}`;
942
- if (nodes.some((n) => n.id === conceptId)) continue;
967
+ if (nodes.some((n) => n.id === conceptId))
968
+ continue;
943
969
  const conceptNode = {
944
970
  id: conceptId,
945
971
  type: "concept",
@@ -1106,33 +1132,21 @@ function removeSessionFromGraph(graph, sessionId) {
1106
1132
  }
1107
1133
  }
1108
1134
  graph.nodes = graph.nodes.filter((n) => !nodeIdsToRemove.has(n.id));
1109
- graph.edges = graph.edges.filter(
1110
- (e) => !nodeIdsToRemove.has(e.source) && !nodeIdsToRemove.has(e.target)
1111
- );
1135
+ graph.edges = graph.edges.filter((e) => !nodeIdsToRemove.has(e.source) && !nodeIdsToRemove.has(e.target));
1112
1136
  }
1113
1137
  function removeMemoryFromGraph(graph, scope) {
1114
1138
  const memoryId = scopeToId(scope);
1115
- graph.nodes = graph.nodes.filter(
1116
- (n) => n.id !== memoryId && !n.id.startsWith(`${memoryId}-chunk-`)
1117
- );
1118
- graph.edges = graph.edges.filter(
1119
- (e) => e.source !== memoryId && e.target !== memoryId && !e.source.startsWith(`${memoryId}-chunk-`) && !e.target.startsWith(`${memoryId}-chunk-`)
1120
- );
1139
+ graph.nodes = graph.nodes.filter((n) => n.id !== memoryId && !n.id.startsWith(`${memoryId}-chunk-`));
1140
+ graph.edges = graph.edges.filter((e) => e.source !== memoryId && e.target !== memoryId && !e.source.startsWith(`${memoryId}-chunk-`) && !e.target.startsWith(`${memoryId}-chunk-`));
1121
1141
  }
1122
1142
 
1123
- // ../chitragupta/packages/smriti/src/graphrag-leiden.ts
1124
- var DEFAULT_LEIDEN_CONFIG = {
1125
- resolution: 1,
1126
- maxIterations: 10,
1127
- minModularityGain: 1e-6,
1128
- seed: 42,
1129
- minCommunitySize: 1
1130
- };
1143
+ // ../chitragupta/packages/smriti/dist/leiden-algorithm.js
1131
1144
  var Xorshift32 = class {
1132
1145
  state;
1133
1146
  constructor(seed) {
1134
1147
  this.state = seed | 0 || 1;
1135
1148
  }
1149
+ /** Generate next pseudo-random number in [0, 1). */
1136
1150
  next() {
1137
1151
  let x = this.state;
1138
1152
  x ^= x << 13;
@@ -1143,17 +1157,17 @@ var Xorshift32 = class {
1143
1157
  }
1144
1158
  };
1145
1159
  var AdjacencyGraph = class {
1146
- /** nodeIndex Map<neighborIndex, weight> */
1160
+ /** nodeIndex -> Map<neighborIndex, weight> */
1147
1161
  adj;
1148
- /** nodeIndex weighted degree (sum of edge weights) */
1162
+ /** nodeIndex -> weighted degree (sum of edge weights) */
1149
1163
  degree;
1150
1164
  /** Total edge weight (2m). */
1151
1165
  totalWeight;
1152
1166
  /** Number of nodes. */
1153
1167
  n;
1154
- /** Node ID index mapping. */
1168
+ /** Node ID -> index mapping. */
1155
1169
  idToIndex;
1156
- /** Index node ID mapping. */
1170
+ /** Index -> node ID mapping. */
1157
1171
  indexToId;
1158
1172
  constructor(graph) {
1159
1173
  const nodeIds = graph.nodes.map((n) => n.id);
@@ -1169,8 +1183,10 @@ var AdjacencyGraph = class {
1169
1183
  for (const edge of graph.edges) {
1170
1184
  const s = this.idToIndex.get(edge.source);
1171
1185
  const t = this.idToIndex.get(edge.target);
1172
- if (s === void 0 || t === void 0) continue;
1173
- if (s === t) continue;
1186
+ if (s === void 0 || t === void 0)
1187
+ continue;
1188
+ if (s === t)
1189
+ continue;
1174
1190
  const w = edge.weight ?? 1;
1175
1191
  this.adj[s].set(t, (this.adj[s].get(t) ?? 0) + w);
1176
1192
  this.adj[t].set(s, (this.adj[t].get(s) ?? 0) + w);
@@ -1183,7 +1199,8 @@ var AdjacencyGraph = class {
1183
1199
  };
1184
1200
  function computeModularity(g, assignment, resolution) {
1185
1201
  const twoM = g.totalWeight;
1186
- if (twoM === 0) return 0;
1202
+ if (twoM === 0)
1203
+ return 0;
1187
1204
  const internalWeight = /* @__PURE__ */ new Map();
1188
1205
  const communityDegree = /* @__PURE__ */ new Map();
1189
1206
  for (let i = 0; i < g.n; i++) {
@@ -1205,15 +1222,19 @@ function computeModularity(g, assignment, resolution) {
1205
1222
  }
1206
1223
  function modularityGain(g, i, cNew, assignment, communityDegree, resolution) {
1207
1224
  const twoM = g.totalWeight;
1208
- if (twoM === 0) return 0;
1225
+ if (twoM === 0)
1226
+ return 0;
1209
1227
  const cOld = assignment[i];
1210
- if (cOld === cNew) return 0;
1228
+ if (cOld === cNew)
1229
+ return 0;
1211
1230
  const ki = g.degree[i];
1212
1231
  let kInNew = 0;
1213
1232
  let kInOld = 0;
1214
1233
  for (const [j, w] of g.adj[i]) {
1215
- if (assignment[j] === cNew) kInNew += w;
1216
- if (assignment[j] === cOld) kInOld += w;
1234
+ if (assignment[j] === cNew)
1235
+ kInNew += w;
1236
+ if (assignment[j] === cOld)
1237
+ kInOld += w;
1217
1238
  }
1218
1239
  const sigmaTotNew = communityDegree.get(cNew) ?? 0;
1219
1240
  const sigmaTotOld = communityDegree.get(cOld) ?? 0;
@@ -1243,7 +1264,8 @@ function localNodeMoving(g, assignment, resolution, rng) {
1243
1264
  let bestCommunity = cOld;
1244
1265
  let bestGain = 0;
1245
1266
  for (const cNew of neighborCommunities) {
1246
- if (cNew === cOld) continue;
1267
+ if (cNew === cOld)
1268
+ continue;
1247
1269
  const gain = modularityGain(g, i, cNew, assignment, communityDegree, resolution);
1248
1270
  if (gain > bestGain) {
1249
1271
  bestGain = gain;
@@ -1263,17 +1285,20 @@ function refineCommunities(g, assignment) {
1263
1285
  const communityNodes = /* @__PURE__ */ new Map();
1264
1286
  for (let i = 0; i < g.n; i++) {
1265
1287
  const c = assignment[i];
1266
- if (!communityNodes.has(c)) communityNodes.set(c, []);
1288
+ if (!communityNodes.has(c))
1289
+ communityNodes.set(c, []);
1267
1290
  communityNodes.get(c).push(i);
1268
1291
  }
1269
1292
  let nextCommunityId = Math.max(...assignment) + 1;
1270
1293
  for (const [_communityId, nodes] of communityNodes) {
1271
- if (nodes.length <= 1) continue;
1294
+ if (nodes.length <= 1)
1295
+ continue;
1272
1296
  const nodeSet = new Set(nodes);
1273
1297
  const visited = /* @__PURE__ */ new Set();
1274
1298
  const components = [];
1275
1299
  for (const start of nodes) {
1276
- if (visited.has(start)) continue;
1300
+ if (visited.has(start))
1301
+ continue;
1277
1302
  const component = [];
1278
1303
  const queue = [start];
1279
1304
  visited.add(start);
@@ -1329,6 +1354,15 @@ function compactCommunities(assignment, minSize) {
1329
1354
  }
1330
1355
  return assignment.map((c) => remap.get(c) ?? 0);
1331
1356
  }
1357
+
1358
+ // ../chitragupta/packages/smriti/dist/graphrag-leiden.js
1359
+ var DEFAULT_LEIDEN_CONFIG = {
1360
+ resolution: 1,
1361
+ maxIterations: 10,
1362
+ minModularityGain: 1e-6,
1363
+ seed: 42,
1364
+ minCommunitySize: 1
1365
+ };
1332
1366
  function leiden(graph, config) {
1333
1367
  const cfg = { ...DEFAULT_LEIDEN_CONFIG, ...config };
1334
1368
  if (graph.nodes.length === 0) {
@@ -1361,10 +1395,22 @@ function leiden(graph, config) {
1361
1395
  communities.set(g.indexToId[i], compacted[i]);
1362
1396
  }
1363
1397
  const finalModularity = computeModularity(g, compacted, cfg.resolution);
1398
+ const communityList = buildCommunityList(g, compacted, cfg.resolution);
1399
+ communityList.sort((a, b) => b.members.length - a.members.length);
1400
+ return {
1401
+ communities,
1402
+ communityList,
1403
+ modularity: finalModularity,
1404
+ iterations,
1405
+ levels: 1
1406
+ };
1407
+ }
1408
+ function buildCommunityList(g, compacted, resolution) {
1364
1409
  const communityNodes = /* @__PURE__ */ new Map();
1365
1410
  for (let i = 0; i < g.n; i++) {
1366
1411
  const c = compacted[i];
1367
- if (!communityNodes.has(c)) communityNodes.set(c, []);
1412
+ if (!communityNodes.has(c))
1413
+ communityNodes.set(c, []);
1368
1414
  communityNodes.get(c).push(g.indexToId[i]);
1369
1415
  }
1370
1416
  const communityList = [];
@@ -1383,11 +1429,10 @@ function leiden(graph, config) {
1383
1429
  const possibleEdges = members.length * (members.length - 1) / 2;
1384
1430
  const density = possibleEdges > 0 ? internalEdges / possibleEdges : 0;
1385
1431
  let ac = 0;
1386
- for (const mi of memberSet) {
1432
+ for (const mi of memberSet)
1387
1433
  ac += g.degree[mi];
1388
- }
1389
1434
  const twoM = g.totalWeight;
1390
- const communityMod = twoM > 0 ? 2 * internalWeight / twoM - cfg.resolution * (ac / twoM) ** 2 : 0;
1435
+ const communityMod = twoM > 0 ? 2 * internalWeight / twoM - resolution * (ac / twoM) ** 2 : 0;
1391
1436
  communityList.push({
1392
1437
  id,
1393
1438
  members,
@@ -1396,14 +1441,7 @@ function leiden(graph, config) {
1396
1441
  level: 0
1397
1442
  });
1398
1443
  }
1399
- communityList.sort((a, b) => b.members.length - a.members.length);
1400
- return {
1401
- communities,
1402
- communityList,
1403
- modularity: finalModularity,
1404
- iterations,
1405
- levels: 1
1406
- };
1444
+ return communityList;
1407
1445
  }
1408
1446
  function annotateCommunities(graph, result) {
1409
1447
  for (const node of graph.nodes) {
@@ -1414,20 +1452,13 @@ function annotateCommunities(graph, result) {
1414
1452
  }
1415
1453
  }
1416
1454
  function communitySummary(graph, communityId, maxLabels = 5) {
1417
- const members = graph.nodes.filter(
1418
- (n) => n.metadata.communityId === communityId
1419
- );
1455
+ const members = graph.nodes.filter((n) => n.metadata.communityId === communityId);
1420
1456
  const typeCount = {};
1421
1457
  for (const node of members) {
1422
1458
  typeCount[node.type] = (typeCount[node.type] ?? 0) + 1;
1423
1459
  }
1424
1460
  const labels = members.filter((n) => n.type === "concept" || n.type === "session").slice(0, maxLabels).map((n) => n.label);
1425
- return {
1426
- communityId,
1427
- labels,
1428
- nodeTypes: typeCount,
1429
- size: members.length
1430
- };
1461
+ return { communityId, labels, nodeTypes: typeCount, size: members.length };
1431
1462
  }
1432
1463
  function filterByCommunity(nodes, communityId) {
1433
1464
  return nodes.filter((n) => n.metadata.communityId === communityId);
@@ -1443,8 +1474,10 @@ function findBridgeNodes(graph, result, minCommunities = 2) {
1443
1474
  for (const edge of graph.edges) {
1444
1475
  const sc = result.communities.get(edge.source);
1445
1476
  const tc = result.communities.get(edge.target);
1446
- if (sc === void 0 || tc === void 0) continue;
1447
- if (sc === tc) continue;
1477
+ if (sc === void 0 || tc === void 0)
1478
+ continue;
1479
+ if (sc === tc)
1480
+ continue;
1448
1481
  touchedCommunities.get(edge.source)?.add(tc);
1449
1482
  touchedCommunities.get(edge.target)?.add(sc);
1450
1483
  }
@@ -1458,12 +1491,9 @@ function findBridgeNodes(graph, result, minCommunities = 2) {
1458
1491
  return bridges;
1459
1492
  }
1460
1493
 
1461
- // ../chitragupta/packages/smriti/src/graphrag.ts
1462
- var DEFAULT_CONFIG = {
1463
- endpoint: process.env.OLLAMA_HOST ?? "http://localhost:11434",
1464
- model: "nomic-embed-text",
1465
- generationModel: "llama3.2"
1466
- };
1494
+ // ../chitragupta/packages/smriti/dist/graphrag-persistence.js
1495
+ import fs from "fs";
1496
+ import path from "path";
1467
1497
  function getGraphDir() {
1468
1498
  return path.join(getChitraguptaHome(), "graphrag");
1469
1499
  }
@@ -1476,6 +1506,267 @@ function getEmbeddingsPath() {
1476
1506
  function getPageRankPath() {
1477
1507
  return path.join(getGraphDir(), "pagerank.json");
1478
1508
  }
1509
+ function getGraphDb(initialized, markInitialized) {
1510
+ try {
1511
+ const dbm = DatabaseManager.instance();
1512
+ if (!initialized) {
1513
+ initGraphSchema(dbm);
1514
+ markInitialized();
1515
+ }
1516
+ return dbm.get("graph");
1517
+ } catch {
1518
+ return null;
1519
+ }
1520
+ }
1521
+ function upsertNodeToDb(db, node) {
1522
+ db.prepare(`
1523
+ INSERT OR REPLACE INTO nodes (id, type, label, content, metadata, created_at, updated_at)
1524
+ VALUES (?, ?, ?, ?, ?, ?, ?)
1525
+ `).run(node.id, node.type, node.label, node.content, JSON.stringify(node.metadata), Date.now(), Date.now());
1526
+ }
1527
+ function insertEdgeToDb(db, edge) {
1528
+ db.prepare(`
1529
+ INSERT OR IGNORE INTO edges (source, target, relationship, weight, pramana, viveka,
1530
+ valid_from, valid_until, recorded_at, superseded_at)
1531
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
1532
+ `).run(edge.source, edge.target, edge.relationship, edge.weight, null, null, edge.validFrom ? new Date(edge.validFrom).getTime() : Date.now(), edge.validUntil ? new Date(edge.validUntil).getTime() : null, edge.recordedAt ? new Date(edge.recordedAt).getTime() : Date.now(), edge.supersededAt ? new Date(edge.supersededAt).getTime() : null);
1533
+ }
1534
+ function saveToSqlite(db, graph, pageRankScores, embeddingCache) {
1535
+ db.transaction(() => {
1536
+ db.prepare("DELETE FROM pagerank").run();
1537
+ db.prepare("DELETE FROM edges").run();
1538
+ db.prepare("DELETE FROM nodes").run();
1539
+ for (const node of graph.nodes)
1540
+ upsertNodeToDb(db, node);
1541
+ for (const edge of graph.edges)
1542
+ insertEdgeToDb(db, edge);
1543
+ for (const [nodeId, score] of pageRankScores) {
1544
+ db.prepare("INSERT OR REPLACE INTO pagerank (node_id, score, updated_at) VALUES (?, ?, ?)").run(nodeId, score, Date.now());
1545
+ }
1546
+ })();
1547
+ saveEmbeddingsJson(embeddingCache);
1548
+ }
1549
+ function loadFromSqlite(db) {
1550
+ const nodeCount = db.prepare("SELECT COUNT(*) as cnt FROM nodes").get().cnt;
1551
+ if (nodeCount === 0)
1552
+ return null;
1553
+ const nodeRows = db.prepare("SELECT * FROM nodes").all();
1554
+ const nodes = nodeRows.map((row) => ({
1555
+ id: row.id,
1556
+ type: row.type,
1557
+ label: row.label,
1558
+ content: row.content ?? "",
1559
+ metadata: (() => {
1560
+ try {
1561
+ return JSON.parse(row.metadata ?? "{}");
1562
+ } catch {
1563
+ return {};
1564
+ }
1565
+ })()
1566
+ }));
1567
+ const edgeRows = db.prepare("SELECT * FROM edges").all();
1568
+ const edges = edgeRows.map((row) => ({
1569
+ source: row.source,
1570
+ target: row.target,
1571
+ relationship: row.relationship,
1572
+ weight: row.weight,
1573
+ validFrom: row.valid_from ? new Date(row.valid_from).toISOString() : void 0,
1574
+ validUntil: row.valid_until ? new Date(row.valid_until).toISOString() : void 0,
1575
+ recordedAt: row.recorded_at ? new Date(row.recorded_at).toISOString() : void 0,
1576
+ supersededAt: row.superseded_at ? new Date(row.superseded_at).toISOString() : void 0
1577
+ }));
1578
+ const pageRankScores = /* @__PURE__ */ new Map();
1579
+ const prRows = db.prepare("SELECT * FROM pagerank").all();
1580
+ for (const row of prRows) {
1581
+ pageRankScores.set(row.node_id, row.score);
1582
+ }
1583
+ return { graph: { nodes, edges }, pageRankScores };
1584
+ }
1585
+ function migrateInMemoryToSqlite(db, graph, pageRankScores) {
1586
+ db.transaction(() => {
1587
+ for (const node of graph.nodes)
1588
+ upsertNodeToDb(db, node);
1589
+ for (const edge of graph.edges)
1590
+ insertEdgeToDb(db, edge);
1591
+ for (const [nodeId, score] of pageRankScores) {
1592
+ db.prepare("INSERT OR REPLACE INTO pagerank (node_id, score, updated_at) VALUES (?, ?, ?)").run(nodeId, score, Date.now());
1593
+ }
1594
+ })();
1595
+ }
1596
+ function saveToJson(graph, pageRankScores, embeddingCache) {
1597
+ try {
1598
+ const dir = getGraphDir();
1599
+ fs.mkdirSync(dir, { recursive: true });
1600
+ fs.writeFileSync(getGraphPath(), JSON.stringify(graph, null, " "), "utf-8");
1601
+ saveEmbeddingsJson(embeddingCache);
1602
+ const pageRankObj = {};
1603
+ for (const [key, value] of pageRankScores)
1604
+ pageRankObj[key] = value;
1605
+ fs.writeFileSync(getPageRankPath(), JSON.stringify(pageRankObj, null, " "), "utf-8");
1606
+ } catch {
1607
+ }
1608
+ }
1609
+ function loadFromJson() {
1610
+ let graph = { nodes: [], edges: [] };
1611
+ const pageRankScores = /* @__PURE__ */ new Map();
1612
+ try {
1613
+ const graphPath = getGraphPath();
1614
+ if (fs.existsSync(graphPath)) {
1615
+ graph = JSON.parse(fs.readFileSync(graphPath, "utf-8"));
1616
+ }
1617
+ } catch {
1618
+ graph = { nodes: [], edges: [] };
1619
+ }
1620
+ try {
1621
+ const prPath = getPageRankPath();
1622
+ if (fs.existsSync(prPath)) {
1623
+ const ranks = JSON.parse(fs.readFileSync(prPath, "utf-8"));
1624
+ for (const [key, value] of Object.entries(ranks))
1625
+ pageRankScores.set(key, value);
1626
+ }
1627
+ } catch {
1628
+ }
1629
+ return { graph, pageRankScores };
1630
+ }
1631
+ function saveEmbeddingsJson(embeddingCache) {
1632
+ try {
1633
+ const dir = getGraphDir();
1634
+ fs.mkdirSync(dir, { recursive: true });
1635
+ const embeddings = {};
1636
+ for (const [key, value] of embeddingCache)
1637
+ embeddings[key] = value;
1638
+ fs.writeFileSync(getEmbeddingsPath(), JSON.stringify(embeddings, null, " "), "utf-8");
1639
+ } catch {
1640
+ }
1641
+ }
1642
+ function loadEmbeddingsJson(maxCacheSize) {
1643
+ const cache = /* @__PURE__ */ new Map();
1644
+ try {
1645
+ const embPath = getEmbeddingsPath();
1646
+ if (fs.existsSync(embPath)) {
1647
+ const embeddings = JSON.parse(fs.readFileSync(embPath, "utf-8"));
1648
+ for (const [key, value] of Object.entries(embeddings))
1649
+ cache.set(key, value);
1650
+ while (cache.size > maxCacheSize) {
1651
+ const oldest = cache.keys().next().value;
1652
+ if (oldest !== void 0)
1653
+ cache.delete(oldest);
1654
+ }
1655
+ }
1656
+ } catch {
1657
+ }
1658
+ return cache;
1659
+ }
1660
+ function lookupPramana(db, nodeId) {
1661
+ if (!db)
1662
+ return "shabda";
1663
+ try {
1664
+ const row = db.prepare(`
1665
+ SELECT pramana, COUNT(*) as cnt FROM edges
1666
+ WHERE (source = ? OR target = ?) AND pramana IS NOT NULL
1667
+ GROUP BY pramana ORDER BY cnt DESC LIMIT 1
1668
+ `).get(nodeId, nodeId);
1669
+ if (row?.pramana)
1670
+ return row.pramana;
1671
+ } catch {
1672
+ }
1673
+ return "shabda";
1674
+ }
1675
+ function lookupPramanaBatch(db, nodeIds) {
1676
+ const result = /* @__PURE__ */ new Map();
1677
+ if (nodeIds.length === 0)
1678
+ return result;
1679
+ if (!db) {
1680
+ for (const id of nodeIds)
1681
+ result.set(id, "shabda");
1682
+ return result;
1683
+ }
1684
+ try {
1685
+ const placeholders = nodeIds.map(() => "?").join(",");
1686
+ const rows = db.prepare(`
1687
+ SELECT node_id, pramana FROM (
1688
+ SELECT source AS node_id, pramana, COUNT(*) AS cnt FROM edges
1689
+ WHERE source IN (${placeholders}) AND pramana IS NOT NULL
1690
+ GROUP BY source, pramana
1691
+ UNION ALL
1692
+ SELECT target AS node_id, pramana, COUNT(*) AS cnt FROM edges
1693
+ WHERE target IN (${placeholders}) AND pramana IS NOT NULL
1694
+ GROUP BY target, pramana
1695
+ ) GROUP BY node_id HAVING cnt = MAX(cnt)
1696
+ `).all(...nodeIds, ...nodeIds);
1697
+ for (const row of rows)
1698
+ result.set(row.node_id, row.pramana);
1699
+ } catch {
1700
+ }
1701
+ for (const id of nodeIds) {
1702
+ if (!result.has(id))
1703
+ result.set(id, "shabda");
1704
+ }
1705
+ return result;
1706
+ }
1707
+ function migrateGraphJson() {
1708
+ const graphPath = getGraphPath();
1709
+ const prPath = getPageRankPath();
1710
+ if (!fs.existsSync(graphPath))
1711
+ return { nodes: 0, edges: 0 };
1712
+ try {
1713
+ const graph = JSON.parse(fs.readFileSync(graphPath, "utf-8"));
1714
+ if (!graph.nodes || graph.nodes.length === 0)
1715
+ return { nodes: 0, edges: 0 };
1716
+ const pageRankScores = /* @__PURE__ */ new Map();
1717
+ try {
1718
+ if (fs.existsSync(prPath)) {
1719
+ const ranks = JSON.parse(fs.readFileSync(prPath, "utf-8"));
1720
+ for (const [key, value] of Object.entries(ranks))
1721
+ pageRankScores.set(key, value);
1722
+ }
1723
+ } catch {
1724
+ }
1725
+ const dbm = DatabaseManager.instance();
1726
+ initGraphSchema(dbm);
1727
+ const db = dbm.get("graph");
1728
+ db.transaction(() => {
1729
+ const upsertStmt = db.prepare(`
1730
+ INSERT OR REPLACE INTO nodes (id, type, label, content, metadata, created_at, updated_at)
1731
+ VALUES (?, ?, ?, ?, ?, ?, ?)
1732
+ `);
1733
+ const edgeStmt = db.prepare(`
1734
+ INSERT OR IGNORE INTO edges (source, target, relationship, weight, pramana, viveka,
1735
+ valid_from, valid_until, recorded_at, superseded_at)
1736
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
1737
+ `);
1738
+ const prStmt = db.prepare("INSERT OR REPLACE INTO pagerank (node_id, score, updated_at) VALUES (?, ?, ?)");
1739
+ const now = Date.now();
1740
+ for (const node of graph.nodes) {
1741
+ upsertStmt.run(node.id, node.type, node.label, node.content, JSON.stringify(node.metadata), now, now);
1742
+ }
1743
+ for (const edge of graph.edges) {
1744
+ edgeStmt.run(edge.source, edge.target, edge.relationship, edge.weight, null, null, edge.validFrom ? new Date(edge.validFrom).getTime() : now, edge.validUntil ? new Date(edge.validUntil).getTime() : null, edge.recordedAt ? new Date(edge.recordedAt).getTime() : now, edge.supersededAt ? new Date(edge.supersededAt).getTime() : null);
1745
+ }
1746
+ for (const [nodeId, score] of pageRankScores)
1747
+ prStmt.run(nodeId, score, now);
1748
+ })();
1749
+ try {
1750
+ fs.renameSync(graphPath, graphPath + ".bak");
1751
+ } catch {
1752
+ }
1753
+ try {
1754
+ if (fs.existsSync(prPath))
1755
+ fs.renameSync(prPath, prPath + ".bak");
1756
+ } catch {
1757
+ }
1758
+ return { nodes: graph.nodes.length, edges: graph.edges.length };
1759
+ } catch {
1760
+ return { nodes: 0, edges: 0 };
1761
+ }
1762
+ }
1763
+
1764
+ // ../chitragupta/packages/smriti/dist/graphrag.js
1765
+ var DEFAULT_CONFIG = {
1766
+ endpoint: process.env.OLLAMA_HOST ?? "http://localhost:11434",
1767
+ model: "nomic-embed-text",
1768
+ generationModel: "llama3.2"
1769
+ };
1479
1770
  var GraphRAGEngine = class {
1480
1771
  config;
1481
1772
  graph;
@@ -1484,9 +1775,9 @@ var GraphRAGEngine = class {
1484
1775
  maxEmbeddingCacheSize;
1485
1776
  ollamaAvailable = null;
1486
1777
  embeddingService;
1487
- /** Push-based incremental PageRank engine — avoids full recompute on edge changes. */
1778
+ /** Push-based incremental PageRank engine. */
1488
1779
  incrementalPR = null;
1489
- /** Whether the graph.db schema has been initialized in this process. */
1780
+ /** Whether graph.db schema has been initialized in this process. */
1490
1781
  _graphDbInitialized = false;
1491
1782
  constructor(config) {
1492
1783
  this.config = { ...DEFAULT_CONFIG, ...config };
@@ -1497,9 +1788,9 @@ var GraphRAGEngine = class {
1497
1788
  this.embeddingService = config?.embeddingService ?? new EmbeddingService();
1498
1789
  this.loadFromDisk();
1499
1790
  }
1500
- // ─── Ollama Availability (for entity extraction) ──────────────────
1501
1791
  async checkOllamaAvailability() {
1502
- if (this.ollamaAvailable !== null) return this.ollamaAvailable;
1792
+ if (this.ollamaAvailable !== null)
1793
+ return this.ollamaAvailable;
1503
1794
  try {
1504
1795
  const response = await fetch(`${this.config.endpoint}/api/version`, {
1505
1796
  method: "GET",
@@ -1511,24 +1802,25 @@ var GraphRAGEngine = class {
1511
1802
  }
1512
1803
  return this.ollamaAvailable;
1513
1804
  }
1805
+ /** Get (or compute and cache) an embedding vector for the given text. */
1514
1806
  async getEmbedding(text) {
1515
1807
  const cached = this.embeddingCache.get(text);
1516
- if (cached) return cached;
1808
+ if (cached)
1809
+ return cached;
1517
1810
  const vector = await this.embeddingService.getEmbedding(text);
1518
1811
  this.embeddingCache.set(text, vector);
1519
1812
  if (this.embeddingCache.size > this.maxEmbeddingCacheSize) {
1520
1813
  const oldest = this.embeddingCache.keys().next().value;
1521
- if (oldest !== void 0) {
1814
+ if (oldest !== void 0)
1522
1815
  this.embeddingCache.delete(oldest);
1523
- }
1524
1816
  }
1525
1817
  return vector;
1526
1818
  }
1527
- // ─── Cosine Similarity (delegate) ──────────────────────────────────
1819
+ /** Compute cosine similarity between two vectors. */
1528
1820
  cosineSimilarity(a, b) {
1529
1821
  return cosineSimilarity(a, b);
1530
1822
  }
1531
- // ─── Entity Extraction (delegates) ─────────────────────────────────
1823
+ /** Extract named entities from text using LLM (with keyword + NER fallback). */
1532
1824
  async extractEntities(text) {
1533
1825
  const isAvailable = await this.checkOllamaAvailability();
1534
1826
  let baseEntities;
@@ -1573,46 +1865,31 @@ var GraphRAGEngine = class {
1573
1865
  return baseEntities;
1574
1866
  }
1575
1867
  // ─── Incremental PageRank ────────────────────────────────────────
1576
- /**
1577
- * Initialize (or reinitialize) the incremental PageRank engine from
1578
- * the current graph state. Performs one full Gauss-Seidel computation
1579
- * internally, then subsequent edge changes are O(1/ε) each via
1580
- * push-based residual propagation.
1581
- */
1868
+ /** Initialize incremental PageRank from current graph state. */
1582
1869
  initIncrementalPR() {
1583
1870
  this.incrementalPR = new IncrementalPageRank();
1584
1871
  this.incrementalPR.initialize(this.graph);
1585
1872
  this.pageRankScores = this.incrementalPR.getRanks();
1586
1873
  }
1587
- /**
1588
- * Feed removed edges into the incremental PR engine so it can adjust
1589
- * scores via residual propagation rather than a full recompute.
1590
- */
1874
+ /** Feed removed edges into incremental PR engine. */
1591
1875
  applyEdgeRemovals(edges) {
1592
- if (!this.incrementalPR || edges.length === 0) return;
1593
- for (const edge of edges) {
1876
+ if (!this.incrementalPR || edges.length === 0)
1877
+ return;
1878
+ for (const edge of edges)
1594
1879
  this.incrementalPR.removeEdge(edge.source, edge.target);
1595
- }
1596
1880
  this.pageRankScores = this.incrementalPR.getRanks();
1597
1881
  }
1598
- /**
1599
- * Feed newly added edges into the incremental PR engine.
1600
- */
1882
+ /** Feed newly added edges into incremental PR engine. */
1601
1883
  applyEdgeAdditions(edges) {
1602
- if (!this.incrementalPR || edges.length === 0) return;
1603
- for (const edge of edges) {
1884
+ if (!this.incrementalPR || edges.length === 0)
1885
+ return;
1886
+ for (const edge of edges)
1604
1887
  this.incrementalPR.addEdge(edge.source, edge.target);
1605
- }
1606
1888
  this.pageRankScores = this.incrementalPR.getRanks();
1607
1889
  }
1608
- // ─── PageRank (delegates) ──────────────────────────────────────────
1609
1890
  /**
1610
- * Compute PageRank for the given graph (or the internal graph if none provided).
1611
- *
1612
- * When called with an explicit graph argument, uses the full power-iteration
1613
- * algorithm (useful for one-off computations on external graphs and tests).
1614
- * When called without arguments, initializes the incremental PageRank engine
1615
- * on the internal graph.
1891
+ * Compute PageRank. With an explicit graph argument uses full power-iteration;
1892
+ * without arguments initializes the incremental engine on the internal graph.
1616
1893
  */
1617
1894
  computePageRank(graph) {
1618
1895
  if (graph) {
@@ -1622,82 +1899,75 @@ var GraphRAGEngine = class {
1622
1899
  this.initIncrementalPR();
1623
1900
  return this.pageRankScores;
1624
1901
  }
1902
+ /** Get the PageRank score for a node. Returns 0 if not computed. */
1625
1903
  getPageRank(nodeId) {
1626
1904
  return this.pageRankScores.get(nodeId) ?? 0;
1627
1905
  }
1628
- /**
1629
- * Force a full PageRank recompute from the current graph state.
1630
- * Reinitializes the incremental engine from scratch. Useful after
1631
- * graph compaction or any structural change that bypasses the
1632
- * normal indexSession/indexMemory paths.
1633
- */
1906
+ /** Force a full PageRank recompute and persist. */
1634
1907
  recomputePageRank() {
1635
1908
  this.initIncrementalPR();
1636
1909
  this.saveToDisk();
1637
1910
  }
1638
1911
  // ─── Graph Building ───────────────────────────────────────────────
1912
+ /** Build a full knowledge graph from sessions and memories. */
1639
1913
  async buildGraph(sessions, memories) {
1640
1914
  const nodes = [];
1641
1915
  const edges = [];
1642
1916
  for (const session of sessions) {
1643
- const sessionNode = await createSessionNode(this, session);
1644
- nodes.push(sessionNode);
1917
+ nodes.push(await createSessionNode(this, session));
1645
1918
  await indexSessionTurns(this, session, nodes, edges);
1646
1919
  }
1647
- for (const memory of memories) {
1920
+ for (const memory of memories)
1648
1921
  await buildMemoryNodes(this, memory, nodes, edges);
1649
- }
1650
1922
  await extractConceptsFromNodes(this, nodes, edges);
1651
1923
  this.graph = { nodes, edges };
1652
1924
  if (this.graph.nodes.length > 0 && this.graph.edges.length > 0) {
1653
- const leidenResult = leiden(this.graph);
1654
- annotateCommunities(this.graph, leidenResult);
1925
+ annotateCommunities(this.graph, leiden(this.graph));
1655
1926
  }
1656
1927
  this.initIncrementalPR();
1657
1928
  this.saveToDisk();
1658
1929
  return this.graph;
1659
1930
  }
1660
1931
  // ─── Hybrid Search ───────────────────────────────────────────────
1932
+ /** Search the knowledge graph using hybrid scoring (cosine + PageRank + BM25). */
1661
1933
  async search(query, graph, topK = 10) {
1662
1934
  const searchGraph = graph ?? this.graph;
1663
- if (searchGraph.nodes.length === 0) return [];
1935
+ if (searchGraph.nodes.length === 0)
1936
+ return [];
1664
1937
  const queryEmbedding = await this.getEmbedding(query);
1665
- if (this.pageRankScores.size === 0) {
1938
+ if (this.pageRankScores.size === 0)
1666
1939
  this.computePageRank(searchGraph);
1667
- }
1668
1940
  let maxPageRank = 0;
1669
1941
  for (const node of searchGraph.nodes) {
1670
1942
  const pr = this.pageRankScores.get(node.id) ?? 0;
1671
- if (pr > maxPageRank) maxPageRank = pr;
1943
+ if (pr > maxPageRank)
1944
+ maxPageRank = pr;
1672
1945
  }
1673
1946
  const scored = [];
1674
1947
  for (const node of searchGraph.nodes) {
1675
1948
  let cosineSim = 0;
1676
1949
  if (node.embedding && node.embedding.length > 0) {
1677
- cosineSim = cosineSimilarity(queryEmbedding, node.embedding);
1678
- cosineSim = Math.max(0, cosineSim);
1950
+ cosineSim = Math.max(0, cosineSimilarity(queryEmbedding, node.embedding));
1679
1951
  }
1680
- const rawPageRank = this.pageRankScores.get(node.id) ?? 0;
1681
- const normalizedPageRank = maxPageRank > 0 ? rawPageRank / maxPageRank : 0;
1952
+ const rawPR = this.pageRankScores.get(node.id) ?? 0;
1953
+ const normPR = maxPageRank > 0 ? rawPR / maxPageRank : 0;
1682
1954
  const textScore = textMatchScore(query, node.content + " " + node.label);
1683
- const finalScore = ALPHA * cosineSim + BETA * normalizedPageRank + GAMMA * textScore;
1684
- if (finalScore > 0) {
1955
+ const finalScore = ALPHA * cosineSim + BETA * normPR + GAMMA * textScore;
1956
+ if (finalScore > 0)
1685
1957
  scored.push({ node, score: finalScore });
1686
- }
1687
1958
  }
1688
1959
  scored.sort((a, b) => b.score - a.score);
1689
1960
  return scored.slice(0, topK).map((s) => s.node);
1690
1961
  }
1691
1962
  // ─── Incremental Indexing ─────────────────────────────────────────
1963
+ /** Index a single session incrementally. */
1692
1964
  async indexSession(session) {
1693
1965
  const edgesBefore = [...this.graph.edges];
1694
1966
  removeSessionFromGraph(this.graph, session.meta.id);
1695
- const edgesAfterRemoval = this.graph.edges;
1696
- const edgesAfterSet = new Set(edgesAfterRemoval);
1967
+ const edgesAfterSet = new Set(this.graph.edges);
1697
1968
  const removedEdges = edgesBefore.filter((e) => !edgesAfterSet.has(e));
1698
1969
  const edgeCountBeforeAdd = this.graph.edges.length;
1699
- const sessionNode = await createSessionNode(this, session);
1700
- this.graph.nodes.push(sessionNode);
1970
+ this.graph.nodes.push(await createSessionNode(this, session));
1701
1971
  await indexSessionTurns(this, session, this.graph.nodes, this.graph.edges);
1702
1972
  const newEdges = this.graph.edges.slice(edgeCountBeforeAdd);
1703
1973
  if (!this.incrementalPR) {
@@ -1708,11 +1978,11 @@ var GraphRAGEngine = class {
1708
1978
  }
1709
1979
  this.saveToDisk();
1710
1980
  }
1981
+ /** Index a memory scope incrementally. */
1711
1982
  async indexMemory(scope, content) {
1712
1983
  const edgesBefore = [...this.graph.edges];
1713
1984
  removeMemoryFromGraph(this.graph, scope);
1714
- const edgesAfterRemoval = this.graph.edges;
1715
- const edgesAfterSet = new Set(edgesAfterRemoval);
1985
+ const edgesAfterSet = new Set(this.graph.edges);
1716
1986
  const removedEdges = edgesBefore.filter((e) => !edgesAfterSet.has(e));
1717
1987
  const edgeCountBeforeAdd = this.graph.edges.length;
1718
1988
  await buildMemoryNodesFromContent(this, scope, content, this.graph.nodes, this.graph.edges);
@@ -1725,422 +1995,111 @@ var GraphRAGEngine = class {
1725
1995
  }
1726
1996
  this.saveToDisk();
1727
1997
  }
1728
- // ─── Pramana Lookup ──────────────────────────────────────────────
1729
- /**
1730
- * Look up the dominant pramana type for a given node ID.
1731
- *
1732
- * Queries the edges table for edges involving this node (as source or target)
1733
- * and returns the most common non-null pramana value. Falls back to 'shabda'
1734
- * (testimony/documentation) if no pramana data is found.
1735
- *
1736
- * @param nodeId - The graph node ID to look up.
1737
- * @returns The dominant PramanaType for this node.
1738
- */
1998
+ // ─── Pramana Lookup (delegates) ──────────────────────────────────
1999
+ /** Look up the dominant pramana type for a given node ID. */
1739
2000
  lookupPramana(nodeId) {
1740
- const db = this.getGraphDb();
1741
- if (!db) return "shabda";
1742
- try {
1743
- const row = db.prepare(`
1744
- SELECT pramana, COUNT(*) as cnt
1745
- FROM edges
1746
- WHERE (source = ? OR target = ?) AND pramana IS NOT NULL
1747
- GROUP BY pramana
1748
- ORDER BY cnt DESC
1749
- LIMIT 1
1750
- `).get(nodeId, nodeId);
1751
- if (row?.pramana) return row.pramana;
1752
- } catch {
1753
- }
1754
- return "shabda";
2001
+ return lookupPramana(this.getGraphDbHandle(), nodeId);
1755
2002
  }
1756
- /**
1757
- * Batch look up pramana types for multiple node IDs.
1758
- *
1759
- * More efficient than calling lookupPramana() individually for each node.
1760
- * Returns a Map from node ID to PramanaType. Missing entries default to 'shabda'.
1761
- *
1762
- * @param nodeIds - Array of node IDs to look up.
1763
- * @returns Map from node ID to its dominant PramanaType.
1764
- */
2003
+ /** Batch look up pramana types for multiple node IDs. */
1765
2004
  lookupPramanaBatch(nodeIds) {
1766
- const result = /* @__PURE__ */ new Map();
1767
- if (nodeIds.length === 0) return result;
1768
- const db = this.getGraphDb();
1769
- if (!db) {
1770
- for (const id of nodeIds) result.set(id, "shabda");
1771
- return result;
1772
- }
1773
- try {
1774
- const placeholders = nodeIds.map(() => "?").join(",");
1775
- const rows = db.prepare(`
1776
- SELECT node_id, pramana FROM (
1777
- SELECT source AS node_id, pramana, COUNT(*) AS cnt
1778
- FROM edges
1779
- WHERE source IN (${placeholders}) AND pramana IS NOT NULL
1780
- GROUP BY source, pramana
1781
- UNION ALL
1782
- SELECT target AS node_id, pramana, COUNT(*) AS cnt
1783
- FROM edges
1784
- WHERE target IN (${placeholders}) AND pramana IS NOT NULL
1785
- GROUP BY target, pramana
1786
- )
1787
- GROUP BY node_id
1788
- HAVING cnt = MAX(cnt)
1789
- `).all(...nodeIds, ...nodeIds);
1790
- for (const row of rows) {
1791
- result.set(row.node_id, row.pramana);
1792
- }
1793
- } catch {
1794
- }
1795
- for (const id of nodeIds) {
1796
- if (!result.has(id)) result.set(id, "shabda");
1797
- }
1798
- return result;
2005
+ return lookupPramanaBatch(this.getGraphDbHandle(), nodeIds);
1799
2006
  }
1800
- // ─── SQLite Persistence Helpers ─────────────────────────────────
1801
- /**
1802
- * Get the graph database handle, initializing the schema on first access.
1803
- * Returns null if the database layer is unavailable (e.g. mocked fs in tests).
1804
- */
1805
- getGraphDb() {
1806
- try {
1807
- const dbm = DatabaseManager.instance();
1808
- if (!this._graphDbInitialized) {
1809
- initGraphSchema(dbm);
1810
- this._graphDbInitialized = true;
1811
- }
1812
- return dbm.get("graph");
1813
- } catch {
1814
- return null;
1815
- }
1816
- }
1817
- /** Insert or replace a node in the SQLite nodes table. */
1818
- upsertNode(db, node) {
1819
- db.prepare(`
1820
- INSERT OR REPLACE INTO nodes (id, type, label, content, metadata, created_at, updated_at)
1821
- VALUES (?, ?, ?, ?, ?, ?, ?)
1822
- `).run(
1823
- node.id,
1824
- node.type,
1825
- node.label,
1826
- node.content,
1827
- JSON.stringify(node.metadata),
1828
- Date.now(),
1829
- Date.now()
1830
- );
1831
- }
1832
- /** Insert an edge into the SQLite edges table (bi-temporal fields mapped). */
1833
- insertEdge(db, edge) {
1834
- db.prepare(`
1835
- INSERT OR IGNORE INTO edges (source, target, relationship, weight, pramana, viveka,
1836
- valid_from, valid_until, recorded_at, superseded_at)
1837
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
1838
- `).run(
1839
- edge.source,
1840
- edge.target,
1841
- edge.relationship,
1842
- edge.weight,
1843
- null,
1844
- // pramana — not yet used
1845
- null,
1846
- // viveka — not yet used
1847
- edge.validFrom ? new Date(edge.validFrom).getTime() : Date.now(),
1848
- edge.validUntil ? new Date(edge.validUntil).getTime() : null,
1849
- edge.recordedAt ? new Date(edge.recordedAt).getTime() : Date.now(),
1850
- edge.supersededAt ? new Date(edge.supersededAt).getTime() : null
1851
- );
1852
- }
1853
- // ─── Persistence ──────────────────────────────────────────────────
2007
+ // ─── Persistence (delegates) ─────────────────────────────────────
2008
+ /** Get graph database handle via persistence layer. */
2009
+ getGraphDbHandle() {
2010
+ return getGraphDb(this._graphDbInitialized, () => {
2011
+ this._graphDbInitialized = true;
2012
+ });
2013
+ }
2014
+ /** Save graph state to SQLite (primary) or JSON (fallback). */
1854
2015
  saveToDisk() {
1855
2016
  try {
1856
- const db = this.getGraphDb();
2017
+ const db = this.getGraphDbHandle();
1857
2018
  if (db) {
1858
- db.transaction(() => {
1859
- db.prepare("DELETE FROM pagerank").run();
1860
- db.prepare("DELETE FROM edges").run();
1861
- db.prepare("DELETE FROM nodes").run();
1862
- for (const node of this.graph.nodes) {
1863
- this.upsertNode(db, node);
1864
- }
1865
- for (const edge of this.graph.edges) {
1866
- this.insertEdge(db, edge);
1867
- }
1868
- for (const [nodeId, score] of this.pageRankScores) {
1869
- db.prepare(
1870
- "INSERT OR REPLACE INTO pagerank (node_id, score, updated_at) VALUES (?, ?, ?)"
1871
- ).run(nodeId, score, Date.now());
1872
- }
1873
- })();
1874
- this.saveEmbeddingsJson();
2019
+ saveToSqlite(db, this.graph, this.pageRankScores, this.embeddingCache);
1875
2020
  return;
1876
2021
  }
1877
2022
  } catch {
1878
2023
  }
1879
- this.saveToDiskJson();
2024
+ saveToJson(this.graph, this.pageRankScores, this.embeddingCache);
1880
2025
  }
2026
+ /** Load graph state from SQLite (primary) or JSON (fallback). */
1881
2027
  loadFromDisk() {
1882
- let loadedFromSqlite = false;
2028
+ let loaded = false;
1883
2029
  try {
1884
- const db = this.getGraphDb();
2030
+ const db = this.getGraphDbHandle();
1885
2031
  if (db) {
1886
- const nodeCount = db.prepare("SELECT COUNT(*) as cnt FROM nodes").get().cnt;
1887
- if (nodeCount > 0) {
1888
- const nodeRows = db.prepare("SELECT * FROM nodes").all();
1889
- this.graph.nodes = nodeRows.map((row) => ({
1890
- id: row.id,
1891
- type: row.type,
1892
- label: row.label,
1893
- content: row.content ?? "",
1894
- metadata: (() => {
1895
- try {
1896
- return JSON.parse(row.metadata ?? "{}");
1897
- } catch {
1898
- return {};
1899
- }
1900
- })()
1901
- // Note: embedding not stored in nodes table — it's in vectors.db (Phase 0.6)
1902
- }));
1903
- const edgeRows = db.prepare("SELECT * FROM edges").all();
1904
- this.graph.edges = edgeRows.map((row) => ({
1905
- source: row.source,
1906
- target: row.target,
1907
- relationship: row.relationship,
1908
- weight: row.weight,
1909
- validFrom: row.valid_from ? new Date(row.valid_from).toISOString() : void 0,
1910
- validUntil: row.valid_until ? new Date(row.valid_until).toISOString() : void 0,
1911
- recordedAt: row.recorded_at ? new Date(row.recorded_at).toISOString() : void 0,
1912
- supersededAt: row.superseded_at ? new Date(row.superseded_at).toISOString() : void 0
1913
- }));
1914
- const prRows = db.prepare("SELECT * FROM pagerank").all();
1915
- for (const row of prRows) {
1916
- this.pageRankScores.set(row.node_id, row.score);
1917
- }
1918
- loadedFromSqlite = true;
2032
+ const sqliteData = loadFromSqlite(db);
2033
+ if (sqliteData) {
2034
+ this.graph = sqliteData.graph;
2035
+ this.pageRankScores = sqliteData.pageRankScores;
1919
2036
  } else {
1920
- this.loadFromDiskJson();
2037
+ const jsonData = loadFromJson();
2038
+ this.graph = jsonData.graph;
2039
+ this.pageRankScores = jsonData.pageRankScores;
1921
2040
  if (this.graph.nodes.length > 0) {
1922
2041
  try {
1923
- db.transaction(() => {
1924
- for (const node of this.graph.nodes) {
1925
- this.upsertNode(db, node);
1926
- }
1927
- for (const edge of this.graph.edges) {
1928
- this.insertEdge(db, edge);
1929
- }
1930
- for (const [nodeId, score] of this.pageRankScores) {
1931
- db.prepare(
1932
- "INSERT OR REPLACE INTO pagerank (node_id, score, updated_at) VALUES (?, ?, ?)"
1933
- ).run(nodeId, score, Date.now());
1934
- }
1935
- })();
2042
+ migrateInMemoryToSqlite(db, this.graph, this.pageRankScores);
1936
2043
  } catch {
1937
2044
  }
1938
2045
  }
1939
- loadedFromSqlite = true;
1940
2046
  }
2047
+ loaded = true;
1941
2048
  }
1942
2049
  } catch {
1943
2050
  }
1944
- if (!loadedFromSqlite) {
1945
- this.loadFromDiskJson();
1946
- }
1947
- this.loadEmbeddingsJson();
1948
- if (this.graph.edges.length > 0) {
1949
- this.initIncrementalPR();
1950
- }
1951
- }
1952
- // ─── JSON Fallback Persistence (legacy / migration) ───────────────
1953
- saveToDiskJson() {
1954
- try {
1955
- const dir = getGraphDir();
1956
- fs.mkdirSync(dir, { recursive: true });
1957
- fs.writeFileSync(getGraphPath(), JSON.stringify(this.graph, null, " "), "utf-8");
1958
- this.saveEmbeddingsJson();
1959
- const pageRankObj = {};
1960
- for (const [key, value] of this.pageRankScores) {
1961
- pageRankObj[key] = value;
1962
- }
1963
- fs.writeFileSync(getPageRankPath(), JSON.stringify(pageRankObj, null, " "), "utf-8");
1964
- } catch {
1965
- }
1966
- }
1967
- saveEmbeddingsJson() {
1968
- try {
1969
- const dir = getGraphDir();
1970
- fs.mkdirSync(dir, { recursive: true });
1971
- const embeddings = {};
1972
- for (const [key, value] of this.embeddingCache) {
1973
- embeddings[key] = value;
1974
- }
1975
- fs.writeFileSync(getEmbeddingsPath(), JSON.stringify(embeddings, null, " "), "utf-8");
1976
- } catch {
1977
- }
1978
- }
1979
- loadFromDiskJson() {
1980
- try {
1981
- const graphPath = getGraphPath();
1982
- if (fs.existsSync(graphPath)) {
1983
- const raw = fs.readFileSync(graphPath, "utf-8");
1984
- this.graph = JSON.parse(raw);
1985
- }
1986
- } catch {
1987
- this.graph = { nodes: [], edges: [] };
1988
- }
1989
- try {
1990
- const prPath = getPageRankPath();
1991
- if (fs.existsSync(prPath)) {
1992
- const raw = fs.readFileSync(prPath, "utf-8");
1993
- const ranks = JSON.parse(raw);
1994
- for (const [key, value] of Object.entries(ranks)) {
1995
- this.pageRankScores.set(key, value);
1996
- }
1997
- }
1998
- } catch {
1999
- this.pageRankScores = /* @__PURE__ */ new Map();
2051
+ if (!loaded) {
2052
+ const jsonData = loadFromJson();
2053
+ this.graph = jsonData.graph;
2054
+ this.pageRankScores = jsonData.pageRankScores;
2000
2055
  }
2001
- }
2002
- loadEmbeddingsJson() {
2003
- try {
2004
- const embPath = getEmbeddingsPath();
2005
- if (fs.existsSync(embPath)) {
2006
- const raw = fs.readFileSync(embPath, "utf-8");
2007
- const embeddings = JSON.parse(raw);
2008
- for (const [key, value] of Object.entries(embeddings)) {
2009
- this.embeddingCache.set(key, value);
2010
- }
2011
- while (this.embeddingCache.size > this.maxEmbeddingCacheSize) {
2012
- const oldest = this.embeddingCache.keys().next().value;
2013
- if (oldest !== void 0) {
2014
- this.embeddingCache.delete(oldest);
2015
- }
2016
- }
2017
- }
2018
- } catch {
2019
- this.embeddingCache = /* @__PURE__ */ new Map();
2056
+ for (const [k, v] of loadEmbeddingsJson(this.maxEmbeddingCacheSize)) {
2057
+ this.embeddingCache.set(k, v);
2020
2058
  }
2059
+ if (this.graph.edges.length > 0)
2060
+ this.initIncrementalPR();
2021
2061
  }
2062
+ /** Get the current in-memory knowledge graph. */
2022
2063
  getGraph() {
2023
2064
  return this.graph;
2024
2065
  }
2066
+ /** Clear all graph data, caches, and persisted state. */
2025
2067
  async clear() {
2026
2068
  this.graph = { nodes: [], edges: [] };
2027
2069
  this.embeddingCache = /* @__PURE__ */ new Map();
2028
2070
  this.pageRankScores = /* @__PURE__ */ new Map();
2029
2071
  this.incrementalPR = null;
2030
2072
  try {
2031
- const db = this.getGraphDb();
2032
- if (db) {
2073
+ const db = this.getGraphDbHandle();
2074
+ if (db)
2033
2075
  db.exec("DELETE FROM pagerank; DELETE FROM edges; DELETE FROM nodes;");
2034
- }
2035
2076
  } catch {
2036
2077
  }
2037
2078
  this.saveToDisk();
2038
2079
  }
2080
+ /** Reset the Ollama availability flag to force re-check. */
2039
2081
  resetAvailability() {
2040
2082
  this.ollamaAvailable = null;
2041
2083
  this.embeddingService.resetAvailability();
2042
2084
  }
2043
- // ─── Graph Neighbor Queries ───────────────────────────────────────
2044
2085
  /**
2045
2086
  * Get edges connected to a node, optionally filtered by direction.
2046
2087
  * Uses the in-memory graph for fast access.
2047
2088
  */
2048
2089
  getNeighbors(nodeId, direction = "both") {
2049
2090
  return this.graph.edges.filter((edge) => {
2050
- if (direction === "out") return edge.source === nodeId;
2051
- if (direction === "in") return edge.target === nodeId;
2091
+ if (direction === "out")
2092
+ return edge.source === nodeId;
2093
+ if (direction === "in")
2094
+ return edge.target === nodeId;
2052
2095
  return edge.source === nodeId || edge.target === nodeId;
2053
2096
  });
2054
2097
  }
2055
2098
  };
2056
- function migrateGraphJson() {
2057
- const graphPath = getGraphPath();
2058
- const prPath = getPageRankPath();
2059
- if (!fs.existsSync(graphPath)) {
2060
- return { nodes: 0, edges: 0 };
2061
- }
2062
- try {
2063
- const raw = fs.readFileSync(graphPath, "utf-8");
2064
- const graph = JSON.parse(raw);
2065
- if (!graph.nodes || graph.nodes.length === 0) {
2066
- return { nodes: 0, edges: 0 };
2067
- }
2068
- const pageRankScores = /* @__PURE__ */ new Map();
2069
- try {
2070
- if (fs.existsSync(prPath)) {
2071
- const prRaw = fs.readFileSync(prPath, "utf-8");
2072
- const ranks = JSON.parse(prRaw);
2073
- for (const [key, value] of Object.entries(ranks)) {
2074
- pageRankScores.set(key, value);
2075
- }
2076
- }
2077
- } catch {
2078
- }
2079
- const dbm = DatabaseManager.instance();
2080
- initGraphSchema(dbm);
2081
- const db = dbm.get("graph");
2082
- db.transaction(() => {
2083
- const upsertNodeStmt = db.prepare(`
2084
- INSERT OR REPLACE INTO nodes (id, type, label, content, metadata, created_at, updated_at)
2085
- VALUES (?, ?, ?, ?, ?, ?, ?)
2086
- `);
2087
- const insertEdgeStmt = db.prepare(`
2088
- INSERT OR IGNORE INTO edges (source, target, relationship, weight, pramana, viveka,
2089
- valid_from, valid_until, recorded_at, superseded_at)
2090
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
2091
- `);
2092
- const upsertPRStmt = db.prepare(
2093
- "INSERT OR REPLACE INTO pagerank (node_id, score, updated_at) VALUES (?, ?, ?)"
2094
- );
2095
- const now = Date.now();
2096
- for (const node of graph.nodes) {
2097
- upsertNodeStmt.run(
2098
- node.id,
2099
- node.type,
2100
- node.label,
2101
- node.content,
2102
- JSON.stringify(node.metadata),
2103
- now,
2104
- now
2105
- );
2106
- }
2107
- for (const edge of graph.edges) {
2108
- insertEdgeStmt.run(
2109
- edge.source,
2110
- edge.target,
2111
- edge.relationship,
2112
- edge.weight,
2113
- null,
2114
- null,
2115
- edge.validFrom ? new Date(edge.validFrom).getTime() : now,
2116
- edge.validUntil ? new Date(edge.validUntil).getTime() : null,
2117
- edge.recordedAt ? new Date(edge.recordedAt).getTime() : now,
2118
- edge.supersededAt ? new Date(edge.supersededAt).getTime() : null
2119
- );
2120
- }
2121
- for (const [nodeId, score] of pageRankScores) {
2122
- upsertPRStmt.run(nodeId, score, now);
2123
- }
2124
- })();
2125
- try {
2126
- fs.renameSync(graphPath, graphPath + ".bak");
2127
- } catch {
2128
- }
2129
- try {
2130
- if (fs.existsSync(prPath)) {
2131
- fs.renameSync(prPath, prPath + ".bak");
2132
- }
2133
- } catch {
2134
- }
2135
- return { nodes: graph.nodes.length, edges: graph.edges.length };
2136
- } catch {
2137
- return { nodes: 0, edges: 0 };
2138
- }
2139
- }
2140
2099
 
2141
2100
  export {
2142
- computePersonalizedPageRank,
2143
2101
  IncrementalPageRank,
2102
+ computePersonalizedPageRank,
2144
2103
  NERExtractor,
2145
2104
  createEdge,
2146
2105
  supersedEdge,
@@ -2154,7 +2113,7 @@ export {
2154
2113
  communitySummary,
2155
2114
  filterByCommunity,
2156
2115
  findBridgeNodes,
2157
- GraphRAGEngine,
2158
- migrateGraphJson
2116
+ migrateGraphJson,
2117
+ GraphRAGEngine
2159
2118
  };
2160
- //# sourceMappingURL=chunk-S2HDNNC7.js.map
2119
+ //# sourceMappingURL=chunk-LJUEMPLG.js.map