@zabaca/lattice 1.0.20 → 1.0.22

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 (2) hide show
  1. package/dist/main.js +42 -137
  2. package/package.json +1 -1
package/dist/main.js CHANGED
@@ -989,29 +989,6 @@ class GraphService {
989
989
  return [];
990
990
  }
991
991
  }
992
- async findNodesWithMissingEmbeddings(labels) {
993
- try {
994
- const conn = await this.ensureConnected();
995
- const labelFilter = labels.map((l) => `'${this.escape(l)}'`).join(", ");
996
- const reader = await conn.runAndReadAll(`
997
- SELECT label, name, properties->>'description' as description
998
- FROM nodes
999
- WHERE label IN (${labelFilter})
1000
- AND embedding IS NULL
1001
- `);
1002
- return reader.getRows().map((row) => {
1003
- const [label, name, description] = row;
1004
- return {
1005
- label,
1006
- name,
1007
- description: description || undefined
1008
- };
1009
- });
1010
- } catch (error) {
1011
- this.logger.error(`Failed to find nodes with missing embeddings: ${error instanceof Error ? error.message : String(error)}`);
1012
- return [];
1013
- }
1014
- }
1015
992
  }
1016
993
  GraphService = __legacyDecorateClassTS([
1017
994
  Injectable4(),
@@ -1312,13 +1289,18 @@ class VoyageEmbeddingProvider {
1312
1289
  class EmbeddingService {
1313
1290
  configService;
1314
1291
  logger = new Logger3(EmbeddingService.name);
1315
- provider;
1292
+ provider = null;
1316
1293
  config;
1317
1294
  constructor(configService) {
1318
1295
  this.configService = configService;
1319
1296
  this.config = this.loadConfig();
1320
- this.provider = this.createProvider();
1321
- this.logger.log(`Initialized embedding service with provider: ${this.provider.name}`);
1297
+ }
1298
+ getProvider() {
1299
+ if (!this.provider) {
1300
+ this.provider = this.createProvider();
1301
+ this.logger.log(`Initialized embedding provider: ${this.provider.name}`);
1302
+ }
1303
+ return this.provider;
1322
1304
  }
1323
1305
  loadConfig() {
1324
1306
  const providerEnv = this.configService.get("EMBEDDING_PROVIDER");
@@ -1365,35 +1347,36 @@ class EmbeddingService {
1365
1347
  }
1366
1348
  }
1367
1349
  getProviderName() {
1368
- return this.provider.name;
1350
+ return this.getProvider().name;
1369
1351
  }
1370
1352
  getDimensions() {
1371
- return this.provider.dimensions;
1353
+ return this.getProvider().dimensions;
1372
1354
  }
1373
1355
  async generateEmbedding(text) {
1374
1356
  if (!text || text.trim().length === 0) {
1375
1357
  throw new Error("Cannot generate embedding for empty text");
1376
1358
  }
1377
- return this.provider.generateEmbedding(text);
1359
+ return this.getProvider().generateEmbedding(text);
1378
1360
  }
1379
1361
  async generateQueryEmbedding(text) {
1380
1362
  if (!text || text.trim().length === 0) {
1381
1363
  throw new Error("Cannot generate embedding for empty text");
1382
1364
  }
1383
- if (this.provider.generateQueryEmbedding) {
1384
- return this.provider.generateQueryEmbedding(text);
1365
+ const provider = this.getProvider();
1366
+ if (provider.generateQueryEmbedding) {
1367
+ return provider.generateQueryEmbedding(text);
1385
1368
  }
1386
- return this.provider.generateEmbedding(text);
1369
+ return provider.generateEmbedding(text);
1387
1370
  }
1388
1371
  async generateEmbeddings(texts) {
1389
1372
  const validTexts = texts.filter((t) => t && t.trim().length > 0);
1390
1373
  if (validTexts.length === 0) {
1391
1374
  return [];
1392
1375
  }
1393
- return this.provider.generateEmbeddings(validTexts);
1376
+ return this.getProvider().generateEmbeddings(validTexts);
1394
1377
  }
1395
1378
  isRealProvider() {
1396
- return this.provider.name !== "mock";
1379
+ return this.getProvider().name !== "mock";
1397
1380
  }
1398
1381
  }
1399
1382
  EmbeddingService = __legacyDecorateClassTS([
@@ -2059,6 +2042,11 @@ class DatabaseChangeDetectorService {
2059
2042
  this.hashCache.clear();
2060
2043
  this.loaded = false;
2061
2044
  }
2045
+ clearEntries(paths) {
2046
+ for (const path2 of paths) {
2047
+ this.hashCache.delete(path2);
2048
+ }
2049
+ }
2062
2050
  getContentHash(content) {
2063
2051
  return createHash3("sha256").update(content).digest("hex");
2064
2052
  }
@@ -2236,30 +2224,30 @@ class SyncService {
2236
2224
  embeddingsGenerated: 0,
2237
2225
  entityEmbeddingsGenerated: 0
2238
2226
  };
2239
- const useDbDetection = options.legacy ? false : options.useDbChangeDetection ?? true;
2240
- const useAiExtraction = options.legacy ? false : options.aiExtraction ?? true;
2227
+ const useAiExtraction = options.aiExtraction ?? true;
2241
2228
  try {
2242
2229
  await this.manifest.load();
2243
- if (useDbDetection) {
2244
- await this.dbChangeDetector.loadHashes();
2245
- if (options.verbose) {
2246
- this.logger.log(`v2 mode: Loaded ${this.dbChangeDetector.getCacheSize()} document hashes from database`);
2247
- }
2230
+ await this.dbChangeDetector.loadHashes();
2231
+ if (options.verbose) {
2232
+ this.logger.log(`Loaded ${this.dbChangeDetector.getCacheSize()} document hashes from database`);
2248
2233
  }
2249
2234
  if (options.force) {
2250
2235
  if (options.paths && options.paths.length > 0) {
2236
+ const normalizedPaths = this.pathResolver.resolveDocPaths(options.paths, { requireExists: true, requireInDocs: true });
2251
2237
  if (options.verbose) {
2252
- this.logger.log(`Force mode: marking ${options.paths.length} document(s) for re-sync`);
2238
+ this.logger.log(`Force mode: marking ${normalizedPaths.length} document(s) for re-sync`);
2253
2239
  }
2254
2240
  await this.clearManifestEntries(options.paths);
2241
+ this.dbChangeDetector.clearEntries(normalizedPaths);
2255
2242
  } else {
2256
2243
  if (options.verbose) {
2257
- this.logger.log("Force mode: clearing manifest to force full re-sync");
2244
+ this.logger.log("Force mode: clearing tracking data to force full re-sync");
2258
2245
  }
2259
2246
  await this.clearManifest();
2247
+ this.dbChangeDetector.reset();
2260
2248
  }
2261
2249
  }
2262
- const changes = await this.detectChanges(options.paths, useDbDetection);
2250
+ const changes = await this.detectChanges(options.paths);
2263
2251
  result.changes = changes;
2264
2252
  const docsToSync = [];
2265
2253
  const docsByPath = new Map;
@@ -2328,10 +2316,6 @@ class SyncService {
2328
2316
  }
2329
2317
  if (!options.dryRun) {
2330
2318
  result.entityEmbeddingsGenerated = await this.syncEntities(uniqueEntities, options);
2331
- if (options.embeddings && !options.skipEmbeddings && this.embeddingService) {
2332
- const repairedCount = await this.repairMissingEntityEmbeddings(options);
2333
- result.entityEmbeddingsGenerated += repairedCount;
2334
- }
2335
2319
  await this.graph.checkpoint();
2336
2320
  if (options.verbose) {
2337
2321
  this.logger.log(`Synced ${uniqueEntities.size} entities, generated ${result.entityEmbeddingsGenerated} embeddings`);
@@ -2379,7 +2363,7 @@ class SyncService {
2379
2363
  result.duration = Date.now() - startTime;
2380
2364
  return result;
2381
2365
  }
2382
- async detectChanges(paths, useDbDetection = false) {
2366
+ async detectChanges(paths) {
2383
2367
  const changes = [];
2384
2368
  let allDocPaths = await this.parser.discoverDocuments();
2385
2369
  if (paths && paths.length > 0) {
@@ -2390,11 +2374,11 @@ class SyncService {
2390
2374
  const pathSet = new Set(normalizedPaths);
2391
2375
  allDocPaths = allDocPaths.filter((p) => pathSet.has(p));
2392
2376
  }
2393
- const trackedPaths = new Set(useDbDetection ? this.dbChangeDetector.getTrackedPaths() : this.manifest.getTrackedPaths());
2377
+ const trackedPaths = new Set(this.dbChangeDetector.getTrackedPaths());
2394
2378
  for (const docPath of allDocPaths) {
2395
2379
  try {
2396
2380
  const doc = await this.parser.parseDocument(docPath);
2397
- const changeType = useDbDetection ? this.dbChangeDetector.detectChange(docPath, doc.contentHash) : this.manifest.detectChange(docPath, doc.contentHash, doc.frontmatterHash);
2381
+ const changeType = this.dbChangeDetector.detectChange(docPath, doc.contentHash);
2398
2382
  changes.push({
2399
2383
  path: docPath,
2400
2384
  changeType,
@@ -2551,11 +2535,8 @@ class SyncService {
2551
2535
  change.embeddingGenerated = embeddingGenerated;
2552
2536
  const currentDoc = await this.parser.parseDocument(change.path);
2553
2537
  this.manifest.updateEntry(currentDoc.path, currentDoc.contentHash, currentDoc.frontmatterHash, currentDoc.entities.length, currentDoc.relationships.length);
2554
- const shouldUpdateDbHashes = options.legacy ? false : options.useDbChangeDetection ?? true;
2555
- if (shouldUpdateDbHashes) {
2556
- const embeddingSourceHash = embeddingGenerated ? currentDoc.contentHash : undefined;
2557
- await this.graph.updateDocumentHashes(currentDoc.path, currentDoc.contentHash, embeddingSourceHash);
2558
- }
2538
+ const embeddingSourceHash = embeddingGenerated ? currentDoc.contentHash : undefined;
2539
+ await this.graph.updateDocumentHashes(currentDoc.path, currentDoc.contentHash, embeddingSourceHash);
2559
2540
  break;
2560
2541
  }
2561
2542
  case "deleted": {
@@ -2640,43 +2621,6 @@ class SyncService {
2640
2621
  }
2641
2622
  }
2642
2623
  }
2643
- async repairMissingEntityEmbeddings(options) {
2644
- if (!this.embeddingService) {
2645
- return 0;
2646
- }
2647
- const labelsToCheck = [...ENTITY_TYPES, "Document"];
2648
- const nodesWithMissingEmbeddings = await this.graph.findNodesWithMissingEmbeddings(labelsToCheck);
2649
- if (nodesWithMissingEmbeddings.length === 0) {
2650
- return 0;
2651
- }
2652
- if (options.verbose) {
2653
- this.logger.log(`Found ${nodesWithMissingEmbeddings.length} nodes with missing embeddings, repairing...`);
2654
- }
2655
- let repairedCount = 0;
2656
- for (const node of nodesWithMissingEmbeddings) {
2657
- try {
2658
- const text = node.label === "Document" ? node.name : composeEntityEmbeddingText({
2659
- type: node.label,
2660
- name: node.name,
2661
- description: node.description,
2662
- documentPaths: []
2663
- });
2664
- if (text.trim()) {
2665
- const embedding = await this.embeddingService.generateEmbedding(text);
2666
- await this.graph.updateNodeEmbedding(node.label, node.name, embedding);
2667
- repairedCount++;
2668
- this.logger.debug(`Repaired embedding for ${node.label}:${node.name}`);
2669
- }
2670
- } catch (error) {
2671
- const errorMessage = error instanceof Error ? error.message : String(error);
2672
- this.logger.warn(`Failed to repair embedding for ${node.label}:${node.name}: ${errorMessage}`);
2673
- }
2674
- }
2675
- if (options.verbose && repairedCount > 0) {
2676
- this.logger.log(`Repaired ${repairedCount} missing embeddings`);
2677
- }
2678
- return repairedCount;
2679
- }
2680
2624
  }
2681
2625
  SyncService = __legacyDecorateClassTS([
2682
2626
  Injectable11(),
@@ -2743,7 +2687,6 @@ class MigrateCommand extends CommandRunner3 {
2743
2687
  if (!options.dryRun) {
2744
2688
  const result = await this.syncService.sync({
2745
2689
  force: false,
2746
- useDbChangeDetection: true,
2747
2690
  aiExtraction: true,
2748
2691
  verbose: options.verbose,
2749
2692
  embeddings: true
@@ -3182,23 +3125,16 @@ import { Injectable as Injectable16 } from "@nestjs/common";
3182
3125
  import { Command as Command6, CommandRunner as CommandRunner6, Option as Option4 } from "nest-commander";
3183
3126
  class StatusCommand extends CommandRunner6 {
3184
3127
  syncService;
3185
- manifestService;
3186
3128
  dbChangeDetector;
3187
- constructor(syncService, manifestService, dbChangeDetector) {
3129
+ constructor(syncService, dbChangeDetector) {
3188
3130
  super();
3189
3131
  this.syncService = syncService;
3190
- this.manifestService = manifestService;
3191
3132
  this.dbChangeDetector = dbChangeDetector;
3192
3133
  }
3193
3134
  async run(_inputs, options) {
3194
3135
  try {
3195
- const useDbDetection = !options.legacy;
3196
- if (useDbDetection) {
3197
- await this.dbChangeDetector.loadHashes();
3198
- } else {
3199
- await this.manifestService.load();
3200
- }
3201
- const changes = await this.syncService.detectChanges(undefined, useDbDetection);
3136
+ await this.dbChangeDetector.loadHashes();
3137
+ const changes = await this.syncService.detectChanges();
3202
3138
  const newDocs = changes.filter((c) => c.changeType === "new");
3203
3139
  const updatedDocs = changes.filter((c) => c.changeType === "updated");
3204
3140
  const deletedDocs = changes.filter((c) => c.changeType === "deleted");
@@ -3251,9 +3187,6 @@ class StatusCommand extends CommandRunner6 {
3251
3187
  parseVerbose() {
3252
3188
  return true;
3253
3189
  }
3254
- parseLegacy() {
3255
- return true;
3256
- }
3257
3190
  }
3258
3191
  __legacyDecorateClassTS([
3259
3192
  Option4({
@@ -3264,15 +3197,6 @@ __legacyDecorateClassTS([
3264
3197
  __legacyMetadataTS("design:paramtypes", []),
3265
3198
  __legacyMetadataTS("design:returntype", Boolean)
3266
3199
  ], StatusCommand.prototype, "parseVerbose", null);
3267
- __legacyDecorateClassTS([
3268
- Option4({
3269
- flags: "--legacy",
3270
- description: "Use legacy v1 mode: manifest-based change detection"
3271
- }),
3272
- __legacyMetadataTS("design:type", Function),
3273
- __legacyMetadataTS("design:paramtypes", []),
3274
- __legacyMetadataTS("design:returntype", Boolean)
3275
- ], StatusCommand.prototype, "parseLegacy", null);
3276
3200
  StatusCommand = __legacyDecorateClassTS([
3277
3201
  Injectable16(),
3278
3202
  Command6({
@@ -3281,7 +3205,6 @@ StatusCommand = __legacyDecorateClassTS([
3281
3205
  }),
3282
3206
  __legacyMetadataTS("design:paramtypes", [
3283
3207
  typeof SyncService === "undefined" ? Object : SyncService,
3284
- typeof ManifestService === "undefined" ? Object : ManifestService,
3285
3208
  typeof DatabaseChangeDetectorService === "undefined" ? Object : DatabaseChangeDetectorService
3286
3209
  ])
3287
3210
  ], StatusCommand);
@@ -3486,7 +3409,6 @@ class SyncCommand extends CommandRunner7 {
3486
3409
  paths: paths.length > 0 ? paths : undefined,
3487
3410
  skipCascade: options.skipCascade,
3488
3411
  embeddings: options.embeddings !== false,
3489
- legacy: options.legacy,
3490
3412
  aiExtraction: !options.skipExtraction
3491
3413
  };
3492
3414
  console.log(`
@@ -3508,14 +3430,9 @@ class SyncCommand extends CommandRunner7 {
3508
3430
  console.log(`\uD83D\uDEAB Embedding generation disabled
3509
3431
  `);
3510
3432
  }
3511
- if (syncOptions.legacy) {
3512
- console.log(`\uD83D\uDCDC Legacy mode: Using manifest-based change detection
3433
+ if (!syncOptions.aiExtraction) {
3434
+ console.log(`\u23ED\uFE0F AI entity extraction skipped (--skip-extraction)
3513
3435
  `);
3514
- } else {
3515
- if (!syncOptions.aiExtraction) {
3516
- console.log(`\u23ED\uFE0F AI entity extraction skipped (--skip-extraction)
3517
- `);
3518
- }
3519
3436
  }
3520
3437
  if (syncOptions.paths) {
3521
3438
  console.log(`\uD83D\uDCC1 Syncing specific paths: ${syncOptions.paths.join(", ")}
@@ -3713,9 +3630,6 @@ class SyncCommand extends CommandRunner7 {
3713
3630
  parseSkipExtraction() {
3714
3631
  return true;
3715
3632
  }
3716
- parseLegacy() {
3717
- return true;
3718
- }
3719
3633
  }
3720
3634
  __legacyDecorateClassTS([
3721
3635
  Option5({
@@ -3789,15 +3703,6 @@ __legacyDecorateClassTS([
3789
3703
  __legacyMetadataTS("design:paramtypes", []),
3790
3704
  __legacyMetadataTS("design:returntype", Boolean)
3791
3705
  ], SyncCommand.prototype, "parseSkipExtraction", null);
3792
- __legacyDecorateClassTS([
3793
- Option5({
3794
- flags: "--legacy",
3795
- description: "Use legacy v1 mode: manifest-based change detection, no AI extraction"
3796
- }),
3797
- __legacyMetadataTS("design:type", Function),
3798
- __legacyMetadataTS("design:paramtypes", []),
3799
- __legacyMetadataTS("design:returntype", Boolean)
3800
- ], SyncCommand.prototype, "parseLegacy", null);
3801
3706
  SyncCommand = __legacyDecorateClassTS([
3802
3707
  Injectable18(),
3803
3708
  Command7({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zabaca/lattice",
3
- "version": "1.0.20",
3
+ "version": "1.0.22",
4
4
  "description": "Human-initiated, AI-powered knowledge graph for markdown documentation",
5
5
  "type": "module",
6
6
  "bin": {