claude-memory-layer 2.4.16 → 2.4.17

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.
@@ -4464,7 +4464,7 @@ function emptyLatencyAggregate() {
4464
4464
  return { count: 0, failedCount: 0, totalMs: 0, maxMs: 0 };
4465
4465
  }
4466
4466
  function runtimeVersion() {
4467
- const value = "2.4.16"?.trim();
4467
+ const value = "2.4.17"?.trim();
4468
4468
  return sanitizeRuntimeVersion(value || "development");
4469
4469
  }
4470
4470
  function sanitizeRuntimeVersion(value) {
@@ -25386,6 +25386,7 @@ function localizePulledMetadata(doc, localProject) {
25386
25386
  };
25387
25387
  return metadata;
25388
25388
  }
25389
+ var LATE_INSERT_WINDOW_MS = 30 * 60 * 1e3;
25389
25390
  function parseIntOrZero(value) {
25390
25391
  if (!value) return 0;
25391
25392
  const n = parseInt(value, 10);
@@ -25512,6 +25513,7 @@ var MongoSyncWorker = class {
25512
25513
  await this.events.createIndex({ projectKey: 1, seq: 1 }, { unique: true });
25513
25514
  await this.events.createIndex({ projectKey: 1, eventId: 1 }, { unique: true });
25514
25515
  await this.events.createIndex({ projectKey: 1, dedupeKey: 1 });
25516
+ await this.events.createIndex({ projectKey: 1, insertedAt: 1 });
25515
25517
  } catch (err) {
25516
25518
  console.warn("[MongoSyncWorker] Failed to ensure indexes (continuing):", err);
25517
25519
  }
@@ -25594,39 +25596,60 @@ var MongoSyncWorker = class {
25594
25596
  }
25595
25597
  return pushed;
25596
25598
  }
25599
+ /**
25600
+ * A pusher reserves its seq range before it inserts, so a document can appear below a cursor that another machine's
25601
+ * faster insert already moved past. Each pull therefore re-reads what was inserted shortly before the previous pull
25602
+ * started — import skips the events it already has — and then reads past the cursor as before. The window also
25603
+ * absorbs clock differences between machines (insertedAt is the pusher's clock).
25604
+ */
25597
25605
  async pullEvents() {
25598
25606
  if (!this.events) throw new Error("Mongo not connected");
25599
25607
  const position = await this.sqliteStore.getSyncPosition(this.pullTargetName());
25600
25608
  let lastSeq = parseIntOrZero(position.lastEventId);
25609
+ const startedAt = /* @__PURE__ */ new Date();
25610
+ const previousPullAt = position.lastTimestamp ? new Date(position.lastTimestamp) : null;
25601
25611
  let pulled = 0;
25612
+ if (lastSeq > 0 && previousPullAt && !Number.isNaN(previousPullAt.getTime())) {
25613
+ const since = new Date(previousPullAt.getTime() - LATE_INSERT_WINDOW_MS);
25614
+ let afterSeq = 0;
25615
+ while (true) {
25616
+ const docs = await this.events.find(
25617
+ { projectKey: this.config.projectKey, seq: { $gt: afterSeq, $lte: lastSeq }, insertedAt: { $gte: since } },
25618
+ { sort: { seq: 1 }, limit: this.config.batchSize }
25619
+ ).toArray();
25620
+ if (docs.length === 0) break;
25621
+ pulled += await this.importPulled(docs);
25622
+ afterSeq = docs[docs.length - 1].seq;
25623
+ if (docs.length < this.config.batchSize) break;
25624
+ }
25625
+ }
25602
25626
  while (true) {
25603
25627
  const docs = await this.events.find(
25604
25628
  { projectKey: this.config.projectKey, seq: { $gt: lastSeq } },
25605
25629
  { sort: { seq: 1 }, limit: this.config.batchSize }
25606
25630
  ).toArray();
25607
25631
  if (docs.length === 0) break;
25608
- const events = docs.map((d) => ({
25609
- id: d.eventId,
25610
- eventType: d.eventType,
25611
- sessionId: d.sessionId,
25612
- timestamp: d.timestamp instanceof Date ? d.timestamp : new Date(d.timestamp),
25613
- content: d.content,
25614
- canonicalKey: d.canonicalKey,
25615
- dedupeKey: d.dedupeKey,
25616
- metadata: this.config.localProject ? localizePulledMetadata(d, this.config.localProject) : d.metadata ?? void 0
25617
- }));
25618
- const result2 = await this.sqliteStore.importEvents(events);
25619
- pulled += result2.inserted;
25632
+ pulled += await this.importPulled(docs);
25620
25633
  lastSeq = docs[docs.length - 1].seq;
25621
- await this.sqliteStore.updateSyncPosition(
25622
- this.pullTargetName(),
25623
- String(lastSeq),
25624
- (/* @__PURE__ */ new Date()).toISOString()
25625
- );
25634
+ await this.sqliteStore.updateSyncPosition(this.pullTargetName(), String(lastSeq), startedAt.toISOString());
25626
25635
  if (docs.length < this.config.batchSize) break;
25627
25636
  }
25637
+ await this.sqliteStore.updateSyncPosition(this.pullTargetName(), String(lastSeq), startedAt.toISOString());
25628
25638
  return pulled;
25629
25639
  }
25640
+ async importPulled(docs) {
25641
+ const events = docs.map((d) => ({
25642
+ id: d.eventId,
25643
+ eventType: d.eventType,
25644
+ sessionId: d.sessionId,
25645
+ timestamp: d.timestamp instanceof Date ? d.timestamp : new Date(d.timestamp),
25646
+ content: d.content,
25647
+ canonicalKey: d.canonicalKey,
25648
+ dedupeKey: d.dedupeKey,
25649
+ metadata: this.config.localProject ? localizePulledMetadata(d, this.config.localProject) : d.metadata ?? void 0
25650
+ }));
25651
+ return (await this.sqliteStore.importEvents(events)).inserted;
25652
+ }
25630
25653
  };
25631
25654
 
25632
25655
  // src/core/product-validation-matrix.ts