claude-memory-layer 1.0.33 → 1.0.34

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.
package/dist/mcp/index.js CHANGED
@@ -19859,7 +19859,8 @@ var HermesSessionHistoryImporter = class {
19859
19859
  source: "hermes",
19860
19860
  hermesSource: session.source,
19861
19861
  sourceSessionId: session.id,
19862
- sourceSessionHash: hashLabel(session.id)
19862
+ sourceSessionHash: hashLabel(session.id),
19863
+ projectPath: effectiveProjectPath
19863
19864
  }
19864
19865
  );
19865
19866
  if (appendResult.success && appendResult.isDuplicate) {
@@ -19896,7 +19897,8 @@ var HermesSessionHistoryImporter = class {
19896
19897
  source: "hermes",
19897
19898
  hermesSource: session.source,
19898
19899
  sourceSessionId: session.id,
19899
- sourceSessionHash: hashLabel(session.id)
19900
+ sourceSessionHash: hashLabel(session.id),
19901
+ projectPath: effectiveProjectPath
19900
19902
  }
19901
19903
  );
19902
19904
  if (appendResult.success && appendResult.isDuplicate) {
@@ -20445,7 +20447,7 @@ async function handleToolCall(name, args) {
20445
20447
  case "mem-details":
20446
20448
  return await handleMemDetails(memoryService, args);
20447
20449
  case "mem-stats":
20448
- return await handleMemStats(memoryService);
20450
+ return await handleMemStats(memoryService, args);
20449
20451
  case "mem-context-pack":
20450
20452
  return await handleMemContextPack(memoryService, args);
20451
20453
  case "mem-import-latest":
@@ -20481,19 +20483,19 @@ async function handleExternalMarketContext(args) {
20481
20483
  async function handleMemSearch(memoryService, args) {
20482
20484
  const query = args.query;
20483
20485
  const topK = Math.min(args.topK || 5, 20);
20484
- const result = await memoryService.retrieveMemories(query, {
20485
- topK,
20486
- sessionId: args.sessionId,
20487
- recordTrace: false
20488
- });
20486
+ const sessionId = args.sessionId;
20487
+ const search = await retrieveMcpMemories(memoryService, query, { topK, sessionId });
20489
20488
  const lines = [
20490
20489
  "## Memory Search Results",
20491
20490
  "",
20492
- `Found ${result.memories.length} relevant memories:`,
20491
+ `Found ${search.memories.length} relevant memories:`,
20493
20492
  ""
20494
20493
  ];
20495
- for (let i = 0; i < result.memories.length; i++) {
20496
- const m = result.memories[i];
20494
+ if (search.warning) {
20495
+ lines.push(search.warning, "");
20496
+ }
20497
+ for (let i = 0; i < search.memories.length; i++) {
20498
+ const m = search.memories[i];
20497
20499
  const citationId = generateCitationId(m.event.id);
20498
20500
  const date = m.event.timestamp.toISOString().split("T")[0];
20499
20501
  const preview = m.event.content.slice(0, 100) + (m.event.content.length > 100 ? "..." : "");
@@ -20508,6 +20510,52 @@ async function handleMemSearch(memoryService, args) {
20508
20510
  content: [{ type: "text", text: lines.join("\n") }]
20509
20511
  };
20510
20512
  }
20513
+ var SEMANTIC_VECTOR_FALLBACK_WARNING = "Warning: semantic/vector retrieval unavailable; used keyword fallback.";
20514
+ var SEMANTIC_VECTOR_FALLBACK_FAILED_WARNING = "Warning: semantic/vector retrieval unavailable; keyword fallback failed.";
20515
+ async function retrieveMcpMemories(memoryService, query, options) {
20516
+ try {
20517
+ const result = await memoryService.retrieveMemories(query, {
20518
+ topK: options.topK,
20519
+ sessionId: options.sessionId,
20520
+ recordTrace: false
20521
+ });
20522
+ return { memories: result.memories };
20523
+ } catch (error) {
20524
+ if (!isVectorSchemaMismatchError(error)) {
20525
+ throw error;
20526
+ }
20527
+ try {
20528
+ const memories = options.sessionId ? rankSessionKeywordMatches(
20529
+ query,
20530
+ await memoryService.getSessionHistory(options.sessionId),
20531
+ options.topK
20532
+ ) : await memoryService.keywordSearch(query, { topK: options.topK });
20533
+ return { memories, warning: SEMANTIC_VECTOR_FALLBACK_WARNING };
20534
+ } catch {
20535
+ return { memories: [], warning: SEMANTIC_VECTOR_FALLBACK_FAILED_WARNING };
20536
+ }
20537
+ }
20538
+ }
20539
+ function isVectorSchemaMismatchError(error) {
20540
+ const message = error instanceof Error ? error.message : String(error);
20541
+ return /no vector column/i.test(message) || /query vector dimension/i.test(message) || /vector[^\n]{0,80}dimension/i.test(message) || /dimension[^\n]{0,80}vector/i.test(message) || /lancedb[^\n]{0,120}schema/i.test(message);
20542
+ }
20543
+ function rankSessionKeywordMatches(query, events, topK) {
20544
+ const queryTokens = tokenizeKeywordQuery(query);
20545
+ if (queryTokens.length === 0)
20546
+ return [];
20547
+ return events.map((event) => ({ event, score: scoreKeywordMatch(event.content, queryTokens) })).filter((match) => match.score > 0).sort((a, b) => b.score - a.score || b.event.timestamp.getTime() - a.event.timestamp.getTime()).slice(0, topK);
20548
+ }
20549
+ function tokenizeKeywordQuery(value) {
20550
+ return Array.from(new Set(
20551
+ value.toLowerCase().split(/[^a-z0-9가-힣_]+/).map((token) => token.trim()).filter((token) => token.length > 1)
20552
+ ));
20553
+ }
20554
+ function scoreKeywordMatch(content, queryTokens) {
20555
+ const haystack = content.toLowerCase();
20556
+ const hits = queryTokens.filter((token) => haystack.includes(token)).length;
20557
+ return hits / queryTokens.length;
20558
+ }
20511
20559
  async function handleMemTimeline(memoryService, args) {
20512
20560
  const ids = args.ids;
20513
20561
  const windowSize = args.windowSize || 3;
@@ -20599,10 +20647,8 @@ async function handleMemContextPack(memoryService, args) {
20599
20647
  sessionsDir: optionalString(args.sessionsDir),
20600
20648
  stateDb: optionalString(args.stateDb)
20601
20649
  }) : void 0;
20602
- const [searchResult, recentEvents] = await Promise.all([
20603
- memoryService.retrieveMemories(query, { topK: retrievalTopK, sessionId, recordTrace: false }),
20604
- memoryService.getRecentEvents(recentLimit)
20605
- ]);
20650
+ const search = await retrieveMcpMemories(memoryService, query, { topK: retrievalTopK, sessionId });
20651
+ const recentEvents = await memoryService.getRecentEvents(recentLimit);
20606
20652
  const timelineEvents = selectContextPackTimelineEvents(
20607
20653
  recentEvents,
20608
20654
  projectPath,
@@ -20610,7 +20656,7 @@ async function handleMemContextPack(memoryService, args) {
20610
20656
  );
20611
20657
  const sessions = summarizeSessions(timelineEvents, sessionLimit);
20612
20658
  const recentSessionIds = new Set(sessions.map((session) => session.sessionId));
20613
- const relevantMemories = selectContextPackMemories(searchResult.memories, {
20659
+ const relevantMemories = selectContextPackMemories(search.memories, {
20614
20660
  genericContinuationQuery,
20615
20661
  topK,
20616
20662
  recentSessionIds,
@@ -20631,6 +20677,9 @@ async function handleMemContextPack(memoryService, args) {
20631
20677
  `- Refresh limits: sessions=${freshnessRun.sessionLimit} messages=${freshnessRun.messageLimit} force=${freshnessRun.force ? "yes" : "no"} embeddings=${freshnessRun.processEmbeddings ? `processed ${freshnessRun.embeddingsProcessed ?? 0}` : "skipped"}`
20632
20678
  );
20633
20679
  }
20680
+ if (search.warning) {
20681
+ lines.push(`- ${search.warning}`);
20682
+ }
20634
20683
  if (genericContinuationQuery) {
20635
20684
  lines.push("- Generic continuation query: recent project timeline prioritized.");
20636
20685
  }
@@ -20870,7 +20919,7 @@ function shouldShowContextPackTimelineEvent(event, projectPath, genericContinuat
20870
20919
  return false;
20871
20920
  if (event.eventType === "tool_observation")
20872
20921
  return false;
20873
- if (mentionsDifferentWorkspaceProject(content, projectPath))
20922
+ if (eventBelongsToDifferentProject(event, projectPath))
20874
20923
  return false;
20875
20924
  if (genericContinuationQuery && isGenericContinuationQuery(content))
20876
20925
  return false;
@@ -20882,7 +20931,7 @@ function shouldShowContextPackMemory(memory, options) {
20882
20931
  return false;
20883
20932
  if (memory.event.eventType === "tool_observation")
20884
20933
  return false;
20885
- if (mentionsDifferentWorkspaceProject(content, options.projectPath))
20934
+ if (eventBelongsToDifferentProject(memory.event, options.projectPath))
20886
20935
  return false;
20887
20936
  if (!options.genericContinuationQuery)
20888
20937
  return true;
@@ -20894,6 +20943,54 @@ function shouldShowContextPackMemory(memory, options) {
20894
20943
  return memory.score >= GENERIC_RECENT_MEMORY_MIN_SCORE;
20895
20944
  return memory.score >= GENERIC_STALE_MEMORY_MIN_SCORE;
20896
20945
  }
20946
+ function eventBelongsToDifferentProject(event, projectPath) {
20947
+ if (!projectPath)
20948
+ return false;
20949
+ const metadata = event.metadata || {};
20950
+ const metadataProjectRefs = metadataProjectReferenceValues(metadata);
20951
+ if (metadataProjectRefs.length > 0) {
20952
+ return !metadataProjectRefs.some((value) => projectReferenceMatches(value, projectPath));
20953
+ }
20954
+ if (isUnscopedImportedHistory(metadata))
20955
+ return true;
20956
+ return mentionsDifferentWorkspaceProject(event.content || "", projectPath);
20957
+ }
20958
+ function isUnscopedImportedHistory(metadata) {
20959
+ return typeof metadata.importedFrom === "string" || typeof metadata.sourceSessionId === "string" || typeof metadata.sourceSessionHash === "string" || typeof metadata.transcriptPath === "string";
20960
+ }
20961
+ var PROJECT_METADATA_KEYS = /* @__PURE__ */ new Set([
20962
+ "projectPath",
20963
+ "sourceProjectPath",
20964
+ "workspacePath",
20965
+ "sourceWorkspacePath",
20966
+ "cwd",
20967
+ "sourceCwd",
20968
+ "currentWorkingDirectory",
20969
+ "projectRoot",
20970
+ "repoPath",
20971
+ "repositoryPath"
20972
+ ]);
20973
+ function metadataProjectReferenceValues(metadata) {
20974
+ const values = [];
20975
+ for (const [key, value] of Object.entries(metadata)) {
20976
+ if (!PROJECT_METADATA_KEYS.has(key))
20977
+ continue;
20978
+ if (typeof value === "string" && value.trim().length > 0) {
20979
+ values.push(value.trim());
20980
+ }
20981
+ }
20982
+ return values;
20983
+ }
20984
+ function projectReferenceMatches(reference, projectPath) {
20985
+ const normalizedReference = normalizeProjectReference(reference);
20986
+ const normalizedProjectPath = normalizeProjectReference(projectPath);
20987
+ if (normalizedReference === normalizedProjectPath)
20988
+ return true;
20989
+ return normalizedReference.startsWith(`${normalizedProjectPath}/`);
20990
+ }
20991
+ function normalizeProjectReference(value) {
20992
+ return value.trim().replace(/\\/g, "/").replace(/\/+$/g, "").toLowerCase();
20993
+ }
20897
20994
  function mentionsDifferentWorkspaceProject(content, projectPath) {
20898
20995
  const currentProject = basenameOfPath(projectPath);
20899
20996
  if (!currentProject)
@@ -21124,9 +21221,11 @@ function formatMetadataValue(value) {
21124
21221
  function textResult(text) {
21125
21222
  return { content: [{ type: "text", text }] };
21126
21223
  }
21127
- async function handleMemStats(memoryService) {
21224
+ async function handleMemStats(memoryService, args) {
21128
21225
  const stats = await memoryService.getStats();
21129
21226
  const recentEvents = await memoryService.getRecentEvents(1e4);
21227
+ const outboxStats = await readMcpOutboxStats(memoryService);
21228
+ const storageView = buildMcpStatsStorageView(optionalString(args.projectPath));
21130
21229
  const uniqueSessions = new Set(recentEvents.map((e) => e.sessionId));
21131
21230
  const lines = [
21132
21231
  "## Memory Statistics",
@@ -21135,6 +21234,19 @@ async function handleMemStats(memoryService) {
21135
21234
  `- **Total Vectors**: ${stats.vectorCount}`,
21136
21235
  `- **Sessions**: ${uniqueSessions.size}`,
21137
21236
  "",
21237
+ "### Storage View / Freshness",
21238
+ "",
21239
+ `- Storage View: ${storageView.storageView}`,
21240
+ `- Storage Path Label: ${storageView.storagePathLabel}`,
21241
+ `- Embedder Model: ${storageView.embedderModel}`,
21242
+ `- Vector Table Dimension: ${storageView.vectorTableDimension}`,
21243
+ `- Pending Embeddings: ${outboxStats.embedding.pending}`,
21244
+ `- Embedding Outbox: pending=${outboxStats.embedding.pending}, processing=${outboxStats.embedding.processing}, failed=${outboxStats.embedding.failed}, total=${outboxStats.embedding.total}`,
21245
+ `- Vector Outbox Pending: ${outboxStats.vector.pending}`,
21246
+ `- Vector Outbox: pending=${outboxStats.vector.pending}, processing=${outboxStats.vector.processing}, failed=${outboxStats.vector.failed}, total=${outboxStats.vector.total}`,
21247
+ "- MCP/CLI parity: CLI `stats -p <project>` and MCP `mem-stats(projectPath=...)` should use this same storage view label.",
21248
+ "- Restart guidance: if CLI and MCP counts differ for this storage view after import/build, restart the long-lived MCP/Hermes gateway process.",
21249
+ "",
21138
21250
  "### Events by Type",
21139
21251
  ""
21140
21252
  ];
@@ -21149,6 +21261,35 @@ async function handleMemStats(memoryService) {
21149
21261
  content: [{ type: "text", text: lines.join("\n") }]
21150
21262
  };
21151
21263
  }
21264
+ async function readMcpOutboxStats(memoryService) {
21265
+ try {
21266
+ return await memoryService.getOutboxStats();
21267
+ } catch {
21268
+ return {
21269
+ embedding: { pending: 0, processing: 0, failed: 0, total: 0 },
21270
+ vector: { pending: 0, processing: 0, failed: 0, total: 0 }
21271
+ };
21272
+ }
21273
+ }
21274
+ function buildMcpStatsStorageView(projectPath) {
21275
+ const embedderModel = process.env.CLAUDE_MEMORY_EMBEDDING_MODEL || DEFAULT_EMBEDDING_MODEL;
21276
+ const requestedProjectPath = projectPath?.trim();
21277
+ if (requestedProjectPath) {
21278
+ const projectHash = hashProjectPath(requestedProjectPath);
21279
+ return {
21280
+ storageView: `project:${projectHash}`,
21281
+ storagePathLabel: `~/.claude-code/memory/projects/${projectHash}`,
21282
+ embedderModel,
21283
+ vectorTableDimension: "unknown (not recorded in current vector metadata)"
21284
+ };
21285
+ }
21286
+ return {
21287
+ storageView: "global",
21288
+ storagePathLabel: "~/.claude-code/memory",
21289
+ embedderModel,
21290
+ vectorTableDimension: "unknown (not recorded in current vector metadata)"
21291
+ };
21292
+ }
21152
21293
 
21153
21294
  // src/extensions/mcp/index.ts
21154
21295
  var server = new Server(