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
@@ -1833,6 +1833,21 @@ var SQLiteEventStore = class {
1833
1833
  [id, eventId, sessionId, score, query.slice(0, 100)]
1834
1834
  );
1835
1835
  }
1836
+ /**
1837
+ * Get session IDs that have unevaluated retrievals (measured_at IS NULL).
1838
+ * Excludes the current session. Used to backfill sessions that ended without Stop hook.
1839
+ */
1840
+ async getUnevaluatedSessions(currentSessionId, limit = 5) {
1841
+ await this.initialize();
1842
+ const rows = sqliteAll(
1843
+ this.db,
1844
+ `SELECT DISTINCT session_id FROM memory_helpfulness
1845
+ WHERE measured_at IS NULL AND session_id != ?
1846
+ ORDER BY created_at DESC LIMIT ?`,
1847
+ [currentSessionId, limit]
1848
+ );
1849
+ return rows.map((r) => r.session_id);
1850
+ }
1836
1851
  /**
1837
1852
  * Evaluate helpfulness for all retrievals in a session
1838
1853
  * Called at session end - uses behavioral signals to compute score
@@ -2620,7 +2635,7 @@ var VectorStore = class {
2620
2635
 
2621
2636
  // src/core/embedder.ts
2622
2637
  import { pipeline } from "@huggingface/transformers";
2623
- var Embedder = class {
2638
+ var Embedder = class _Embedder {
2624
2639
  pipeline = null;
2625
2640
  modelName;
2626
2641
  activeModelName;
@@ -2651,6 +2666,11 @@ var Embedder = class {
2651
2666
  this.initialized = true;
2652
2667
  }
2653
2668
  }
2669
+ // ~4 chars per token; 512 tokens * 4 = 2048, use 2000 to be safe
2670
+ static MAX_CHARS = 2e3;
2671
+ truncate(text) {
2672
+ return text.length > _Embedder.MAX_CHARS ? text.slice(0, _Embedder.MAX_CHARS) : text;
2673
+ }
2654
2674
  /**
2655
2675
  * Generate embedding for a single text
2656
2676
  */
@@ -2659,9 +2679,11 @@ var Embedder = class {
2659
2679
  if (!this.pipeline) {
2660
2680
  throw new Error("Embedding pipeline not initialized");
2661
2681
  }
2662
- const output = await this.pipeline(text, {
2682
+ const output = await this.pipeline(this.truncate(text), {
2663
2683
  pooling: "mean",
2664
- normalize: true
2684
+ normalize: true,
2685
+ truncation: true,
2686
+ max_length: 512
2665
2687
  });
2666
2688
  const vector = Array.from(output.data);
2667
2689
  return {
@@ -2683,9 +2705,11 @@ var Embedder = class {
2683
2705
  for (let i = 0; i < texts.length; i += batchSize) {
2684
2706
  const batch = texts.slice(i, i + batchSize);
2685
2707
  for (const text of batch) {
2686
- const output = await this.pipeline(text, {
2708
+ const output = await this.pipeline(this.truncate(text), {
2687
2709
  pooling: "mean",
2688
- normalize: true
2710
+ normalize: true,
2711
+ truncation: true,
2712
+ max_length: 512
2689
2713
  });
2690
2714
  const vector = Array.from(output.data);
2691
2715
  results.push({
@@ -5980,6 +6004,7 @@ var MemoryService = class {
5980
6004
  projectPath = null;
5981
6005
  readOnly;
5982
6006
  lightweightMode;
6007
+ embeddingOnly;
5983
6008
  mdMirror;
5984
6009
  storagePath;
5985
6010
  constructor(config) {
@@ -5987,6 +6012,7 @@ var MemoryService = class {
5987
6012
  this.storagePath = storagePath;
5988
6013
  this.readOnly = config.readOnly ?? false;
5989
6014
  this.lightweightMode = config.lightweightMode ?? false;
6015
+ this.embeddingOnly = config.embeddingOnly ?? false;
5990
6016
  this.mdMirror = new MarkdownMirror2(process.cwd());
5991
6017
  if (!this.readOnly && !fs4.existsSync(storagePath)) {
5992
6018
  fs4.mkdirSync(storagePath, { recursive: true });
@@ -6060,19 +6086,21 @@ var MemoryService = class {
6060
6086
  this.embedder
6061
6087
  );
6062
6088
  this.vectorWorker.start();
6063
- this.retriever.setGraduationPipeline(this.graduation);
6064
- this.graduationWorker = createGraduationWorker(
6065
- this.sqliteStore,
6066
- this.graduation
6067
- );
6068
- this.graduationWorker.start();
6069
- if (this.analyticsStore) {
6070
- this.syncWorker = new SyncWorker(
6089
+ if (!this.embeddingOnly) {
6090
+ this.retriever.setGraduationPipeline(this.graduation);
6091
+ this.graduationWorker = createGraduationWorker(
6071
6092
  this.sqliteStore,
6072
- this.analyticsStore,
6073
- { intervalMs: 3e4, batchSize: 500 }
6093
+ this.graduation
6074
6094
  );
6075
- this.syncWorker.start();
6095
+ this.graduationWorker.start();
6096
+ if (this.analyticsStore) {
6097
+ this.syncWorker = new SyncWorker(
6098
+ this.sqliteStore,
6099
+ this.analyticsStore,
6100
+ { intervalMs: 3e4, batchSize: 500 }
6101
+ );
6102
+ this.syncWorker.start();
6103
+ }
6076
6104
  }
6077
6105
  const savedMode = await this.sqliteStore.getEndlessConfig("mode");
6078
6106
  if (savedMode === "endless") {
@@ -6796,6 +6824,19 @@ var MemoryService = class {
6796
6824
  await this.initialize();
6797
6825
  await this.sqliteStore.recordRetrieval(eventId, sessionId, score, query);
6798
6826
  }
6827
+ /**
6828
+ * Record a query-level retrieval trace (used by user-prompt-submit hook).
6829
+ * Feeds the retrieval_traces table that powers dashboard stats.
6830
+ */
6831
+ async recordQueryTrace(input) {
6832
+ await this.initialize();
6833
+ await this.sqliteStore.recordRetrievalTrace({
6834
+ ...input,
6835
+ candidateDetails: [],
6836
+ selectedDetails: [],
6837
+ fallbackTrace: []
6838
+ });
6839
+ }
6799
6840
  /**
6800
6841
  * Evaluate helpfulness of retrievals in a session (called at session end)
6801
6842
  */
@@ -6803,6 +6844,20 @@ var MemoryService = class {
6803
6844
  await this.initialize();
6804
6845
  await this.sqliteStore.evaluateSessionHelpfulness(sessionId);
6805
6846
  }
6847
+ /**
6848
+ * Backfill helpfulness evaluation for sessions that ended without Stop hook.
6849
+ * Call on first turn of a new session to catch missed evaluations.
6850
+ */
6851
+ async evaluatePendingSessions(currentSessionId) {
6852
+ await this.initialize();
6853
+ const sessions = await this.sqliteStore.getUnevaluatedSessions(currentSessionId, 5);
6854
+ for (const sid of sessions) {
6855
+ try {
6856
+ await this.sqliteStore.evaluateSessionHelpfulness(sid);
6857
+ } catch {
6858
+ }
6859
+ }
6860
+ }
6806
6861
  /**
6807
6862
  * Get most helpful memories ranked by helpfulness score
6808
6863
  */