claude-memory-layer 1.0.22 → 1.0.24

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 (51) hide show
  1. package/.claude/settings.local.json +11 -0
  2. package/README.md +2 -0
  3. package/dist/cli/index.js +87 -17
  4. package/dist/cli/index.js.map +2 -2
  5. package/dist/core/index.js +30 -5
  6. package/dist/core/index.js.map +2 -2
  7. package/dist/hooks/post-tool-use.js +117 -18
  8. package/dist/hooks/post-tool-use.js.map +2 -2
  9. package/dist/hooks/semantic-daemon.js +7337 -0
  10. package/dist/hooks/semantic-daemon.js.map +7 -0
  11. package/dist/hooks/session-end.js +71 -16
  12. package/dist/hooks/session-end.js.map +2 -2
  13. package/dist/hooks/session-start.js +156 -24
  14. package/dist/hooks/session-start.js.map +4 -4
  15. package/dist/hooks/stop.js +101 -18
  16. package/dist/hooks/stop.js.map +2 -2
  17. package/dist/hooks/user-prompt-submit.js +291 -102
  18. package/dist/hooks/user-prompt-submit.js.map +4 -4
  19. package/dist/server/api/index.js +71 -16
  20. package/dist/server/api/index.js.map +2 -2
  21. package/dist/server/index.js +71 -16
  22. package/dist/server/index.js.map +2 -2
  23. package/dist/services/memory-service.js +71 -16
  24. package/dist/services/memory-service.js.map +2 -2
  25. package/dist/ui/app.js +48 -1
  26. package/dist/ui/index.html +11 -3
  27. package/memory/_index.md +1 -0
  28. package/memory/agent_response/uncategorized/2026-03-04.md +1138 -1
  29. package/memory/session_summary/uncategorized/2026-03-04.md +31 -0
  30. package/memory/tool_observation/uncategorized/2026-03-04.md +785 -1
  31. package/memory/user_prompt/uncategorized/2026-03-04.md +438 -1
  32. package/package.json +1 -1
  33. package/scripts/build.ts +2 -1
  34. package/specs/selective-tool-observation/context.md +100 -0
  35. package/specs/selective-tool-observation/plan.md +158 -0
  36. package/specs/selective-tool-observation/spec.md +127 -0
  37. package/src/cli/index.ts +1 -0
  38. package/src/core/embedder.ts +15 -4
  39. package/src/core/sqlite-event-store.ts +16 -0
  40. package/src/core/turn-state.ts +48 -0
  41. package/src/core/types.ts +1 -0
  42. package/src/hooks/post-tool-use.ts +47 -2
  43. package/src/hooks/semantic-daemon-client.ts +208 -0
  44. package/src/hooks/semantic-daemon.ts +276 -0
  45. package/src/hooks/session-start.ts +7 -0
  46. package/src/hooks/stop.ts +19 -4
  47. package/src/hooks/user-prompt-submit.ts +48 -40
  48. package/src/services/memory-service.ts +59 -16
  49. package/src/services/session-history-importer.ts +18 -0
  50. package/src/ui/app.js +48 -1
  51. package/src/ui/index.html +11 -3
@@ -1850,6 +1850,21 @@ var SQLiteEventStore = class {
1850
1850
  [id, eventId, sessionId, score, query.slice(0, 100)]
1851
1851
  );
1852
1852
  }
1853
+ /**
1854
+ * Get session IDs that have unevaluated retrievals (measured_at IS NULL).
1855
+ * Excludes the current session. Used to backfill sessions that ended without Stop hook.
1856
+ */
1857
+ async getUnevaluatedSessions(currentSessionId, limit = 5) {
1858
+ await this.initialize();
1859
+ const rows = sqliteAll(
1860
+ this.db,
1861
+ `SELECT DISTINCT session_id FROM memory_helpfulness
1862
+ WHERE measured_at IS NULL AND session_id != ?
1863
+ ORDER BY created_at DESC LIMIT ?`,
1864
+ [currentSessionId, limit]
1865
+ );
1866
+ return rows.map((r) => r.session_id);
1867
+ }
1853
1868
  /**
1854
1869
  * Evaluate helpfulness for all retrievals in a session
1855
1870
  * Called at session end - uses behavioral signals to compute score
@@ -2637,7 +2652,7 @@ var VectorStore = class {
2637
2652
 
2638
2653
  // src/core/embedder.ts
2639
2654
  import { pipeline } from "@huggingface/transformers";
2640
- var Embedder = class {
2655
+ var Embedder = class _Embedder {
2641
2656
  pipeline = null;
2642
2657
  modelName;
2643
2658
  activeModelName;
@@ -2668,6 +2683,11 @@ var Embedder = class {
2668
2683
  this.initialized = true;
2669
2684
  }
2670
2685
  }
2686
+ // ~4 chars per token; 512 tokens * 4 = 2048, use 2000 to be safe
2687
+ static MAX_CHARS = 2e3;
2688
+ truncate(text) {
2689
+ return text.length > _Embedder.MAX_CHARS ? text.slice(0, _Embedder.MAX_CHARS) : text;
2690
+ }
2671
2691
  /**
2672
2692
  * Generate embedding for a single text
2673
2693
  */
@@ -2676,9 +2696,11 @@ var Embedder = class {
2676
2696
  if (!this.pipeline) {
2677
2697
  throw new Error("Embedding pipeline not initialized");
2678
2698
  }
2679
- const output = await this.pipeline(text, {
2699
+ const output = await this.pipeline(this.truncate(text), {
2680
2700
  pooling: "mean",
2681
- normalize: true
2701
+ normalize: true,
2702
+ truncation: true,
2703
+ max_length: 512
2682
2704
  });
2683
2705
  const vector = Array.from(output.data);
2684
2706
  return {
@@ -2700,9 +2722,11 @@ var Embedder = class {
2700
2722
  for (let i = 0; i < texts.length; i += batchSize) {
2701
2723
  const batch = texts.slice(i, i + batchSize);
2702
2724
  for (const text of batch) {
2703
- const output = await this.pipeline(text, {
2725
+ const output = await this.pipeline(this.truncate(text), {
2704
2726
  pooling: "mean",
2705
- normalize: true
2727
+ normalize: true,
2728
+ truncation: true,
2729
+ max_length: 512
2706
2730
  });
2707
2731
  const vector = Array.from(output.data);
2708
2732
  results.push({
@@ -5968,6 +5992,7 @@ var MemoryService = class {
5968
5992
  projectPath = null;
5969
5993
  readOnly;
5970
5994
  lightweightMode;
5995
+ embeddingOnly;
5971
5996
  mdMirror;
5972
5997
  storagePath;
5973
5998
  constructor(config) {
@@ -5975,6 +6000,7 @@ var MemoryService = class {
5975
6000
  this.storagePath = storagePath;
5976
6001
  this.readOnly = config.readOnly ?? false;
5977
6002
  this.lightweightMode = config.lightweightMode ?? false;
6003
+ this.embeddingOnly = config.embeddingOnly ?? false;
5978
6004
  this.mdMirror = new MarkdownMirror2(process.cwd());
5979
6005
  if (!this.readOnly && !fs4.existsSync(storagePath)) {
5980
6006
  fs4.mkdirSync(storagePath, { recursive: true });
@@ -6048,19 +6074,21 @@ var MemoryService = class {
6048
6074
  this.embedder
6049
6075
  );
6050
6076
  this.vectorWorker.start();
6051
- this.retriever.setGraduationPipeline(this.graduation);
6052
- this.graduationWorker = createGraduationWorker(
6053
- this.sqliteStore,
6054
- this.graduation
6055
- );
6056
- this.graduationWorker.start();
6057
- if (this.analyticsStore) {
6058
- this.syncWorker = new SyncWorker(
6077
+ if (!this.embeddingOnly) {
6078
+ this.retriever.setGraduationPipeline(this.graduation);
6079
+ this.graduationWorker = createGraduationWorker(
6059
6080
  this.sqliteStore,
6060
- this.analyticsStore,
6061
- { intervalMs: 3e4, batchSize: 500 }
6081
+ this.graduation
6062
6082
  );
6063
- this.syncWorker.start();
6083
+ this.graduationWorker.start();
6084
+ if (this.analyticsStore) {
6085
+ this.syncWorker = new SyncWorker(
6086
+ this.sqliteStore,
6087
+ this.analyticsStore,
6088
+ { intervalMs: 3e4, batchSize: 500 }
6089
+ );
6090
+ this.syncWorker.start();
6091
+ }
6064
6092
  }
6065
6093
  const savedMode = await this.sqliteStore.getEndlessConfig("mode");
6066
6094
  if (savedMode === "endless") {
@@ -6784,6 +6812,19 @@ var MemoryService = class {
6784
6812
  await this.initialize();
6785
6813
  await this.sqliteStore.recordRetrieval(eventId, sessionId, score, query);
6786
6814
  }
6815
+ /**
6816
+ * Record a query-level retrieval trace (used by user-prompt-submit hook).
6817
+ * Feeds the retrieval_traces table that powers dashboard stats.
6818
+ */
6819
+ async recordQueryTrace(input) {
6820
+ await this.initialize();
6821
+ await this.sqliteStore.recordRetrievalTrace({
6822
+ ...input,
6823
+ candidateDetails: [],
6824
+ selectedDetails: [],
6825
+ fallbackTrace: []
6826
+ });
6827
+ }
6787
6828
  /**
6788
6829
  * Evaluate helpfulness of retrievals in a session (called at session end)
6789
6830
  */
@@ -6791,6 +6832,20 @@ var MemoryService = class {
6791
6832
  await this.initialize();
6792
6833
  await this.sqliteStore.evaluateSessionHelpfulness(sessionId);
6793
6834
  }
6835
+ /**
6836
+ * Backfill helpfulness evaluation for sessions that ended without Stop hook.
6837
+ * Call on first turn of a new session to catch missed evaluations.
6838
+ */
6839
+ async evaluatePendingSessions(currentSessionId) {
6840
+ await this.initialize();
6841
+ const sessions = await this.sqliteStore.getUnevaluatedSessions(currentSessionId, 5);
6842
+ for (const sid of sessions) {
6843
+ try {
6844
+ await this.sqliteStore.evaluateSessionHelpfulness(sid);
6845
+ } catch {
6846
+ }
6847
+ }
6848
+ }
6794
6849
  /**
6795
6850
  * Get most helpful memories ranked by helpfulness score
6796
6851
  */