claude-memory-layer 1.0.7 → 1.0.8

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 (38) hide show
  1. package/.claude/settings.local.json +4 -1
  2. package/.history/package_20260201192048.json +47 -0
  3. package/dist/cli/index.js +569 -39
  4. package/dist/cli/index.js.map +4 -4
  5. package/dist/core/index.js +192 -5
  6. package/dist/core/index.js.map +4 -4
  7. package/dist/hooks/session-end.js +262 -18
  8. package/dist/hooks/session-end.js.map +4 -4
  9. package/dist/hooks/session-start.js +262 -18
  10. package/dist/hooks/session-start.js.map +4 -4
  11. package/dist/hooks/stop.js +262 -18
  12. package/dist/hooks/stop.js.map +4 -4
  13. package/dist/hooks/user-prompt-submit.js +262 -18
  14. package/dist/hooks/user-prompt-submit.js.map +4 -4
  15. package/dist/server/api/index.js +404 -39
  16. package/dist/server/api/index.js.map +4 -4
  17. package/dist/server/index.js +413 -46
  18. package/dist/server/index.js.map +4 -4
  19. package/dist/services/memory-service.js +269 -18
  20. package/dist/services/memory-service.js.map +4 -4
  21. package/dist/ui/index.html +495 -15
  22. package/package.json +2 -1
  23. package/scripts/build.ts +3 -2
  24. package/src/cli/index.ts +226 -0
  25. package/src/core/db-wrapper.ts +8 -1
  26. package/src/core/event-store.ts +52 -3
  27. package/src/core/graduation-worker.ts +171 -0
  28. package/src/core/graduation.ts +15 -2
  29. package/src/core/index.ts +1 -0
  30. package/src/core/retriever.ts +18 -0
  31. package/src/server/api/citations.ts +7 -3
  32. package/src/server/api/events.ts +7 -3
  33. package/src/server/api/search.ts +7 -3
  34. package/src/server/api/sessions.ts +7 -3
  35. package/src/server/api/stats.ts +129 -12
  36. package/src/server/index.ts +18 -9
  37. package/src/services/memory-service.ts +107 -19
  38. package/src/ui/index.html +495 -15
@@ -639,7 +639,10 @@ function toDate(value) {
639
639
  return new Date(value);
640
640
  return new Date(String(value));
641
641
  }
642
- function createDatabase(path) {
642
+ function createDatabase(path, options) {
643
+ if (options?.readOnly) {
644
+ return new duckdb.Database(path, { access_mode: "READ_ONLY" });
645
+ }
643
646
  return new duckdb.Database(path);
644
647
  }
645
648
  function dbRun(db, sql, params = []) {
@@ -693,18 +696,24 @@ function dbClose(db) {
693
696
 
694
697
  // src/core/event-store.ts
695
698
  var EventStore = class {
696
- constructor(dbPath) {
699
+ constructor(dbPath, options) {
697
700
  this.dbPath = dbPath;
698
- this.db = createDatabase(dbPath);
701
+ this.readOnly = options?.readOnly ?? false;
702
+ this.db = createDatabase(dbPath, { readOnly: this.readOnly });
699
703
  }
700
704
  db;
701
705
  initialized = false;
706
+ readOnly;
702
707
  /**
703
708
  * Initialize database schema
704
709
  */
705
710
  async initialize() {
706
711
  if (this.initialized)
707
712
  return;
713
+ if (this.readOnly) {
714
+ this.initialized = true;
715
+ return;
716
+ }
708
717
  await dbRun(this.db, `
709
718
  CREATE TABLE IF NOT EXISTS events (
710
719
  id VARCHAR PRIMARY KEY,
@@ -1181,6 +1190,36 @@ var EventStore = class {
1181
1190
  );
1182
1191
  return rows;
1183
1192
  }
1193
+ /**
1194
+ * Get events by memory level
1195
+ */
1196
+ async getEventsByLevel(level, options) {
1197
+ await this.initialize();
1198
+ const limit = options?.limit || 50;
1199
+ const offset = options?.offset || 0;
1200
+ const rows = await dbAll(
1201
+ this.db,
1202
+ `SELECT e.* FROM events e
1203
+ INNER JOIN memory_levels ml ON e.id = ml.event_id
1204
+ WHERE ml.level = ?
1205
+ ORDER BY e.timestamp DESC
1206
+ LIMIT ? OFFSET ?`,
1207
+ [level, limit, offset]
1208
+ );
1209
+ return rows.map((row) => this.rowToEvent(row));
1210
+ }
1211
+ /**
1212
+ * Get memory level for a specific event
1213
+ */
1214
+ async getEventLevel(eventId) {
1215
+ await this.initialize();
1216
+ const rows = await dbAll(
1217
+ this.db,
1218
+ `SELECT level FROM memory_levels WHERE event_id = ?`,
1219
+ [eventId]
1220
+ );
1221
+ return rows.length > 0 ? rows[0].level : null;
1222
+ }
1184
1223
  // ============================================================
1185
1224
  // Endless Mode Helper Methods
1186
1225
  // ============================================================
@@ -3167,6 +3206,7 @@ var Retriever = class {
3167
3206
  matcher;
3168
3207
  sharedStore;
3169
3208
  sharedVectorStore;
3209
+ graduation;
3170
3210
  constructor(eventStore, vectorStore, embedder, matcher, sharedOptions) {
3171
3211
  this.eventStore = eventStore;
3172
3212
  this.vectorStore = vectorStore;
@@ -3175,6 +3215,12 @@ var Retriever = class {
3175
3215
  this.sharedStore = sharedOptions?.sharedStore;
3176
3216
  this.sharedVectorStore = sharedOptions?.sharedVectorStore;
3177
3217
  }
3218
+ /**
3219
+ * Set graduation pipeline for access tracking
3220
+ */
3221
+ setGraduationPipeline(graduation) {
3222
+ this.graduation = graduation;
3223
+ }
3178
3224
  /**
3179
3225
  * Set shared stores after construction
3180
3226
  */
@@ -3297,6 +3343,13 @@ var Retriever = class {
3297
3343
  const event = await this.eventStore.getEvent(result.eventId);
3298
3344
  if (!event)
3299
3345
  continue;
3346
+ if (this.graduation) {
3347
+ this.graduation.recordAccess(
3348
+ event.id,
3349
+ options.sessionId || "unknown",
3350
+ result.score
3351
+ );
3352
+ }
3300
3353
  let sessionContext;
3301
3354
  if (options.includeSessionContext) {
3302
3355
  sessionContext = await this.getSessionContext(event.sessionId, event.id);
@@ -3418,15 +3471,26 @@ var GraduationPipeline = class {
3418
3471
  L3toL4: { ...DEFAULT_CRITERIA.L3toL4, ...criteria.L3toL4 }
3419
3472
  };
3420
3473
  }
3474
+ // Track which sessions have accessed each event
3475
+ sessionAccesses = /* @__PURE__ */ new Map();
3421
3476
  /**
3422
3477
  * Record an access to an event (used for graduation scoring)
3423
3478
  */
3424
3479
  recordAccess(eventId, fromSessionId, confidence = 1) {
3425
3480
  const existing = this.metrics.get(eventId);
3481
+ if (!this.sessionAccesses.has(eventId)) {
3482
+ this.sessionAccesses.set(eventId, /* @__PURE__ */ new Set());
3483
+ }
3484
+ const sessions = this.sessionAccesses.get(eventId);
3485
+ const isNewSession = !sessions.has(fromSessionId);
3486
+ sessions.add(fromSessionId);
3426
3487
  if (existing) {
3427
3488
  existing.accessCount++;
3428
3489
  existing.lastAccessed = /* @__PURE__ */ new Date();
3429
3490
  existing.confidence = Math.max(existing.confidence, confidence);
3491
+ if (isNewSession && sessions.size > 1) {
3492
+ existing.crossSessionRefs = sessions.size - 1;
3493
+ }
3430
3494
  } else {
3431
3495
  this.metrics.set(eventId, {
3432
3496
  eventId,
@@ -3631,8 +3695,129 @@ function createGraduationPipeline(eventStore) {
3631
3695
  return new GraduationPipeline(eventStore);
3632
3696
  }
3633
3697
 
3634
- // src/core/task/task-matcher.ts
3698
+ // src/core/graduation-worker.ts
3635
3699
  var DEFAULT_CONFIG4 = {
3700
+ evaluationIntervalMs: 3e5,
3701
+ // 5 minutes
3702
+ batchSize: 50,
3703
+ cooldownMs: 36e5
3704
+ // 1 hour cooldown between evaluations
3705
+ };
3706
+ var GraduationWorker = class {
3707
+ constructor(eventStore, graduation, config = DEFAULT_CONFIG4) {
3708
+ this.eventStore = eventStore;
3709
+ this.graduation = graduation;
3710
+ this.config = config;
3711
+ }
3712
+ running = false;
3713
+ timeout = null;
3714
+ lastEvaluated = /* @__PURE__ */ new Map();
3715
+ /**
3716
+ * Start the graduation worker
3717
+ */
3718
+ start() {
3719
+ if (this.running)
3720
+ return;
3721
+ this.running = true;
3722
+ this.scheduleNext();
3723
+ }
3724
+ /**
3725
+ * Stop the graduation worker
3726
+ */
3727
+ stop() {
3728
+ this.running = false;
3729
+ if (this.timeout) {
3730
+ clearTimeout(this.timeout);
3731
+ this.timeout = null;
3732
+ }
3733
+ }
3734
+ /**
3735
+ * Check if currently running
3736
+ */
3737
+ isRunning() {
3738
+ return this.running;
3739
+ }
3740
+ /**
3741
+ * Force a graduation evaluation run
3742
+ */
3743
+ async forceRun() {
3744
+ return await this.runGraduation();
3745
+ }
3746
+ /**
3747
+ * Schedule the next graduation check
3748
+ */
3749
+ scheduleNext() {
3750
+ if (!this.running)
3751
+ return;
3752
+ this.timeout = setTimeout(
3753
+ () => this.run(),
3754
+ this.config.evaluationIntervalMs
3755
+ );
3756
+ }
3757
+ /**
3758
+ * Run graduation evaluation
3759
+ */
3760
+ async run() {
3761
+ if (!this.running)
3762
+ return;
3763
+ try {
3764
+ await this.runGraduation();
3765
+ } catch (error) {
3766
+ console.error("Graduation error:", error);
3767
+ }
3768
+ this.scheduleNext();
3769
+ }
3770
+ /**
3771
+ * Perform graduation evaluation across all levels
3772
+ */
3773
+ async runGraduation() {
3774
+ const result = {
3775
+ evaluated: 0,
3776
+ graduated: 0,
3777
+ byLevel: {}
3778
+ };
3779
+ const levels = ["L0", "L1", "L2", "L3"];
3780
+ const now = Date.now();
3781
+ for (const level of levels) {
3782
+ const events = await this.eventStore.getEventsByLevel(level, {
3783
+ limit: this.config.batchSize
3784
+ });
3785
+ let levelGraduated = 0;
3786
+ for (const event of events) {
3787
+ const lastEval = this.lastEvaluated.get(event.id);
3788
+ if (lastEval && now - lastEval < this.config.cooldownMs) {
3789
+ continue;
3790
+ }
3791
+ result.evaluated++;
3792
+ this.lastEvaluated.set(event.id, now);
3793
+ const gradResult = await this.graduation.evaluateGraduation(event.id, level);
3794
+ if (gradResult.success) {
3795
+ result.graduated++;
3796
+ levelGraduated++;
3797
+ }
3798
+ }
3799
+ if (levelGraduated > 0) {
3800
+ result.byLevel[level] = levelGraduated;
3801
+ }
3802
+ }
3803
+ if (this.lastEvaluated.size > 1e3) {
3804
+ const entries = Array.from(this.lastEvaluated.entries());
3805
+ entries.sort((a, b) => b[1] - a[1]);
3806
+ this.lastEvaluated = new Map(entries.slice(0, 1e3));
3807
+ }
3808
+ return result;
3809
+ }
3810
+ };
3811
+ function createGraduationWorker(eventStore, graduation, config) {
3812
+ return new GraduationWorker(
3813
+ eventStore,
3814
+ graduation,
3815
+ { ...DEFAULT_CONFIG4, ...config }
3816
+ );
3817
+ }
3818
+
3819
+ // src/core/task/task-matcher.ts
3820
+ var DEFAULT_CONFIG5 = {
3636
3821
  minCombinedScore: MATCH_THRESHOLDS.minCombinedScore,
3637
3822
  minGap: MATCH_THRESHOLDS.minGap,
3638
3823
  suggestionThreshold: MATCH_THRESHOLDS.suggestionThreshold,
@@ -3641,7 +3826,7 @@ var DEFAULT_CONFIG4 = {
3641
3826
  var TaskMatcher = class {
3642
3827
  constructor(db, config) {
3643
3828
  this.db = db;
3644
- this.config = { ...DEFAULT_CONFIG4, ...config };
3829
+ this.config = { ...DEFAULT_CONFIG5, ...config };
3645
3830
  }
3646
3831
  config;
3647
3832
  /**
@@ -5291,6 +5476,7 @@ export {
5291
5476
  FullDetailSchema,
5292
5477
  GraduationPipeline,
5293
5478
  GraduationResultSchema,
5479
+ GraduationWorker,
5294
5480
  InsightSchema,
5295
5481
  InsightTypeSchema,
5296
5482
  MATCH_THRESHOLDS,
@@ -5341,6 +5527,7 @@ export {
5341
5527
  VectorWorkerV2,
5342
5528
  WorkingSetItemSchema,
5343
5529
  createGraduationPipeline,
5530
+ createGraduationWorker,
5344
5531
  createRetriever,
5345
5532
  createSharedEventStore,
5346
5533
  createSharedPromoter,