open-mem 0.7.0 → 0.7.2

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 (111) hide show
  1. package/CHANGELOG.md +23 -3
  2. package/README.md +77 -27
  3. package/dist/adapters/http/server.d.ts +15 -1
  4. package/dist/adapters/http/server.d.ts.map +1 -1
  5. package/dist/adapters/http/sse.d.ts +16 -1
  6. package/dist/adapters/http/sse.d.ts.map +1 -1
  7. package/dist/adapters/mcp/server.d.ts +25 -1
  8. package/dist/adapters/mcp/server.d.ts.map +1 -1
  9. package/dist/adapters/opencode/tools.d.ts.map +1 -1
  10. package/dist/adapters/platform/bridge-client.d.ts +32 -0
  11. package/dist/adapters/platform/bridge-client.d.ts.map +1 -0
  12. package/dist/adapters/platform/builtin.d.ts +6 -0
  13. package/dist/adapters/platform/builtin.d.ts.map +1 -0
  14. package/dist/adapters/platform/claude-code.d.ts +7 -0
  15. package/dist/adapters/platform/claude-code.d.ts.map +1 -0
  16. package/dist/adapters/platform/cursor.d.ts +7 -0
  17. package/dist/adapters/platform/cursor.d.ts.map +1 -0
  18. package/dist/adapters/platform/index.d.ts +9 -0
  19. package/dist/adapters/platform/index.d.ts.map +1 -0
  20. package/dist/adapters/platform/normalize.d.ts +14 -0
  21. package/dist/adapters/platform/normalize.d.ts.map +1 -0
  22. package/dist/adapters/platform/opencode.d.ts +7 -0
  23. package/dist/adapters/platform/opencode.d.ts.map +1 -0
  24. package/dist/adapters/platform/runtime.d.ts +27 -0
  25. package/dist/adapters/platform/runtime.d.ts.map +1 -0
  26. package/dist/adapters/platform/types.d.ts +53 -0
  27. package/dist/adapters/platform/types.d.ts.map +1 -0
  28. package/dist/ai/compressor.d.ts.map +1 -1
  29. package/dist/ai/conflict-evaluator.d.ts.map +1 -1
  30. package/dist/ai/entity-extractor.d.ts +2 -2
  31. package/dist/ai/entity-extractor.d.ts.map +1 -1
  32. package/dist/ai/parser.d.ts.map +1 -1
  33. package/dist/ai/prompts.d.ts.map +1 -1
  34. package/dist/ai/summarizer.d.ts.map +1 -1
  35. package/dist/claude-code.d.ts +3 -0
  36. package/dist/claude-code.d.ts.map +1 -0
  37. package/dist/claude-code.js +551 -0
  38. package/dist/config/store.d.ts.map +1 -1
  39. package/dist/config.d.ts.map +1 -1
  40. package/dist/context/builder.d.ts.map +1 -1
  41. package/dist/contracts/api.d.ts +129 -0
  42. package/dist/contracts/api.d.ts.map +1 -0
  43. package/dist/core/contracts.d.ts +67 -1
  44. package/dist/core/contracts.d.ts.map +1 -1
  45. package/dist/core/memory-engine.d.ts +33 -2
  46. package/dist/core/memory-engine.d.ts.map +1 -1
  47. package/dist/cursor.d.ts +3 -0
  48. package/dist/cursor.d.ts.map +1 -0
  49. package/dist/cursor.js +551 -0
  50. package/dist/daemon.js +146 -122
  51. package/dist/dashboard/assets/index-BTEnO15N.js +63 -0
  52. package/dist/dashboard/assets/index-o3hCx7_v.css +1 -0
  53. package/dist/dashboard/index.html +2 -2
  54. package/dist/db/config-audit.d.ts +10 -0
  55. package/dist/db/config-audit.d.ts.map +1 -0
  56. package/dist/db/entities.d.ts.map +1 -1
  57. package/dist/db/maintenance-history.d.ts +9 -0
  58. package/dist/db/maintenance-history.d.ts.map +1 -0
  59. package/dist/db/observations.d.ts +12 -0
  60. package/dist/db/observations.d.ts.map +1 -1
  61. package/dist/db/schema.d.ts +3 -1
  62. package/dist/db/schema.d.ts.map +1 -1
  63. package/dist/db/user-memory.d.ts.map +1 -1
  64. package/dist/hooks/chat-capture.d.ts +11 -0
  65. package/dist/hooks/chat-capture.d.ts.map +1 -1
  66. package/dist/hooks/context-inject.d.ts.map +1 -1
  67. package/dist/hooks/session-events.d.ts +10 -0
  68. package/dist/hooks/session-events.d.ts.map +1 -1
  69. package/dist/hooks/tool-capture.d.ts +12 -0
  70. package/dist/hooks/tool-capture.d.ts.map +1 -1
  71. package/dist/index.d.ts +5 -3
  72. package/dist/index.d.ts.map +1 -1
  73. package/dist/index.js +226 -225
  74. package/dist/maintenance.js +159 -132
  75. package/dist/mcp.js +187 -187
  76. package/dist/platform-worker.d.ts +3 -0
  77. package/dist/platform-worker.d.ts.map +1 -0
  78. package/dist/queue/processor.d.ts +26 -1
  79. package/dist/queue/processor.d.ts.map +1 -1
  80. package/dist/runtime/metrics.d.ts +43 -0
  81. package/dist/runtime/metrics.d.ts.map +1 -0
  82. package/dist/search/graph.d.ts.map +1 -1
  83. package/dist/search/orchestrator.d.ts +1 -0
  84. package/dist/search/orchestrator.d.ts.map +1 -1
  85. package/dist/search/reranker.d.ts +1 -1
  86. package/dist/search/reranker.d.ts.map +1 -1
  87. package/dist/store/ports.d.ts +9 -0
  88. package/dist/store/ports.d.ts.map +1 -1
  89. package/dist/store/sqlite/adapters.d.ts.map +1 -1
  90. package/dist/tools/recall.d.ts.map +1 -1
  91. package/dist/tools/save.d.ts +1 -1
  92. package/dist/tools/save.d.ts.map +1 -1
  93. package/dist/types.d.ts +64 -0
  94. package/dist/types.d.ts.map +1 -1
  95. package/dist/utils/agents-md.d.ts.map +1 -1
  96. package/dist/utils/folder-context-maintenance.d.ts.map +1 -1
  97. package/package.json +27 -6
  98. package/dist/dashboard/assets/index-9JxqY10c.css +0 -1
  99. package/dist/dashboard/assets/index-DWbZtwHB.js +0 -60
  100. package/dist/dashboard/dist/assets/index-9JxqY10c.css +0 -1
  101. package/dist/dashboard/dist/assets/index-CGCNZcwT.js +0 -60
  102. package/dist/dashboard/dist/assets/index-CI60x_dC.css +0 -1
  103. package/dist/dashboard/dist/assets/index-CTwrdVhA.js +0 -60
  104. package/dist/dashboard/dist/assets/index-DWbZtwHB.js +0 -60
  105. package/dist/dashboard/dist/index.html +0 -19
  106. package/dist/servers/http-server.d.ts +0 -22
  107. package/dist/servers/http-server.d.ts.map +0 -1
  108. package/dist/servers/mcp-server.d.ts +0 -27
  109. package/dist/servers/mcp-server.d.ts.map +0 -1
  110. package/dist/servers/sse-broadcaster.d.ts +0 -27
  111. package/dist/servers/sse-broadcaster.d.ts.map +0 -1
package/dist/mcp.js CHANGED
@@ -1,102 +1,109 @@
1
1
  #!/usr/bin/env bun
2
2
  // @bun
3
- var G=import.meta.require;import{readFileSync as S2}from"fs";import{join as M2}from"path";import{parseArgs as Q2}from"util";var b$={"claude-sonnet-4-20250514":"us.anthropic.claude-sonnet-4-20250514-v1:0","claude-opus-4-20250514":"us.anthropic.claude-opus-4-20250514-v1:0","claude-3-5-sonnet-20241022":"us.anthropic.claude-3-5-sonnet-20241022-v2:0","claude-3-5-haiku-20241022":"us.anthropic.claude-3-5-haiku-20241022-v1:0","claude-3-haiku-20240307":"anthropic.claude-3-haiku-20240307-v1:0"};function l$($){if($.includes("."))return $;return b$[$]||`us.anthropic.${$}-v1:0`}function e($){switch($.provider){case"anthropic":{let{createAnthropic:J}=G("@ai-sdk/anthropic");return J({apiKey:$.apiKey})($.model)}case"bedrock":{let{createAmazonBedrock:J}=G("@ai-sdk/amazon-bedrock");return J()(l$($.model))}case"openai":{let{createOpenAI:J}=G("@ai-sdk/openai");return J({apiKey:$.apiKey})($.model)}case"google":{let{createGoogleGenerativeAI:J}=G("@ai-sdk/google");return J({apiKey:$.apiKey})($.model)}default:throw Error(`Unknown provider: ${$.provider}. Supported: anthropic, bedrock, openai, google`)}}function o($){try{switch($.provider){case"google":{let{createGoogleGenerativeAI:J}=G("@ai-sdk/google");return J({apiKey:$.apiKey}).embedding("text-embedding-004")}case"openai":{let{createOpenAI:J}=G("@ai-sdk/openai");return J({apiKey:$.apiKey}).embedding("text-embedding-3-small")}case"bedrock":{let{createAmazonBedrock:J}=G("@ai-sdk/amazon-bedrock");return J().embedding("amazon.titan-embed-text-v2:0")}case"anthropic":return null;default:return null}}catch{return null}}import{existsSync as d$,readFileSync as i$}from"fs";var r$={dbPath:".open-mem/memory.db",provider:"google",apiKey:void 0,model:"gemini-2.5-flash-lite",maxTokensPerCompression:1024,compressionEnabled:!0,contextInjectionEnabled:!0,maxContextTokens:4000,batchSize:5,batchIntervalMs:30000,ignoredTools:[],minOutputLength:50,maxIndexEntries:20,sensitivePatterns:[],retentionDays:90,maxDatabaseSizeMb:500,logLevel:"warn",contextShowTokenCosts:!0,contextObservationTypes:"all",contextFullObservationCount:3,maxObservations:50,contextShowLastSummary:!0,rateLimitingEnabled:!0,folderContextEnabled:!0,folderContextMaxDepth:5,daemonEnabled:!1,dashboardEnabled:!1,dashboardPort:3737,embeddingDimension:void 0,conflictResolutionEnabled:!1,conflictSimilarityBandLow:0.7,conflictSimilarityBandHigh:0.92,userMemoryEnabled:!1,userMemoryDbPath:"~/.config/open-mem/user-memory.db",userMemoryMaxContextTokens:1000,rerankingEnabled:!1,rerankingMaxCandidates:20,entityExtractionEnabled:!1};function t$(){let $={};if(process.env.OPEN_MEM_DB_PATH)$.dbPath=process.env.OPEN_MEM_DB_PATH;if(process.env.OPEN_MEM_PROVIDER)$.provider=process.env.OPEN_MEM_PROVIDER;if(process.env.OPEN_MEM_MODEL)$.model=process.env.OPEN_MEM_MODEL;if(process.env.OPEN_MEM_MAX_CONTEXT_TOKENS)$.maxContextTokens=Number.parseInt(process.env.OPEN_MEM_MAX_CONTEXT_TOKENS,10);if(process.env.OPEN_MEM_COMPRESSION==="false")$.compressionEnabled=!1;if(process.env.OPEN_MEM_CONTEXT_INJECTION==="false")$.contextInjectionEnabled=!1;if(process.env.OPEN_MEM_IGNORED_TOOLS)$.ignoredTools=process.env.OPEN_MEM_IGNORED_TOOLS.split(",").map((J)=>J.trim());if(process.env.OPEN_MEM_BATCH_SIZE)$.batchSize=Number.parseInt(process.env.OPEN_MEM_BATCH_SIZE,10);if(process.env.OPEN_MEM_RETENTION_DAYS)$.retentionDays=Number.parseInt(process.env.OPEN_MEM_RETENTION_DAYS,10);if(process.env.OPEN_MEM_LOG_LEVEL)$.logLevel=process.env.OPEN_MEM_LOG_LEVEL;if(process.env.OPEN_MEM_CONTEXT_SHOW_TOKEN_COSTS==="false")$.contextShowTokenCosts=!1;if(process.env.OPEN_MEM_CONTEXT_TYPES)$.contextObservationTypes=process.env.OPEN_MEM_CONTEXT_TYPES==="all"?"all":process.env.OPEN_MEM_CONTEXT_TYPES.split(",").map((J)=>J.trim());if(process.env.OPEN_MEM_CONTEXT_FULL_COUNT)$.contextFullObservationCount=Number.parseInt(process.env.OPEN_MEM_CONTEXT_FULL_COUNT,10);if(process.env.OPEN_MEM_MAX_OBSERVATIONS)$.maxObservations=Number.parseInt(process.env.OPEN_MEM_MAX_OBSERVATIONS,10);if(process.env.OPEN_MEM_CONTEXT_SHOW_LAST_SUMMARY==="false")$.contextShowLastSummary=!1;if(process.env.OPEN_MEM_RATE_LIMITING==="false")$.rateLimitingEnabled=!1;if(process.env.OPEN_MEM_FOLDER_CONTEXT==="false")$.folderContextEnabled=!1;if(process.env.OPEN_MEM_FOLDER_CONTEXT_MAX_DEPTH)$.folderContextMaxDepth=Number.parseInt(process.env.OPEN_MEM_FOLDER_CONTEXT_MAX_DEPTH,10);if(process.env.OPEN_MEM_DAEMON==="true")$.daemonEnabled=!0;if(process.env.OPEN_MEM_DASHBOARD==="true")$.dashboardEnabled=!0;if(process.env.OPEN_MEM_DASHBOARD_PORT)$.dashboardPort=Number.parseInt(process.env.OPEN_MEM_DASHBOARD_PORT,10);if(process.env.OPEN_MEM_EMBEDDING_DIMENSION)$.embeddingDimension=Number.parseInt(process.env.OPEN_MEM_EMBEDDING_DIMENSION,10);if(process.env.OPEN_MEM_CONFLICT_RESOLUTION==="true")$.conflictResolutionEnabled=!0;if(process.env.OPEN_MEM_CONFLICT_BAND_LOW){let J=Number.parseFloat(process.env.OPEN_MEM_CONFLICT_BAND_LOW);if(!Number.isNaN(J))$.conflictSimilarityBandLow=J}if(process.env.OPEN_MEM_CONFLICT_BAND_HIGH){let J=Number.parseFloat(process.env.OPEN_MEM_CONFLICT_BAND_HIGH);if(!Number.isNaN(J))$.conflictSimilarityBandHigh=J}if(process.env.OPEN_MEM_USER_MEMORY==="true")$.userMemoryEnabled=!0;if(process.env.OPEN_MEM_USER_MEMORY_DB_PATH)$.userMemoryDbPath=process.env.OPEN_MEM_USER_MEMORY_DB_PATH;if(process.env.OPEN_MEM_USER_MEMORY_MAX_TOKENS)$.userMemoryMaxContextTokens=Number.parseInt(process.env.OPEN_MEM_USER_MEMORY_MAX_TOKENS,10);if(process.env.OPEN_MEM_RERANKING==="true")$.rerankingEnabled=!0;if(process.env.OPEN_MEM_RERANKING_MAX_CANDIDATES)$.rerankingMaxCandidates=Number.parseInt(process.env.OPEN_MEM_RERANKING_MAX_CANDIDATES,10);if(process.env.OPEN_MEM_ENTITY_EXTRACTION==="true")$.entityExtractionEnabled=!0;return $}function e$($){let J=`${$}/.open-mem/config.json`;if(!d$(J))return{};try{let S=i$(J,"utf-8"),M=JSON.parse(S);if(!M||typeof M!=="object"||Array.isArray(M))return{};return M}catch{return{}}}function o$($){switch($){case"google":return 768;case"openai":return 1536;case"bedrock":return 1024;case"anthropic":return 0;default:return 768}}function s($,J){let S=e$($),M=t$(),Q={...r$,...S,...M,...J};if(!Q.dbPath.startsWith("/"))Q.dbPath=`${$}/${Q.dbPath}`;if(!process.env.OPEN_MEM_PROVIDER&&!J?.provider){if(process.env.GOOGLE_GENERATIVE_AI_API_KEY||process.env.GEMINI_API_KEY)Q.provider="google";else if(process.env.ANTHROPIC_API_KEY)Q.provider="anthropic";else if(process.env.AWS_BEARER_TOKEN_BEDROCK||process.env.AWS_ACCESS_KEY_ID||process.env.AWS_PROFILE)Q.provider="bedrock"}if(!Q.apiKey)switch(Q.provider){case"google":Q.apiKey=process.env.GOOGLE_GENERATIVE_AI_API_KEY||process.env.GEMINI_API_KEY;break;case"anthropic":Q.apiKey=process.env.ANTHROPIC_API_KEY;break;case"openai":Q.apiKey=process.env.OPENAI_API_KEY;break;case"bedrock":break}if(Q.embeddingDimension===void 0)Q.embeddingDimension=o$(Q.provider);return Q}function s$($,J){let S=new RegExp(`<${J}[^>]*>([\\s\\S]*?)</${J}>`,"i"),M=$.match(S);return M?M[1].trim():""}function a$($,J){let S=new RegExp(`<${J}[^>]*>([\\s\\S]*?)</${J}>`,"gi"),M=[];for(let Q of $.matchAll(S)){let Z=Q[1].trim();if(Z)M.push(Z)}return M}function a($){let J=s$($,"reranked");if(!J)return null;let S=a$(J,"index");if(S.length===0)return null;let M=[];for(let Q of S){let Z=Number.parseInt(Q,10);if(Number.isNaN(Z)||Z<0)return null;M.push(Z)}return M}function N($){return Math.ceil($.length/4)}var $0={showTokenCosts:!0,observationTypes:"all",fullObservationCount:3,showLastSummary:!0},E={bugfix:"\uD83D\uDD34",feature:"\uD83D\uDFE3",refactor:"\uD83D\uDD04",change:"\u2705",discovery:"\uD83D\uDD35",decision:"\u2696\uFE0F"};function $$($,J=$0){let S=[];if(S.push("## open-mem: Past Session Memory"),S.push(""),S.push("**\uD83D\uDCA1 Progressive Disclosure:** This is a compact index showing WHAT was observed and retrieval COST."),S.push("Use `mem-search` to find observations by query, then `mem-recall` with IDs to fetch full details."),S.push(""),S.push("**3-Layer Memory Access:**"),S.push("- **Layer 1** `mem-search` \u2014 Find observations by query (returns IDs + summaries)"),S.push("- **Layer 2** `mem-timeline` \u2014 Browse session history and drill into sessions"),S.push("- **Layer 3** `mem-recall` \u2014 Get full details by ID (use IDs from search results or the index below)"),J.showLastSummary&&$.recentSummaries.length>0){S.push(""),S.push("### Recent Sessions"),S.push("| Session | Summary | Decisions |"),S.push("|---------|---------|-----------|");for(let X of $.recentSummaries){let U=X.keyDecisions.length>0?X.keyDecisions.join("; "):"\u2014";S.push(`| ${X.sessionId} | ${X.summary} | ${U} |`)}}let M=J.observationTypes==="all"?$.observationIndex:$.observationIndex.filter((X)=>J.observationTypes.includes(X.type));if(M.length>0){S.push(""),S.push(`### Recent Observations (${M.length} entries)`);let X=S0(M,$.fullObservations);for(let[U,K]of X){if(S.push(""),S.push(`**${U}**`),J.showTokenCosts)S.push("| ID | Type | Title | ~Tokens |"),S.push("|----|------|-------|---------|");else S.push("| ID | Type | Title |"),S.push("|----|------|-------|");for(let W of K){let V=E[W.type]||"\uD83D\uDCDD";if(J.showTokenCosts)S.push(`| ${W.id} | ${V} | ${W.title} | ~${W.tokenCount} |`);else S.push(`| ${W.id} | ${V} | ${W.title} |`)}}}let Q=$.fullObservations.slice(0,J.fullObservationCount);if(Q.length>0){S.push(""),S.push("### Full Details (most recent)");for(let X of Q){let U=E[X.type]||"\uD83D\uDCDD";if(S.push(""),S.push(`#### ${U} ${X.title} (${X.id})`),S.push(X.narrative),X.facts.length>0)S.push(`**Facts:** ${X.facts.map((W)=>`- ${W}`).join(" ")}`);if(X.concepts.length>0)S.push(`**Concepts:** ${X.concepts.join(", ")}`);let K=[...X.filesRead,...X.filesModified];if(K.length>0)S.push(`**Files:** ${K.join(", ")}`)}}let Z=J0($);if(Z)S.push(""),S.push(Z);return S.join(`
4
- `)}function J0($){let J=0,S=0,M=new Set($.observationIndex.map((X)=>X.id));for(let X of $.observationIndex)J+=X.tokenCount,S+=X.discoveryTokens;for(let X of $.fullObservations)if(!M.has(X.id))J+=X.tokenCount,S+=X.discoveryTokens;if(S===0)return null;let Q=S-J,Z=Math.max(0,Math.round(Q/S*100));return`### \uD83D\uDCB0 Memory Economics
5
- **Read cost:** ~${J}t | **Discovery cost:** ~${S}t | **Savings:** ${Z}% (${Q}t saved)`}function S0($,J){let S=new Map;for(let Q of J){let Z=Q.filesModified[0]||Q.filesRead[0];if(Z)S.set(Q.id,Z)}let M=new Map;for(let Q of $){let Z=S.get(Q.id)??"General",X=M.get(Z)??[];X.push(Q),M.set(Z,X)}return M}function J$($){let J=[];if(J.push("[open-mem] Memory context:"),$.recentSummaries.length>0){J.push(`
6
- Recent sessions:`);for(let S of $.recentSummaries)J.push(`- ${S.summary}`)}if($.observationIndex.length>0){J.push(`
7
- Recent observations (${$.observationIndex.length} entries):`);for(let S of $.observationIndex)J.push(`- ${E[S.type]||"\uD83D\uDCDD"} ${S.title}`)}return J.join(`
8
- `)}function S$($,J){if($.length===0)return"";let S=J,M=[];for(let Z of $){let X=Z.tokenCount||N(Z.title);if(S-X<0)break;M.push(Z),S-=X}if(M.length===0)return"";let Q=[];Q.push("### Cross-Project Memory"),Q.push(""),Q.push("| ID | Type | Title | ~Tokens |"),Q.push("|----|------|-------|---------|");for(let Z of M){let X=E[Z.type]||"\uD83D\uDCDD";Q.push(`| ${Z.id} | ${X} | ${Z.title} | ~${Z.tokenCount} |`)}return Q.join(`
9
- `)}function M$($,J){if($.length===0)return"";let S=J,M=[];for(let Z of $){let X=Z.tokenCount||N(Z.title);if(S-X<0)break;M.push(Z),S-=X}if(M.length===0)return"";let Q=[];Q.push(`
10
- Cross-project observations (${M.length} entries):`);for(let Z of M)Q.push(`- ${E[Z.type]||"\uD83D\uDCDD"} ${Z.title}`);return Q.join(`
11
- `)}var D={recency:0.4,typeImportance:0.3,sessionAffinity:0.2,tokenEfficiency:0.1},M0={decision:1,bugfix:0.9,feature:0.8,refactor:0.6,discovery:0.5,change:0.4};function Q0($,J){let S=new Date($),Q=(J.getTime()-S.getTime())/3600000;if(Q<0)return 1;if(Q<24)return 1;if(Q<48)return 0.8;if(Q<168)return 0.5;return 0.2}function Z0($){return M0[$]??0.3}function X0($,J){if(!J)return 0.5;return $===J?1:0.3}function U0($){if($<=10)return 1;if($>=200)return 0.2;return 1-($-10)/190*0.8}function K0($,J){let S=Q0($.createdAt,J.now),M=Z0($.type),Q=X0($.sessionId,J.currentSessionId),Z=U0($.tokenCount);return S*D.recency+M*D.typeImportance+Q*D.sessionAffinity+Z*D.tokenEfficiency}function Q$($,J){let S=new Map;for(let M of $)S.set(M.id,K0(M,J));return[...$].sort((M,Q)=>{let Z=S.get(M.id)??0,X=S.get(Q.id)??0;if(X!==Z)return X-Z;return new Date(Q.createdAt).getTime()-new Date(M.createdAt).getTime()})}function Z$($,J,S,M,Q=[],Z){let X=M,U=[],K=[];for(let V of J){let H=V.tokenCount||N(V.summary);if(X-H<0)break;U.push(V),X-=H}let W=Z?Q$(S,Z):S;for(let V of W){let H=V.tokenCount||N(V.title);if(X-H<0)break;K.push(V),X-=H}return{recentSummaries:U,observationIndex:K,fullObservations:[...Q],totalTokens:M-X}}import{existsSync as h0}from"fs";import{readdir as j0,readFile as D0,writeFile as R0}from"fs/promises";import{join as f0,resolve as C0}from"path";import{existsSync as U$}from"fs";import{mkdir as W0,readFile as V0,rename as Y0,unlink as H0,writeFile as N0}from"fs/promises";import{dirname as q,isAbsolute as K$,join as f,normalize as z0,relative as W$,resolve as P,sep as I}from"path";var R="<!-- open-mem-context -->",h="<!-- /open-mem-context -->",G0={bugfix:"\uD83D\uDD34",feature:"\uD83D\uDFE3",refactor:"\uD83D\uDD04",change:"\u2705",discovery:"\uD83D\uDD35",decision:"\u2696\uFE0F"},X$=new Map,B0=new Set(["node_modules",".git","dist","coverage",".open-mem","build","__pycache__",".next",".nuxt"]);async function V$($,J,S=5){if(J.length===0)return;let M=[];for(let X of J){for(let U of X.filesModified)M.push(U);for(let U of X.filesRead)M.push(U)}let Q=A0(M,$,S);if(Q.size===0)return;let Z=E0(J,Q,$);for(let[X,U]of Z)try{let K=L0(X,U,$);await F0(X,K)}catch(K){console.error(`[open-mem] Failed to update AGENTS.md in ${X}:`,K)}}function L0($,J,S){let M=[...J].sort((K,W)=>W.createdAt.localeCompare(K.createdAt)).slice(0,10),Q=W$(S,$)||".",Z=[];Z.push(`## Recent Activity in \`${Q}/\` (auto-generated by open-mem)`),Z.push(""),Z.push("| Type | Title | Date |"),Z.push("|------|-------|------|");for(let K of M){let W=G0[K.type]||"\uD83D\uDCDD",V=K.createdAt.split("T")[0],H=K.title.replace(/\|/g,"\\|");Z.push(`| ${W} ${K.type} | ${H} | ${V} |`)}let X=new Set;for(let K of M)for(let W of K.concepts)X.add(W);if(X.size>0){let K=[...X].slice(0,10).join(", ");Z.push(""),Z.push(`**Key concepts:** ${K}`)}let U=M.filter((K)=>K.type==="decision").map((K)=>K.title);if(U.length>0)Z.push(""),Z.push(`**Recent decisions:** ${U.slice(0,5).join("; ")}`);return Z.join(`
12
- `)}async function F0($,J){if(!U$($))return;let M=(X$.get($)??Promise.resolve()).then(async()=>{let Q=f($,"AGENTS.md"),Z=f($,".AGENTS.md.tmp"),X="";try{X=await V0(Q,"utf-8")}catch{}let U=_0(X,J);try{await W0(q(Z),{recursive:!0}),await N0(Z,U,"utf-8"),await Y0(Z,Q)}catch(K){try{await H0(Z)}catch{}throw K}});return X$.set($,M.catch(()=>{})),M}function _0($,J){if(!$)return`${R}
13
- ${J}
14
- ${h}
15
- `;let S=$.indexOf(R),M=$.indexOf(h);if(S!==-1&&M!==-1&&M>S){let Q=$.substring(0,S),Z=$.substring(M+h.length);return`${Q}${R}
16
- ${J}
17
- ${h}${Z}`}return`${$}
18
-
19
- ${R}
20
- ${J}
21
- ${h}
22
- `}function A0($,J,S){let M=new Set,Q=P(J);for(let Z of $){if(!Z||!Z.trim())continue;if(Z.startsWith("~")||Z.startsWith("http"))continue;let X=K$(Z)?Z:f(J,Z),U=q(X),K=P(U);if(!K.startsWith(Q+I)&&K!==Q)continue;if(K===Q)continue;let W=W$(Q,K);if(W.split(I).length>S)continue;if(z0(W).split(I).some((_)=>B0.has(_)))continue;if(!U$(K))continue;M.add(K)}return M}function E0($,J,S){let M=new Map;for(let Q of $){let Z=[...Q.filesModified,...Q.filesRead],X=new Set;for(let U of Z){if(!U)continue;let K=K$(U)?U:f(S,U),W=P(q(K));if(J.has(W))X.add(W)}for(let U of X){let K=M.get(U)??[];K.push(Q),M.set(U,K)}}return M}var O0="<!-- open-mem-context -->",Y$="<!-- /open-mem-context -->";async function H$($,J){let S;try{S=await j0($,{withFileTypes:!0,encoding:"utf8"})}catch{return}for(let M of S){let Q=String(M.name);if(Q===".git"||Q==="node_modules"||Q===".open-mem"||Q==="dist")continue;let Z=f0($,Q);if(M.isDirectory())await H$(Z,J);else if(M.isFile()&&Q==="AGENTS.md")J.push(Z)}}async function N$($){let J=C0($),S=[];return await H$(J,S),S}function x0($){let J=$.indexOf(O0),S=$.indexOf(Y$);if(J===-1||S===-1||S<=J)return $;let M=$.slice(0,J).trimEnd(),Q=$.slice(S+Y$.length).trimStart();if(!M&&!Q)return"";if(!M)return`${Q}
23
- `;if(!Q)return`${M}
24
- `;return`${M}
25
-
26
- ${Q}
27
- `}async function z$($,J=!1){let S=await N$($),M=0;for(let Q of S){let Z=await D0(Q,"utf-8"),X=x0(Z);if(X!==Z){if(M+=1,!J)await R0(Q,X,"utf-8")}}return{files:S,changed:M}}async function G$($,J,S,M,Q=!1){let X=J.getAll($).flatMap((K)=>S.getBySession(K.id));if(Q){let K=new Set;for(let W of X)for(let V of[...W.filesRead,...W.filesModified])K.add(V);return{observations:X.length,filesTouched:K.size}}if(!h0($))return{observations:0,filesTouched:0};await V$($,X,M);let U=await N$($);return{observations:X.length,filesTouched:U.length}}class p{observations;sessions;summaries;searchOrchestrator;projectPath;config;userObservationRepo;constructor($){this.observations=$.observations,this.sessions=$.sessions,this.summaries=$.summaries,this.searchOrchestrator=$.searchOrchestrator,this.projectPath=$.projectPath,this.config=$.config,this.userObservationRepo=$.userObservationRepo??null}async ingest($){}async processPending($){return 0}async search($,J={}){return this.searchOrchestrator.search($,{type:J.type,limit:J.limit??10,projectPath:this.projectPath,importanceMin:J.importanceMin,importanceMax:J.importanceMax,createdAfter:J.after,createdBefore:J.before,concepts:J.concepts,files:J.files})}async timeline($={}){if($.sessionId){let S=this.sessions.getById($.sessionId);if(!S)return[];return[{session:S,summary:this.summaries.getBySessionId(S.id),observations:this.observations.getBySession(S.id)}]}return this.sessions.getRecent(this.projectPath,$.limit??5).map((S)=>({session:S,summary:this.summaries.getBySessionId(S.id),observations:[]}))}async recall($,J=10){let S=[];for(let M of $.slice(0,J)){let Q=this.observations.getById(M);if(Q){S.push(Q);continue}if(!this.userObservationRepo)continue;let Z=this.userObservationRepo.getById(M);if(!Z)continue;S.push({...Z,sessionId:"",rawToolOutput:"",discoveryTokens:0})}return S}async save($){if($.scope==="user"){if(!this.userObservationRepo)return null;return{...this.userObservationRepo.create({type:$.type,title:$.title,subtitle:"",facts:[],narrative:$.narrative,concepts:$.concepts??[],filesRead:[],filesModified:$.files??[],toolName:"mem-save",tokenCount:N(`${$.title} ${$.narrative}`),importance:$.importance??3,sourceProject:this.projectPath}),sessionId:"",rawToolOutput:"",discoveryTokens:0}}this.sessions.getOrCreate($.sessionId,this.projectPath);let J=this.observations.create({sessionId:$.sessionId,type:$.type,title:$.title,subtitle:"",facts:[],narrative:$.narrative,concepts:$.concepts??[],filesRead:[],filesModified:$.files??[],rawToolOutput:`[Manual save] ${$.narrative}`,toolName:"mem-save",tokenCount:N(`${$.title} ${$.narrative}`),discoveryTokens:0,importance:$.importance??3});return this.sessions.incrementObservationCount($.sessionId),J}async update($){let J=this.observations.getById($.id);if(!J)return null;let S=this.sessions.getById(J.sessionId);if(!S||S.projectPath!==this.projectPath)return null;let{id:M,...Q}=$;return this.observations.update($.id,Q)??null}async delete($){let J=0;for(let S of $){let M=this.observations.getById(S);if(!M)continue;let Q=this.sessions.getById(M.sessionId);if(!Q||Q.projectPath!==this.projectPath)continue;if(this.observations.delete(S))J+=1}return J}async export($,J={}){if($!=="project")throw Error("Only project scope export is supported.");let S=this.sessions.getAll(this.projectPath),M=[];for(let U of S)M.push(...this.observations.getBySession(U.id));if(J.type)M=M.filter((U)=>U.type===J.type);if(M.sort((U,K)=>new Date(U.createdAt).getTime()-new Date(K.createdAt).getTime()),J.limit&&J.limit<M.length)M=M.slice(0,J.limit);let Q=M.map(({rawToolOutput:U,...K})=>K),Z=S.map((U)=>this.summaries.getBySessionId(U.id)).filter((U)=>U!==null);return{version:1,exportedAt:new Date().toISOString(),project:this.projectPath,observations:Q,summaries:Z}}async import($,J={}){let S;try{S=JSON.parse($)}catch{throw Error("Invalid JSON payload.")}if(typeof S!=="object"||S===null)throw Error("Invalid import payload.");let M=S;if(M.version!==1||!Array.isArray(M.observations))throw Error("Unsupported export format.");let Q=J.mode??"skip-duplicates",Z=0,X=0;for(let U of M.observations){let K=this.observations.getById(U.id);if(K&&Q==="skip-duplicates"){X+=1;continue}if(K&&Q==="overwrite")this.observations.delete(U.id);this.sessions.getOrCreate(U.sessionId,this.projectPath),this.observations.importObservation({id:U.id,sessionId:U.sessionId,type:U.type,title:U.title,subtitle:U.subtitle??"",facts:U.facts??[],narrative:U.narrative??"",concepts:U.concepts??[],filesRead:U.filesRead??[],filesModified:U.filesModified??[],rawToolOutput:U.rawToolOutput??"",toolName:U.toolName??"unknown",createdAt:U.createdAt,tokenCount:U.tokenCount??0,discoveryTokens:U.discoveryTokens??0,importance:U.importance??3,supersededBy:U.supersededBy??null,supersededAt:U.supersededAt??null}),this.sessions.incrementObservationCount(U.sessionId),Z+=1}for(let U of M.summaries??[]){let K=this.summaries.getBySessionId(U.sessionId);if(K&&Q==="skip-duplicates")continue;if(K&&Q==="overwrite")continue;this.sessions.getOrCreate(U.sessionId,this.projectPath),this.summaries.importSummary(U),this.sessions.setSummary(U.sessionId,U.id)}return{imported:Z,skipped:X}}async buildContext($,J="normal"){let S=this.sessions.getRecent(this.projectPath,5),M=S.map((V)=>V.summaryId?this.summaries.getBySessionId(V.id):null).filter((V)=>V!==null),Q=this.observations.getIndex(this.projectPath,this.config.maxObservations),X=Q.slice(0,this.config.contextFullObservationCount).map((V)=>V.id).map((V)=>this.observations.getById(V)).filter((V)=>V!==null),U=Z$(S,M,Q,this.config.maxContextTokens,X);if(J==="compaction"){let V=J$(U);if(this.config.userMemoryEnabled&&this.userObservationRepo)V+=M$(this.userObservationRepo.getIndex(this.config.maxObservations),this.config.userMemoryMaxContextTokens);return V}let K={showTokenCosts:this.config.contextShowTokenCosts,observationTypes:this.config.contextObservationTypes,fullObservationCount:this.config.contextFullObservationCount,showLastSummary:this.config.contextShowLastSummary},W=$$(U,K);if(this.config.userMemoryEnabled&&this.userObservationRepo){let V=S$(this.userObservationRepo.getIndex(this.config.maxObservations),this.config.userMemoryMaxContextTokens);if(V)W+=`
28
-
29
- ${V}`}return W}guide(){return["open-mem workflow:","1) Use mem-search to find candidate observations by query.","2) Use mem-timeline to inspect session-level history and summaries.","3) Use mem-recall with IDs from search/timeline to fetch full details.","Write/edit flow: mem-save (new), mem-update (refine), mem-delete (remove stale).","Transfer flow: mem-export for backup/portability, mem-import to restore."].join(`
30
- `)}listObservations($){let{limit:J=50,offset:S=0,type:M,sessionId:Q}=$;if(Q){let U=this.observations.getBySession(Q);if(M)U=U.filter((K)=>K.type===M);return U.slice(S,S+J)}let X=this.observations.getIndex(this.projectPath,S+J).slice(S);if(M)X=X.filter((U)=>U.type===M);return X.map((U)=>this.observations.getById(U.id)).filter((U)=>U!==null)}getObservation($){return this.observations.getById($)}listSessions($){return this.sessions.getRecent($.projectPath??this.projectPath,$.limit??20)}getSession($){let J=this.sessions.getById($);if(!J)return null;return{session:J,summary:this.summaries.getBySessionId($),observations:this.observations.getBySession($)}}stats(){let $=this.observations.getCount(),S=this.sessions.getAll(this.projectPath).length,M=this.observations.getIndex(this.projectPath,1e4),Q=0,Z=0,X={};for(let W of M)Q+=W.tokenCount,Z+=W.discoveryTokens,X[W.type]=(X[W.type]||0)+1;let U=Z-Q,K=M.length>0?Math.round(Q/M.length):0;return{totalObservations:$,totalSessions:S,totalTokensSaved:U,averageObservationSize:K,typeBreakdown:X}}async maintainFolderContext($,J){if($==="rebuild"){let M=await G$(this.projectPath,this.sessions,this.observations,this.config.folderContextMaxDepth,J);return{action:$,dryRun:J,...M}}let S=await z$(this.projectPath,J);return{action:"clean",dryRun:J,...S}}}import{Database as B$}from"bun:sqlite";import{existsSync as m,mkdirSync as k0,unlinkSync as L$}from"fs";import*as F$ from"sqlite-vec";class C{db;dbPath;_hasVectorExtension=!1;static enableExtensionSupport(){let $=["/opt/homebrew/opt/sqlite/lib/libsqlite3.dylib","/usr/local/opt/sqlite/lib/libsqlite3.dylib"];for(let J of $)try{if(m(J))return B$.setCustomSQLite(J),!0}catch{return!1}return!1}constructor($){this.dbPath=$,this.db=this.open($),this.configure()}open($){let J=$.lastIndexOf("/");if(J>0){let S=$.substring(0,J);k0(S,{recursive:!0})}return new B$($,{create:!0})}configure(){try{this.applyPragmas(),this.loadExtensions()}catch($){console.warn("[open-mem] Database configure failed, attempting recovery by removing WAL/SHM files:",$.message);try{this.db.close()}catch{}this.deleteSidecarFiles();try{this.db=this.open(this.dbPath),this.applyPragmas(),this.loadExtensions(),console.warn("[open-mem] Recovery successful after removing WAL/SHM files");return}catch(J){console.warn("[open-mem] WAL/SHM cleanup insufficient, recreating database from scratch:",J.message);try{this.db.close()}catch{}this.deleteDatabaseFiles();try{this.db=this.open(this.dbPath),this.applyPragmas(),this.loadExtensions(),console.warn("[open-mem] Recovery successful after full database recreation");return}catch(S){throw console.warn("[open-mem] All recovery attempts failed, filesystem may be broken:",S.message),$}}}}applyPragmas(){this.db.exec("PRAGMA journal_mode = WAL"),this.db.exec("PRAGMA synchronous = NORMAL"),this.db.exec("PRAGMA foreign_keys = ON"),this.db.exec("PRAGMA busy_timeout = 5000")}loadExtensions(){try{F$.load(this.db),this._hasVectorExtension=!0}catch{this._hasVectorExtension=!1}}get hasVectorExtension(){return this._hasVectorExtension}deleteSidecarFiles(){for(let $ of["-wal","-shm"]){let J=this.dbPath+$;try{if(m(J))L$(J)}catch{}}}deleteDatabaseFiles(){this.deleteSidecarFiles();try{if(m(this.dbPath))L$(this.dbPath)}catch{}}ensureMigrationTable(){this.db.exec(`
3
+ var RM=Object.defineProperty;var HM=(E,M)=>{for(var N in M)RM(E,N,{get:M[N],enumerable:!0,configurable:!0,set:(_)=>M[N]=()=>_})};var ZE=(E,M)=>()=>(E&&(M=E(E=0)),M);var U=import.meta.require;import{existsSync as UM,readFileSync as BM}from"fs";function FM(){let E={};if(process.env.OPEN_MEM_DB_PATH)E.dbPath=process.env.OPEN_MEM_DB_PATH;if(process.env.OPEN_MEM_PROVIDER)E.provider=process.env.OPEN_MEM_PROVIDER;if(process.env.OPEN_MEM_MODEL)E.model=process.env.OPEN_MEM_MODEL;if(process.env.OPEN_MEM_MAX_CONTEXT_TOKENS)E.maxContextTokens=Number.parseInt(process.env.OPEN_MEM_MAX_CONTEXT_TOKENS,10);if(process.env.OPEN_MEM_COMPRESSION==="false")E.compressionEnabled=!1;if(process.env.OPEN_MEM_CONTEXT_INJECTION==="false")E.contextInjectionEnabled=!1;if(process.env.OPEN_MEM_IGNORED_TOOLS)E.ignoredTools=process.env.OPEN_MEM_IGNORED_TOOLS.split(",").map((M)=>M.trim());if(process.env.OPEN_MEM_BATCH_SIZE)E.batchSize=Number.parseInt(process.env.OPEN_MEM_BATCH_SIZE,10);if(process.env.OPEN_MEM_RETENTION_DAYS)E.retentionDays=Number.parseInt(process.env.OPEN_MEM_RETENTION_DAYS,10);if(process.env.OPEN_MEM_LOG_LEVEL)E.logLevel=process.env.OPEN_MEM_LOG_LEVEL;if(process.env.OPEN_MEM_CONTEXT_SHOW_TOKEN_COSTS==="false")E.contextShowTokenCosts=!1;if(process.env.OPEN_MEM_CONTEXT_TYPES)E.contextObservationTypes=process.env.OPEN_MEM_CONTEXT_TYPES==="all"?"all":process.env.OPEN_MEM_CONTEXT_TYPES.split(",").map((M)=>M.trim());if(process.env.OPEN_MEM_CONTEXT_FULL_COUNT)E.contextFullObservationCount=Number.parseInt(process.env.OPEN_MEM_CONTEXT_FULL_COUNT,10);if(process.env.OPEN_MEM_MAX_OBSERVATIONS)E.maxObservations=Number.parseInt(process.env.OPEN_MEM_MAX_OBSERVATIONS,10);if(process.env.OPEN_MEM_CONTEXT_SHOW_LAST_SUMMARY==="false")E.contextShowLastSummary=!1;if(process.env.OPEN_MEM_RATE_LIMITING==="false")E.rateLimitingEnabled=!1;if(process.env.OPEN_MEM_FOLDER_CONTEXT==="false")E.folderContextEnabled=!1;if(process.env.OPEN_MEM_FOLDER_CONTEXT_MAX_DEPTH)E.folderContextMaxDepth=Number.parseInt(process.env.OPEN_MEM_FOLDER_CONTEXT_MAX_DEPTH,10);if(process.env.OPEN_MEM_DAEMON==="true")E.daemonEnabled=!0;if(process.env.OPEN_MEM_DASHBOARD==="true")E.dashboardEnabled=!0;if(process.env.OPEN_MEM_DASHBOARD_PORT)E.dashboardPort=Number.parseInt(process.env.OPEN_MEM_DASHBOARD_PORT,10);if(process.env.OPEN_MEM_PLATFORM_OPENCODE==="false")E.platformOpenCodeEnabled=!1;if(process.env.OPEN_MEM_PLATFORM_CLAUDE_CODE==="true")E.platformClaudeCodeEnabled=!0;if(process.env.OPEN_MEM_PLATFORM_CURSOR==="true")E.platformCursorEnabled=!0;if(process.env.OPEN_MEM_MCP_COMPAT_MODE)E.mcpCompatibilityMode=process.env.OPEN_MEM_MCP_COMPAT_MODE;if(process.env.OPEN_MEM_MCP_PROTOCOL_VERSION)E.mcpProtocolVersion=process.env.OPEN_MEM_MCP_PROTOCOL_VERSION;if(process.env.OPEN_MEM_MCP_SUPPORTED_PROTOCOLS)E.mcpSupportedProtocolVersions=process.env.OPEN_MEM_MCP_SUPPORTED_PROTOCOLS.split(",").map((M)=>M.trim()).filter(Boolean);if(process.env.OPEN_MEM_EMBEDDING_DIMENSION)E.embeddingDimension=Number.parseInt(process.env.OPEN_MEM_EMBEDDING_DIMENSION,10);if(process.env.OPEN_MEM_CONFLICT_RESOLUTION==="true")E.conflictResolutionEnabled=!0;if(process.env.OPEN_MEM_CONFLICT_BAND_LOW){let M=Number.parseFloat(process.env.OPEN_MEM_CONFLICT_BAND_LOW);if(!Number.isNaN(M))E.conflictSimilarityBandLow=M}if(process.env.OPEN_MEM_CONFLICT_BAND_HIGH){let M=Number.parseFloat(process.env.OPEN_MEM_CONFLICT_BAND_HIGH);if(!Number.isNaN(M))E.conflictSimilarityBandHigh=M}if(process.env.OPEN_MEM_USER_MEMORY==="true")E.userMemoryEnabled=!0;if(process.env.OPEN_MEM_USER_MEMORY_DB_PATH)E.userMemoryDbPath=process.env.OPEN_MEM_USER_MEMORY_DB_PATH;if(process.env.OPEN_MEM_USER_MEMORY_MAX_TOKENS)E.userMemoryMaxContextTokens=Number.parseInt(process.env.OPEN_MEM_USER_MEMORY_MAX_TOKENS,10);if(process.env.OPEN_MEM_RERANKING==="true")E.rerankingEnabled=!0;if(process.env.OPEN_MEM_RERANKING_MAX_CANDIDATES)E.rerankingMaxCandidates=Number.parseInt(process.env.OPEN_MEM_RERANKING_MAX_CANDIDATES,10);if(process.env.OPEN_MEM_ENTITY_EXTRACTION==="true")E.entityExtractionEnabled=!0;return E}function GM(E){let M=`${E}/.open-mem/config.json`;if(!UM(M))return{};try{let N=BM(M,"utf-8"),_=JSON.parse(N);if(!_||typeof _!=="object"||Array.isArray(_))return{};return _}catch{return{}}}function DM(E){switch(E){case"google":return 768;case"openai":return 1536;case"bedrock":return 1024;case"anthropic":return 0;default:return 768}}function m(E,M){let N=GM(E),_=FM(),O={...LE,...N,..._,...M};if(!O.dbPath.startsWith("/"))O.dbPath=`${E}/${O.dbPath}`;if(!process.env.OPEN_MEM_PROVIDER&&!M?.provider){if(process.env.GOOGLE_GENERATIVE_AI_API_KEY||process.env.GEMINI_API_KEY)O.provider="google";else if(process.env.ANTHROPIC_API_KEY)O.provider="anthropic";else if(process.env.AWS_BEARER_TOKEN_BEDROCK||process.env.AWS_ACCESS_KEY_ID||process.env.AWS_PROFILE)O.provider="bedrock"}if(!O.apiKey)switch(O.provider){case"google":O.apiKey=process.env.GOOGLE_GENERATIVE_AI_API_KEY||process.env.GEMINI_API_KEY;break;case"anthropic":O.apiKey=process.env.ANTHROPIC_API_KEY;break;case"openai":O.apiKey=process.env.OPENAI_API_KEY;break;case"bedrock":break}if(O.embeddingDimension===void 0)O.embeddingDimension=DM(O.provider);return O}function d(){return{...LE}}var LE;var i=ZE(()=>{LE={dbPath:".open-mem/memory.db",provider:"google",apiKey:void 0,model:"gemini-2.5-flash-lite",maxTokensPerCompression:1024,compressionEnabled:!0,contextInjectionEnabled:!0,maxContextTokens:4000,batchSize:5,batchIntervalMs:30000,ignoredTools:[],minOutputLength:50,maxIndexEntries:20,sensitivePatterns:[],retentionDays:90,maxDatabaseSizeMb:500,logLevel:"warn",contextShowTokenCosts:!0,contextObservationTypes:"all",contextFullObservationCount:3,maxObservations:50,contextShowLastSummary:!0,rateLimitingEnabled:!0,folderContextEnabled:!0,folderContextMaxDepth:5,daemonEnabled:!1,dashboardEnabled:!1,dashboardPort:3737,platformOpenCodeEnabled:!0,platformClaudeCodeEnabled:!1,platformCursorEnabled:!1,mcpCompatibilityMode:"strict",mcpProtocolVersion:"2024-11-05",mcpSupportedProtocolVersions:["2024-11-05"],embeddingDimension:void 0,conflictResolutionEnabled:!1,conflictSimilarityBandLow:0.7,conflictSimilarityBandHigh:0.92,userMemoryEnabled:!1,userMemoryDbPath:"~/.config/open-mem/user-memory.db",userMemoryMaxContextTokens:1000,rerankingEnabled:!1,rerankingMaxCandidates:20,entityExtractionEnabled:!1}});var hE={};HM(hE,{writeProjectConfig:()=>IE,validatePatch:()=>t,readProjectConfig:()=>q,previewConfig:()=>R0,patchConfig:()=>H0,getEffectiveConfig:()=>p,getConfigSchema:()=>Z0});import{existsSync as O0}from"fs";import{mkdir as J0,readFile as S0,writeFile as V0}from"fs/promises";import{dirname as C0,join as A0}from"path";function vE(E){return A0(E,".open-mem","config.json")}function gE(E){return pE.find((M)=>M.key===E)}function X0(E,M){let N=gE(E);if(!N)return null;if(N.type==="string"&&typeof M!=="string")return`${String(E)} must be a string`;if(N.type==="number"&&typeof M!=="number")return`${String(E)} must be a number`;if(N.type==="boolean"&&typeof M!=="boolean")return`${String(E)} must be a boolean`;if(N.type==="array"&&!Array.isArray(M))return`${String(E)} must be an array`;if(N.enum&&typeof M==="string"&&!N.enum.includes(M))return`${String(E)} must be one of: ${N.enum.join(", ")}`;if(typeof M==="number"){if(N.min!==void 0&&M<N.min)return`${String(E)} must be >= ${N.min}`;if(N.max!==void 0&&M>N.max)return`${String(E)} must be <= ${N.max}`}return null}function Z0(){return pE}async function q(E){let M=vE(E);if(!O0(M))return{};try{let N=await S0(M,"utf-8"),_=JSON.parse(N);if(!_||typeof _!=="object"||Array.isArray(_))return{};return _}catch{return{}}}async function IE(E,M){let N=vE(E),O={...await q(E),...M};await J0(C0(N),{recursive:!0}),await V0(N,JSON.stringify(O,null,2),"utf-8")}function t(E){let M=[];for(let[N,_]of Object.entries(E)){let J=X0(N,_);if(J)M.push(J)}return M}async function p(E){let M=d(),N=await q(E),_=m(E),O=[],J={};for(let[S,V]of Object.entries(M)){let C=S,A=gE(C),H=($0[C]??[]).some((D)=>typeof process.env[D]==="string"),Y=Object.hasOwn(N,C),B="default";if(Y)B="file";if(H)B="env";if(J[C]={source:B,locked:H,restartRequired:A?.restartRequired??!1,liveApply:A?.liveApply??!1},B==="env"&&Y)O.push(`${String(C)} is overridden by environment variable.`);if(_[C]===void 0&&V!==void 0)O.push(`${String(C)} resolved to undefined unexpectedly.`)}return{config:_,meta:J,warnings:O}}async function R0(E,M){let N=t(M);if(N.length>0)return{...await p(E),warnings:N};let _=d(),O=await q(E),J={..._,...O,...M},V={...m(E,M),...J},C=(await p(E)).meta;return{config:V,meta:C,warnings:[]}}async function H0(E,M){let N=t(M);if(N.length>0)return{...await p(E),warnings:N};return await IE(E,M),p(E)}var pE,$0;var qE=ZE(()=>{i();pE=[{key:"dbPath",label:"Database Path",type:"string",group:"Storage",liveApply:!1,restartRequired:!0},{key:"provider",label:"Provider",type:"string",group:"AI",liveApply:!1,restartRequired:!0,enum:["google","anthropic","openai","bedrock"]},{key:"model",label:"Model",type:"string",group:"AI",liveApply:!1,restartRequired:!0},{key:"maxTokensPerCompression",label:"Max Tokens Per Compression",type:"number",group:"AI",liveApply:!0,restartRequired:!1,min:128,max:8192},{key:"compressionEnabled",label:"Compression Enabled",type:"boolean",group:"Behavior",liveApply:!0,restartRequired:!1},{key:"contextInjectionEnabled",label:"Context Injection Enabled",type:"boolean",group:"Behavior",liveApply:!0,restartRequired:!1},{key:"maxContextTokens",label:"Max Context Tokens",type:"number",group:"Behavior",liveApply:!0,restartRequired:!1,min:500,max:64000},{key:"batchSize",label:"Batch Size",type:"number",group:"Behavior",liveApply:!0,restartRequired:!1,min:1,max:100},{key:"batchIntervalMs",label:"Batch Interval (ms)",type:"number",group:"Behavior",liveApply:!0,restartRequired:!1,min:1000,max:300000},{key:"ignoredTools",label:"Ignored Tools",type:"array",group:"Filtering",liveApply:!0,restartRequired:!1},{key:"minOutputLength",label:"Min Output Length",type:"number",group:"Filtering",liveApply:!0,restartRequired:!1,min:0,max:1e4},{key:"maxObservations",label:"Max Observations",type:"number",group:"Progressive Disclosure",liveApply:!0,restartRequired:!1,min:1,max:200},{key:"contextFullObservationCount",label:"Full Observation Count",type:"number",group:"Progressive Disclosure",liveApply:!0,restartRequired:!1,min:0,max:20},{key:"contextShowTokenCosts",label:"Show Token Costs",type:"boolean",group:"Progressive Disclosure",liveApply:!0,restartRequired:!1},{key:"sensitivePatterns",label:"Sensitive Patterns",type:"array",group:"Privacy",liveApply:!0,restartRequired:!1},{key:"retentionDays",label:"Retention Days",type:"number",group:"Data Retention",liveApply:!1,restartRequired:!0,min:0,max:3650},{key:"maxDatabaseSizeMb",label:"Max Database Size (MB)",type:"number",group:"Data Retention",liveApply:!1,restartRequired:!0,min:0,max:1e5},{key:"dashboardEnabled",label:"Dashboard Enabled",type:"boolean",group:"Dashboard",liveApply:!1,restartRequired:!0},{key:"dashboardPort",label:"Dashboard Port",type:"number",group:"Dashboard",liveApply:!1,restartRequired:!0,min:1,max:65535},{key:"platformOpenCodeEnabled",label:"OpenCode Adapter",type:"boolean",group:"Advanced",liveApply:!1,restartRequired:!0},{key:"platformClaudeCodeEnabled",label:"Claude Code Adapter",type:"boolean",group:"Advanced",liveApply:!1,restartRequired:!0},{key:"platformCursorEnabled",label:"Cursor Adapter",type:"boolean",group:"Advanced",liveApply:!1,restartRequired:!0},{key:"mcpCompatibilityMode",label:"MCP Compatibility Mode",type:"string",group:"Advanced",liveApply:!1,restartRequired:!0,enum:["strict","legacy"]},{key:"mcpProtocolVersion",label:"MCP Protocol Version",type:"string",group:"Advanced",liveApply:!1,restartRequired:!0},{key:"mcpSupportedProtocolVersions",label:"MCP Supported Protocols",type:"array",group:"Advanced",liveApply:!1,restartRequired:!0},{key:"rerankingEnabled",label:"Reranking Enabled",type:"boolean",group:"Advanced",liveApply:!0,restartRequired:!1},{key:"entityExtractionEnabled",label:"Entity Extraction Enabled",type:"boolean",group:"Advanced",liveApply:!0,restartRequired:!1},{key:"userMemoryEnabled",label:"User Memory Enabled",type:"boolean",group:"Advanced",liveApply:!1,restartRequired:!0},{key:"userMemoryMaxContextTokens",label:"User Memory Max Context Tokens",type:"number",group:"Advanced",liveApply:!0,restartRequired:!1,min:0,max:8000}],$0={dbPath:["OPEN_MEM_DB_PATH"],provider:["OPEN_MEM_PROVIDER"],model:["OPEN_MEM_MODEL"],compressionEnabled:["OPEN_MEM_COMPRESSION"],contextInjectionEnabled:["OPEN_MEM_CONTEXT_INJECTION"],maxContextTokens:["OPEN_MEM_MAX_CONTEXT_TOKENS"],ignoredTools:["OPEN_MEM_IGNORED_TOOLS"],batchSize:["OPEN_MEM_BATCH_SIZE"],retentionDays:["OPEN_MEM_RETENTION_DAYS"],contextShowTokenCosts:["OPEN_MEM_CONTEXT_SHOW_TOKEN_COSTS"],contextFullObservationCount:["OPEN_MEM_CONTEXT_FULL_COUNT"],maxObservations:["OPEN_MEM_MAX_OBSERVATIONS"],dashboardEnabled:["OPEN_MEM_DASHBOARD"],dashboardPort:["OPEN_MEM_DASHBOARD_PORT"],platformOpenCodeEnabled:["OPEN_MEM_PLATFORM_OPENCODE"],platformClaudeCodeEnabled:["OPEN_MEM_PLATFORM_CLAUDE_CODE"],platformCursorEnabled:["OPEN_MEM_PLATFORM_CURSOR"],mcpCompatibilityMode:["OPEN_MEM_MCP_COMPAT_MODE"],mcpProtocolVersion:["OPEN_MEM_MCP_PROTOCOL_VERSION"],mcpSupportedProtocolVersions:["OPEN_MEM_MCP_SUPPORTED_PROTOCOLS"],rerankingEnabled:["OPEN_MEM_RERANKING"],userMemoryEnabled:["OPEN_MEM_USER_MEMORY"]}});import{readFileSync as x0}from"fs";import{join as u0}from"path";import{parseArgs as w0}from"util";import{createInterface as KM}from"readline";import{z as F}from"zod";import{z as X}from"zod";var v=X.enum(["decision","bugfix","feature","refactor","discovery","change"]);function K(E,M={}){return{data:E,error:null,meta:M}}function z(E,M,N){return{data:null,error:{code:E,message:M,details:N},meta:{}}}var Z={find:X.object({query:X.string().min(1),scope:X.enum(["project","user","all"]).optional().default("project"),types:X.array(v).optional(),limit:X.number().int().min(1).max(50).optional().default(10),cursor:X.string().optional(),include:X.object({snippets:X.boolean().optional(),scores:X.boolean().optional(),relations:X.boolean().optional()}).optional()}),history:X.object({limit:X.number().int().min(1).max(20).optional().default(5),cursor:X.string().optional(),sessionId:X.string().optional()}),get:X.object({ids:X.array(X.string()).min(1),includeHistory:X.boolean().optional().default(!1),limit:X.number().int().min(1).max(50).optional().default(10)}),create:X.object({title:X.string(),type:v,narrative:X.string(),concepts:X.array(X.string()).optional(),files:X.array(X.string()).optional(),importance:X.number().int().min(1).max(5).optional(),scope:X.enum(["project","user"]).optional().default("project")}),revise:X.object({id:X.string(),title:X.string().optional(),narrative:X.string().optional(),type:v.optional(),concepts:X.array(X.string()).optional(),importance:X.number().int().min(1).max(5).optional(),reason:X.string().optional()}),remove:X.object({id:X.string(),reason:X.string().optional()}),transferExport:X.object({scope:X.enum(["project"]).optional().default("project"),type:v.optional(),limit:X.number().int().min(1).optional(),format:X.enum(["json"]).optional().default("json")}),transferImport:X.object({payload:X.string(),mode:X.enum(["skip","merge","replace"]).optional().default("skip")}),maintenance:X.object({action:X.enum(["folderContextDryRun","folderContextClean","folderContextRebuild"])}),help:X.object({})};var LM="2024-11-05",QM=F.object({name:F.string().min(1),arguments:F.record(F.string(),F.unknown()).optional()});function zM(E){if(typeof E!=="object"||E===null)return!1;let M=E;return M.jsonrpc==="2.0"&&typeof M.method==="string"}function Q(E){let N=F.toJSONSchema(E);return{type:"object",properties:N.properties??{},required:N.required??void 0,additionalProperties:!1}}function RE(E){return E.issues.map((M)=>{return`${M.path.length>0?M.path.join("."):"input"}: ${M.message}`}).join("; ")}class n{memoryEngine;version;compatibilityMode;protocolVersion;supportedProtocolVersions;initialized=!1;pendingOps=[];constructor(E){this.memoryEngine=E.memoryEngine,this.version=E.version,this.compatibilityMode=E.compatibilityMode??"strict",this.protocolVersion=E.protocolVersion??LM,this.supportedProtocolVersions=E.supportedProtocolVersions&&E.supportedProtocolVersions.length>0?E.supportedProtocolVersions:[this.protocolVersion]}start(){let E=KM({input:process.stdin,terminal:!1});E.on("line",(M)=>{let N=M.trim();if(!N)return;try{let _=JSON.parse(N);if(!zM(_)){this.send({jsonrpc:"2.0",id:null,error:{code:-32600,message:"Invalid Request"}});return}this.handle(_)}catch{this.send({jsonrpc:"2.0",id:null,error:{code:-32700,message:"Parse error"}})}}),E.on("close",()=>{Promise.allSettled(this.pendingOps).then(()=>process.exit(0))})}handle(E){if(E.method==="notifications/initialized"){this.initialized=!0;return}if(E.id===void 0||E.id===null)return;if(E.method==="initialize"){this.handleInitialize(E);return}if(!this.initialized&&this.compatibilityMode==="strict"){this.send({jsonrpc:"2.0",id:E.id,error:{code:-32002,message:"Server not initialized"}});return}switch(E.method){case"tools/list":this.send({jsonrpc:"2.0",id:E.id,result:{tools:this.getToolDefinitions()}});return;case"tools/call":{let M=this.handleToolCall(E.id,E.params);this.pendingOps.push(M),M.finally(()=>{this.pendingOps=this.pendingOps.filter((N)=>N!==M)});return}case"ping":this.send({jsonrpc:"2.0",id:E.id,result:{}});return;default:this.send({jsonrpc:"2.0",id:E.id,error:{code:-32601,message:`Method not found: ${E.method}`}})}}handleInitialize(E){let M=typeof E.params?.protocolVersion==="string"?E.params.protocolVersion:this.protocolVersion;if(!this.supportedProtocolVersions.includes(M)){this.send({jsonrpc:"2.0",id:E.id??null,error:{code:-32602,message:`Unsupported protocol version: ${M}`,data:{supported:this.supportedProtocolVersions}}});return}this.initialized=!0,this.send({jsonrpc:"2.0",id:E.id??null,result:{protocolVersion:M,capabilities:{tools:{listChanged:!1}},serverInfo:{name:"open-mem",version:this.version}}})}getToolDefinitions(){return[{name:"memory.find",description:"Find relevant memory records.",inputSchema:Q(Z.find)},{name:"memory.history",description:"Browse session history.",inputSchema:Q(Z.history)},{name:"memory.get",description:"Fetch full memory records by id.",inputSchema:Q(Z.get)},{name:"memory.create",description:"Create a memory record.",inputSchema:Q(Z.create)},{name:"memory.revise",description:"Create a revised memory revision.",inputSchema:Q(Z.revise)},{name:"memory.remove",description:"Tombstone a memory record.",inputSchema:Q(Z.remove)},{name:"memory.transfer.export",description:"Export memory.",inputSchema:Q(Z.transferExport)},{name:"memory.transfer.import",description:"Import memory payload.",inputSchema:Q(Z.transferImport)},{name:"memory.maintenance",description:"Run maintenance action.",inputSchema:Q(Z.maintenance)},{name:"memory.help",description:"Show memory workflow guidance.",inputSchema:Q(Z.help)}]}async handleToolCall(E,M){let N=QM.safeParse(M??{});if(!N.success){this.send({jsonrpc:"2.0",id:E,result:{content:[{type:"text",text:JSON.stringify(z("VALIDATION_ERROR",RE(N.error)),null,2)}],isError:!0}});return}let _=N.data.name,O=N.data.arguments??{};try{let J=await this.executeTool(_,O);this.send({jsonrpc:"2.0",id:E,result:J})}catch(J){this.send({jsonrpc:"2.0",id:E,result:{content:[{type:"text",text:JSON.stringify(z("INTERNAL_ERROR",String(J)),null,2)}],isError:!0}})}}async executeTool(E,M){let N=async()=>{switch(E){case"memory.find":{let _=Z.find.parse(M),O=await this.memoryEngine.search(_.query,{limit:_.limit,type:_.types?.[0]});return JSON.stringify(K({results:O}),null,2)}case"memory.history":{let _=Z.history.parse(M);return JSON.stringify(K({items:await this.memoryEngine.timeline({limit:_.limit,sessionId:_.sessionId})}),null,2)}case"memory.get":{let _=Z.get.parse(M);return JSON.stringify(K({observations:await this.memoryEngine.recall(_.ids,_.limit)}),null,2)}case"memory.create":{let _=Z.create.parse(M),O=await this.memoryEngine.save({..._,sessionId:"mcp"});return JSON.stringify(O?K({observation:O}):z("CONFLICT","Unable to create memory"),null,2)}case"memory.revise":{let _=Z.revise.parse(M),O=await this.memoryEngine.update(_);return JSON.stringify(O?K({previousId:_.id,newId:O.id,observation:O}):z("NOT_FOUND",`Observation ${_.id} not found`),null,2)}case"memory.remove":{let _=Z.remove.parse(M),O=await this.memoryEngine.delete([_.id]);return JSON.stringify(O>0?K({id:_.id,tombstoned:!0}):z("NOT_FOUND",`Observation ${_.id} not found`),null,2)}case"memory.transfer.export":{let _=Z.transferExport.parse(M),O=await this.memoryEngine.export("project",{type:_.type,limit:_.limit});return JSON.stringify(K({payload:O,format:_.format}),null,2)}case"memory.transfer.import":{let _=Z.transferImport.parse(M),O=_.mode==="replace"?"overwrite":"skip-duplicates",J=await this.memoryEngine.import(_.payload,{mode:O});return JSON.stringify(K({imported:J.imported,skipped:J.skipped,mode:_.mode}),null,2)}case"memory.maintenance":{let _=Z.maintenance.parse(M);if(_.action==="folderContextDryRun")return JSON.stringify(K(await this.memoryEngine.maintainFolderContext("clean",!0)),null,2);if(_.action==="folderContextClean")return JSON.stringify(K(await this.memoryEngine.maintainFolderContext("clean",!1)),null,2);return JSON.stringify(K(await this.memoryEngine.maintainFolderContext("rebuild",!1)),null,2)}case"memory.help":return JSON.stringify(K({guide:this.memoryEngine.guide()}),null,2);default:return JSON.stringify(z("NOT_FOUND",`Unknown tool: ${E}`),null,2)}};try{let _=await N(),O=_.includes('"error": {')&&!_.includes('"error": null');return{content:[{type:"text",text:_}],isError:O}}catch(_){if(_ instanceof F.ZodError)return{content:[{type:"text",text:JSON.stringify(z("VALIDATION_ERROR",RE(_)),null,2)}],isError:!0};return{content:[{type:"text",text:JSON.stringify(z("INTERNAL_ERROR",String(_)),null,2)}],isError:!0}}}send(E){process.stdout.write(`${JSON.stringify(E)}
4
+ `)}}var WM={"claude-sonnet-4-20250514":"us.anthropic.claude-sonnet-4-20250514-v1:0","claude-opus-4-20250514":"us.anthropic.claude-opus-4-20250514-v1:0","claude-3-5-sonnet-20241022":"us.anthropic.claude-3-5-sonnet-20241022-v2:0","claude-3-5-haiku-20241022":"us.anthropic.claude-3-5-haiku-20241022-v1:0","claude-3-haiku-20240307":"anthropic.claude-3-haiku-20240307-v1:0"};function YM(E){if(E.includes("."))return E;return WM[E]||`us.anthropic.${E}-v1:0`}function HE(E){switch(E.provider){case"anthropic":{let{createAnthropic:M}=U("@ai-sdk/anthropic");return M({apiKey:E.apiKey})(E.model)}case"bedrock":{let{createAmazonBedrock:M}=U("@ai-sdk/amazon-bedrock");return M()(YM(E.model))}case"openai":{let{createOpenAI:M}=U("@ai-sdk/openai");return M({apiKey:E.apiKey})(E.model)}case"google":{let{createGoogleGenerativeAI:M}=U("@ai-sdk/google");return M({apiKey:E.apiKey})(E.model)}default:throw Error(`Unknown provider: ${E.provider}. Supported: anthropic, bedrock, openai, google`)}}function KE(E){try{switch(E.provider){case"google":{let{createGoogleGenerativeAI:M}=U("@ai-sdk/google");return M({apiKey:E.apiKey}).embedding("text-embedding-004")}case"openai":{let{createOpenAI:M}=U("@ai-sdk/openai");return M({apiKey:E.apiKey}).embedding("text-embedding-3-small")}case"bedrock":{let{createAmazonBedrock:M}=U("@ai-sdk/amazon-bedrock");return M().embedding("amazon.titan-embed-text-v2:0")}case"anthropic":return null;default:return null}}catch{return null}}i();import{randomUUID as xE}from"crypto";function yM(E,M){let N=new RegExp(`<${M}[^>]*>([\\s\\S]*?)</${M}>`,"i"),_=E.match(N);return _?_[1].trim():""}function jM(E,M){let N=new RegExp(`<${M}[^>]*>([\\s\\S]*?)</${M}>`,"gi"),_=[];for(let O of E.matchAll(N)){let J=O[1].trim();if(J)_.push(J)}return _}function QE(E){let M=yM(E,"reranked");if(!M)return null;let N=jM(M,"index");if(N.length===0)return null;let _=[];for(let O of N){let J=Number.parseInt(O,10);if(Number.isNaN(J)||J<0)return null;_.push(J)}return _}function W(E){return Math.ceil(E.length/4)}var kM={showTokenCosts:!0,observationTypes:"all",fullObservationCount:3,showLastSummary:!0},T={bugfix:"\uD83D\uDD34",feature:"\uD83D\uDFE3",refactor:"\uD83D\uDD04",change:"\u2705",discovery:"\uD83D\uDD35",decision:"\u2696\uFE0F"};function zE(E,M=kM){let N=[];if(N.push("## open-mem: Past Session Memory"),N.push(""),N.push("**\uD83D\uDCA1 Progressive Disclosure:** This is a compact index showing WHAT was observed and retrieval COST."),N.push("Use `memory.find` to find observations by query, then `memory.get` with IDs to fetch full details."),N.push(""),N.push("**3-Layer Memory Access:**"),N.push("- **Layer 1** `memory.find` \u2014 Find observations by query (returns IDs + summaries)"),N.push("- **Layer 2** `memory.history` \u2014 Browse session history and drill into sessions"),N.push("- **Layer 3** `memory.get` \u2014 Get full details by ID (use IDs from search results or the index below)"),M.showLastSummary&&E.recentSummaries.length>0){N.push(""),N.push("### Recent Sessions"),N.push("| Session | Summary | Decisions |"),N.push("|---------|---------|-----------|");for(let S of E.recentSummaries){let V=S.keyDecisions.length>0?S.keyDecisions.join("; "):"\u2014";N.push(`| ${S.sessionId} | ${S.summary} | ${V} |`)}}let _=M.observationTypes==="all"?E.observationIndex:E.observationIndex.filter((S)=>M.observationTypes.includes(S.type));if(_.length>0){N.push(""),N.push(`### Recent Observations (${_.length} entries)`);let S=PM(_,E.fullObservations);for(let[V,C]of S){if(N.push(""),N.push(`**${V}**`),M.showTokenCosts)N.push("| ID | Type | Title | ~Tokens |"),N.push("|----|------|-------|---------|");else N.push("| ID | Type | Title |"),N.push("|----|------|-------|");for(let A of C){let $=T[A.type]||"\uD83D\uDCDD";if(M.showTokenCosts)N.push(`| ${A.id} | ${$} | ${A.title} | ~${A.tokenCount} |`);else N.push(`| ${A.id} | ${$} | ${A.title} |`)}}}let O=E.fullObservations.slice(0,M.fullObservationCount);if(O.length>0){N.push(""),N.push("### Full Details (most recent)");for(let S of O){let V=T[S.type]||"\uD83D\uDCDD";if(N.push(""),N.push(`#### ${V} ${S.title} (${S.id})`),N.push(S.narrative),S.facts.length>0)N.push(`**Facts:** ${S.facts.map((A)=>`- ${A}`).join(" ")}`);if(S.concepts.length>0)N.push(`**Concepts:** ${S.concepts.join(", ")}`);let C=[...S.filesRead,...S.filesModified];if(C.length>0)N.push(`**Files:** ${C.join(", ")}`)}}let J=fM(E);if(J)N.push(""),N.push(J);return N.join(`
5
+ `)}function fM(E){let M=0,N=0,_=new Set(E.observationIndex.map((S)=>S.id));for(let S of E.observationIndex)M+=S.tokenCount,N+=S.discoveryTokens;for(let S of E.fullObservations)if(!_.has(S.id))M+=S.tokenCount,N+=S.discoveryTokens;if(N===0)return null;let O=N-M,J=Math.max(0,Math.round(O/N*100));return`### \uD83D\uDCB0 Memory Economics
6
+ **Read cost:** ~${M}t | **Discovery cost:** ~${N}t | **Savings:** ${J}% (${O}t saved)`}function PM(E,M){let N=new Map;for(let O of M){let J=O.filesModified[0]||O.filesRead[0];if(J)N.set(O.id,J)}let _=new Map;for(let O of E){let J=N.get(O.id)??"General",S=_.get(J)??[];S.push(O),_.set(J,S)}return _}function WE(E){let M=[];if(M.push("[open-mem] Memory context:"),E.recentSummaries.length>0){M.push(`
7
+ Recent sessions:`);for(let N of E.recentSummaries)M.push(`- ${N.summary}`)}if(E.observationIndex.length>0){M.push(`
8
+ Recent observations (${E.observationIndex.length} entries):`);for(let N of E.observationIndex)M.push(`- ${T[N.type]||"\uD83D\uDCDD"} ${N.title}`)}return M.join(`
9
+ `)}function YE(E,M){if(E.length===0)return"";let N=M,_=[];for(let J of E){let S=J.tokenCount||W(J.title);if(N-S<0)break;_.push(J),N-=S}if(_.length===0)return"";let O=[];O.push("### Cross-Project Memory"),O.push(""),O.push("| ID | Type | Title | ~Tokens |"),O.push("|----|------|-------|---------|");for(let J of _){let S=T[J.type]||"\uD83D\uDCDD";O.push(`| ${J.id} | ${S} | ${J.title} | ~${J.tokenCount} |`)}return O.join(`
10
+ `)}function UE(E,M){if(E.length===0)return"";let N=M,_=[];for(let J of E){let S=J.tokenCount||W(J.title);if(N-S<0)break;_.push(J),N-=S}if(_.length===0)return"";let O=[];O.push(`
11
+ Cross-project observations (${_.length} entries):`);for(let J of _)O.push(`- ${T[J.type]||"\uD83D\uDCDD"} ${J.title}`);return O.join(`
12
+ `)}var g={recency:0.4,typeImportance:0.3,sessionAffinity:0.2,tokenEfficiency:0.1},mM={decision:1,bugfix:0.9,feature:0.8,refactor:0.6,discovery:0.5,change:0.4};function TM(E,M){let N=new Date(E),O=(M.getTime()-N.getTime())/3600000;if(O<0)return 1;if(O<24)return 1;if(O<48)return 0.8;if(O<168)return 0.5;return 0.2}function pM(E){return mM[E]??0.3}function vM(E,M){if(!M)return 0.5;return E===M?1:0.3}function gM(E){if(E<=10)return 1;if(E>=200)return 0.2;return 1-(E-10)/190*0.8}function IM(E,M){let N=TM(E.createdAt,M.now),_=pM(E.type),O=vM(E.sessionId,M.currentSessionId),J=gM(E.tokenCount);return N*g.recency+_*g.typeImportance+O*g.sessionAffinity+J*g.tokenEfficiency}function BE(E,M){let N=new Map;for(let _ of E)N.set(_.id,IM(_,M));return[...E].sort((_,O)=>{let J=N.get(_.id)??0,S=N.get(O.id)??0;if(S!==J)return S-J;return new Date(O.createdAt).getTime()-new Date(_.createdAt).getTime()})}function FE(E,M,N,_,O=[],J){let S=_,V=[],C=[];for(let $ of M){let H=$.tokenCount||W($.summary);if(S-H<0)break;V.push($),S-=H}let A=J?BE(N,J):N;for(let $ of A){let H=$.tokenCount||W($.title);if(S-H<0)break;C.push($),S-=H}return{recentSummaries:V,observationIndex:C,fullObservations:[...O],totalTokens:_-S}}import{existsSync as aM}from"fs";import{readdir as eM,readFile as tM,unlink as sM,writeFile as E0}from"fs/promises";import{join as M0,resolve as N0}from"path";import{existsSync as DE}from"fs";import{mkdir as hM,readFile as qM,rename as xM,unlink as uM,writeFile as wM}from"fs/promises";import{dirname as a,isAbsolute as yE,join as I,normalize as lM,relative as jE,resolve as o,sep as r}from"path";var y="<!-- open-mem-context -->",G="<!-- /open-mem-context -->",cM={bugfix:"\uD83D\uDD34",feature:"\uD83D\uDFE3",refactor:"\uD83D\uDD04",change:"\u2705",discovery:"\uD83D\uDD35",decision:"\u2696\uFE0F"},GE=new Map,bM=new Set(["node_modules",".git","dist","coverage",".open-mem","build","__pycache__",".next",".nuxt"]);async function kE(E,M,N=5){if(M.length===0)return;let _=[];for(let S of M){for(let V of S.filesModified)_.push(V);for(let V of S.filesRead)_.push(V)}let O=rM(_,E,N);if(O.size===0)return;let J=oM(M,O,E);for(let[S,V]of J)try{let C=nM(S,V,E);await dM(S,C)}catch(C){console.error(`[open-mem] Failed to update AGENTS.md in ${S}:`,C)}}function nM(E,M,N){let _=[...M].sort((C,A)=>A.createdAt.localeCompare(C.createdAt)).slice(0,10),O=jE(N,E)||".",J=[];J.push(`## Recent Activity in \`${O}/\` (auto-generated by open-mem)`),J.push(""),J.push("| Type | Title | Date |"),J.push("|------|-------|------|");for(let C of _){let A=cM[C.type]||"\uD83D\uDCDD",$=C.createdAt.split("T")[0],H=C.title.replace(/\|/g,"\\|");J.push(`| ${A} ${C.type} | ${H} | ${$} |`)}let S=new Set;for(let C of _)for(let A of C.concepts)S.add(A);if(S.size>0){let C=[...S].slice(0,10).join(", ");J.push(""),J.push(`**Key concepts:** ${C}`)}let V=_.filter((C)=>C.type==="decision").map((C)=>C.title);if(V.length>0)J.push(""),J.push(`**Recent decisions:** ${V.slice(0,5).join("; ")}`);return J.join(`
13
+ `)}async function dM(E,M){if(!DE(E))return;let _=(GE.get(E)??Promise.resolve()).then(async()=>{let O=I(E,"AGENTS.md"),J=I(E,".AGENTS.md.tmp"),S="";try{S=await qM(O,"utf-8")}catch{}let V=iM(S,M);try{await hM(a(J),{recursive:!0}),await wM(J,V,"utf-8"),await xM(J,O)}catch(C){try{await uM(J)}catch{}throw C}});return GE.set(E,_.catch(()=>{})),_}function iM(E,M){if(!E)return`${y}
14
+ ${M}
15
+ ${G}
16
+ `;let N=E.indexOf(y),_=E.indexOf(G);if(N!==-1&&_!==-1&&_>N){let J=E.substring(0,N),S=E.substring(_+G.length);return`${J}${y}
17
+ ${M}
18
+ ${G}${S}`}let O=E;if(N!==-1&&_===-1)O=O.replace(y,"").trim();else if(N===-1&&_!==-1)O=O.replace(G,"").trim();else if(N!==-1&&_!==-1&&_<=N)O=O.replace(G,"").replace(y,"").trim();return`${O}
19
+
20
+ ${y}
21
+ ${M}
22
+ ${G}
23
+ `}function rM(E,M,N){let _=new Set,O=o(M);for(let J of E){if(!J||!J.trim())continue;if(J.startsWith("~")||J.startsWith("http"))continue;let S=yE(J)?J:I(M,J),V=a(S),C=o(V);if(!C.startsWith(O+r)&&C!==O)continue;if(C===O)continue;let A=jE(O,C);if(A.split(r).length>N)continue;if(lM(A).split(r).some((Y)=>bM.has(Y)))continue;if(!DE(C))continue;_.add(C)}return _}function oM(E,M,N){let _=new Map;for(let O of E){let J=[...O.filesModified,...O.filesRead],S=new Set;for(let V of J){if(!V)continue;let C=yE(V)?V:I(N,V),A=o(a(C));if(M.has(A))S.add(A)}for(let V of S){let C=_.get(V)??[];C.push(O),_.set(V,C)}}return _}var e="<!-- open-mem-context -->",h="<!-- /open-mem-context -->";async function fE(E,M){let N;try{N=await eM(E,{withFileTypes:!0,encoding:"utf8"})}catch{return}for(let _ of N){let O=String(_.name);if(O===".git"||O==="node_modules"||O===".open-mem"||O==="dist")continue;let J=M0(E,O);if(_.isDirectory())await fE(J,M);else if(_.isFile()&&O==="AGENTS.md")M.push(J)}}async function PE(E){let M=N0(E),N=[];return await fE(M,N),N}function _0(E){let M=E.indexOf(e),N=E.indexOf(h);if(M===-1&&N===-1)return E;if(M!==-1&&N===-1){let J=E.replace(e,"").trim();return J?`${J}
24
+ `:""}if(M===-1&&N!==-1){let J=E.replace(h,"").trim();return J?`${J}
25
+ `:""}if(N<=M){let J=E.replace(e,"").replace(h,"").trim();return J?`${J}
26
+ `:""}let _=E.slice(0,M).trimEnd(),O=E.slice(N+h.length).trimStart();if(!_&&!O)return"";if(!_)return`${O}
27
+ `;if(!O)return`${_}
28
+ `;return`${_}
29
+
30
+ ${O}
31
+ `}async function mE(E,M=!1){let N=await PE(E),_=0;for(let O of N){let J=await tM(O,"utf-8"),S=_0(J);if(S!==J){if(_+=1,!M)if(S==="")await sM(O);else await E0(O,S,"utf-8")}}return{files:N,changed:_}}async function TE(E,M,N,_,O=!1){let S=M.getAll(E).flatMap((C)=>N.getBySession(C.id));if(O){let C=new Set;for(let A of S)for(let $ of[...A.filesRead,...A.filesModified])C.add($);return{observations:S.length,filesTouched:C.size}}if(!aM(E))return{observations:0,filesTouched:0};await kE(E,S,_);let V=await PE(E);return{observations:S.length,filesTouched:V.length}}class s{observations;sessions;summaries;searchOrchestrator;projectPath;config;userObservationRepo;runtimeSnapshotProvider;configAuditStore;maintenanceHistoryStore;configAuditLogFallback=[];maintenanceLogFallback=[];constructor(E){this.observations=E.observations,this.sessions=E.sessions,this.summaries=E.summaries,this.searchOrchestrator=E.searchOrchestrator,this.projectPath=E.projectPath,this.config=E.config,this.userObservationRepo=E.userObservationRepo??null,this.runtimeSnapshotProvider=E.runtimeSnapshotProvider??null,this.configAuditStore=E.configAuditStore??null,this.maintenanceHistoryStore=E.maintenanceHistoryStore??null}getByIdIncludingArchived(E){let M=this.observations;return M.getByIdIncludingArchived?M.getByIdIncludingArchived(E):this.observations.getById(E)}listByProjectWithState(E){let M=this.observations;if(M.listByProject)return M.listByProject(this.projectPath,E);if(E.state!=="current")return[];return this.listObservations({limit:E.limit,offset:E.offset,type:E.type,sessionId:E.sessionId})}async ingest(E){}async processPending(E){return 0}async search(E,M={}){return this.searchOrchestrator.search(E,{type:M.type,limit:M.limit??10,projectPath:this.projectPath,importanceMin:M.importanceMin,importanceMax:M.importanceMax,createdAfter:M.after,createdBefore:M.before,concepts:M.concepts,files:M.files})}async timeline(E={}){if(E.sessionId){let N=this.sessions.getById(E.sessionId);if(!N)return[];return[{session:N,summary:this.summaries.getBySessionId(N.id),observations:this.observations.getBySession(N.id)}]}return this.sessions.getRecent(this.projectPath,E.limit??5).map((N)=>({session:N,summary:this.summaries.getBySessionId(N.id),observations:[]}))}async recall(E,M=10){let N=[];for(let _ of E.slice(0,M)){let O=this.observations.getById(_);if(O){N.push(O);continue}if(!this.userObservationRepo)continue;let J=this.userObservationRepo.getById(_);if(!J)continue;N.push({...J,sessionId:"",rawToolOutput:"",discoveryTokens:0})}return N}async save(E){if(E.scope==="user"){if(!this.userObservationRepo)return null;return{...this.userObservationRepo.create({type:E.type,title:E.title,subtitle:"",facts:[],narrative:E.narrative,concepts:E.concepts??[],filesRead:[],filesModified:E.files??[],toolName:"memory.create",tokenCount:W(`${E.title} ${E.narrative}`),importance:E.importance??3,sourceProject:this.projectPath}),sessionId:"",rawToolOutput:"",discoveryTokens:0}}this.sessions.getOrCreate(E.sessionId,this.projectPath);let M=this.observations.create({sessionId:E.sessionId,type:E.type,title:E.title,subtitle:"",facts:[],narrative:E.narrative,concepts:E.concepts??[],filesRead:[],filesModified:E.files??[],rawToolOutput:`[Manual save] ${E.narrative}`,toolName:"memory.create",tokenCount:W(`${E.title} ${E.narrative}`),discoveryTokens:0,importance:E.importance??3});return this.sessions.incrementObservationCount(E.sessionId),M}async update(E){let M=this.observations.getById(E.id);if(!M)return null;let N=this.sessions.getById(M.sessionId);if(!N||N.projectPath!==this.projectPath)return null;let{id:_,...O}=E;return this.observations.update(E.id,O)??null}async delete(E){let M=0;for(let N of E){let _=this.observations.getById(N);if(!_)continue;let O=this.sessions.getById(_.sessionId);if(!O||O.projectPath!==this.projectPath)continue;if(this.observations.delete(N))M+=1}return M}async export(E,M={}){if(E!=="project")throw Error("Only project scope export is supported.");let N=this.sessions.getAll(this.projectPath),_=[];for(let V of N)_.push(...this.observations.getBySession(V.id));if(M.type)_=_.filter((V)=>V.type===M.type);if(_.sort((V,C)=>new Date(V.createdAt).getTime()-new Date(C.createdAt).getTime()),M.limit&&M.limit<_.length)_=_.slice(0,M.limit);let O=_.map(({rawToolOutput:V,...C})=>C),J=N.map((V)=>this.summaries.getBySessionId(V.id)).filter((V)=>V!==null);return{version:1,exportedAt:new Date().toISOString(),project:this.projectPath,observations:O,summaries:J}}async import(E,M={}){let N;try{N=JSON.parse(E)}catch{throw Error("Invalid JSON payload.")}if(typeof N!=="object"||N===null)throw Error("Invalid import payload.");let _=N;if(_.version!==1||!Array.isArray(_.observations))throw Error("Unsupported export format.");let O=M.mode??"skip-duplicates",J=0,S=0;for(let V of _.observations){let C=this.observations.getById(V.id);if(C&&O==="skip-duplicates"){S+=1;continue}if(C&&O==="overwrite")this.observations.delete(V.id);this.sessions.getOrCreate(V.sessionId,this.projectPath),this.observations.importObservation({id:V.id,sessionId:V.sessionId,type:V.type,title:V.title,subtitle:V.subtitle??"",facts:V.facts??[],narrative:V.narrative??"",concepts:V.concepts??[],filesRead:V.filesRead??[],filesModified:V.filesModified??[],rawToolOutput:V.rawToolOutput??"",toolName:V.toolName??"unknown",createdAt:V.createdAt,tokenCount:V.tokenCount??0,discoveryTokens:V.discoveryTokens??0,importance:V.importance??3,supersededBy:V.supersededBy??null,supersededAt:V.supersededAt??null}),this.sessions.incrementObservationCount(V.sessionId),J+=1}for(let V of _.summaries??[]){let C=this.summaries.getBySessionId(V.sessionId);if(C&&O==="skip-duplicates")continue;if(C&&O==="overwrite")continue;this.sessions.getOrCreate(V.sessionId,this.projectPath),this.summaries.importSummary(V),this.sessions.setSummary(V.sessionId,V.id)}return{imported:J,skipped:S}}async buildContext(E,M="normal"){let N=this.sessions.getRecent(this.projectPath,5),_=N.map(($)=>$.summaryId?this.summaries.getBySessionId($.id):null).filter(($)=>$!==null),O=this.observations.getIndex(this.projectPath,this.config.maxObservations),S=O.slice(0,this.config.contextFullObservationCount).map(($)=>$.id).map(($)=>this.observations.getById($)).filter(($)=>$!==null),V=FE(N,_,O,this.config.maxContextTokens,S);if(M==="compaction"){let $=WE(V);if(this.config.userMemoryEnabled&&this.userObservationRepo)$+=UE(this.userObservationRepo.getIndex(this.config.maxObservations),this.config.userMemoryMaxContextTokens);return $}let C={showTokenCosts:this.config.contextShowTokenCosts,observationTypes:this.config.contextObservationTypes,fullObservationCount:this.config.contextFullObservationCount,showLastSummary:this.config.contextShowLastSummary},A=zE(V,C);if(this.config.userMemoryEnabled&&this.userObservationRepo){let $=YE(this.userObservationRepo.getIndex(this.config.maxObservations),this.config.userMemoryMaxContextTokens);if($)A+=`
32
+
33
+ ${$}`}return A}guide(){return["open-mem workflow:","1) Use memory.find to find candidate observations by query.","2) Use memory.history to inspect session-level history and summaries.","3) Use memory.get with IDs from find/history to fetch full details.","Write/edit flow: memory.create (new), memory.revise (refine), memory.remove (tombstone).","Transfer flow: memory.transfer.export for backup/portability, memory.transfer.import to restore."].join(`
34
+ `)}listObservations(E){let{limit:M=50,offset:N=0,type:_,sessionId:O,state:J}=E;if(J)return this.listByProjectWithState({limit:M,offset:N,type:_,state:J,sessionId:O});if(O){let C=this.observations.getBySession(O);if(_)C=C.filter((A)=>A.type===_);return C.slice(N,N+M)}let V=this.observations.getIndex(this.projectPath,N+M).slice(N);if(_)V=V.filter((C)=>C.type===_);return V.map((C)=>this.observations.getById(C.id)).filter((C)=>C!==null)}getObservation(E){return this.observations.getById(E)}getLineage(E){let N=this.getByIdIncludingArchived(E);if(!N)return null;let _=N,O=0,J=new Set([N.id]);while(_.revisionOf&&O<256){let $=this.getByIdIncludingArchived(_.revisionOf);if(!$||J.has($.id))break;_=$,J.add($.id),O+=1}let S=[],V=_,C=new Set,A=0;while(V&&!C.has(V.id)&&A<256){C.add(V.id);let $=V.deletedAt?"tombstoned":V.supersededBy?"superseded":"current";S.push({id:V.id,revisionOf:V.revisionOf??null,supersededBy:V.supersededBy??null,supersededAt:V.supersededAt??null,deletedAt:V.deletedAt??null,state:$,observation:V}),V=V.supersededBy?this.getByIdIncludingArchived(V.supersededBy):null,A+=1}return S}listSessions(E){return this.sessions.getRecent(E.projectPath??this.projectPath,E.limit??20)}getSession(E){let M=this.sessions.getById(E);if(!M)return null;return{session:M,summary:this.summaries.getBySessionId(E),observations:this.observations.getBySession(E)}}stats(){let E=this.observations.getCount(),N=this.sessions.getAll(this.projectPath).length,_=this.observations.getIndex(this.projectPath,1e4),O=0,J=0,S={};for(let A of _)O+=A.tokenCount,J+=A.discoveryTokens,S[A.type]=(S[A.type]||0)+1;let V=J-O,C=_.length>0?Math.round(O/_.length):0;return{totalObservations:E,totalSessions:N,totalTokensSaved:V,averageObservationSize:C,typeBreakdown:S}}async maintainFolderContext(E,M){if(E==="rebuild"){let _=await TE(this.projectPath,this.sessions,this.observations,this.config.folderContextMaxDepth,M);return{action:E,dryRun:M,..._}}let N=await mE(this.projectPath,M);return{action:"clean",dryRun:M,...N}}getRevisionDiff(E,M){let N=this.getByIdIncludingArchived(E),_=this.getByIdIncludingArchived(M);if(!N||!_)return null;let O=[],J=(V,C,A)=>{if(JSON.stringify(C)!==JSON.stringify(A))O.push({field:V,before:C,after:A})};J("title",_.title,N.title),J("subtitle",_.subtitle,N.subtitle),J("narrative",_.narrative,N.narrative),J("type",_.type,N.type),J("facts",_.facts,N.facts),J("concepts",_.concepts,N.concepts),J("filesRead",_.filesRead,N.filesRead),J("filesModified",_.filesModified,N.filesModified),J("importance",_.importance,N.importance);let S=O.length===0?"No material changes between revisions.":`Changed ${O.length} field${O.length===1?"":"s"}: ${O.map((V)=>V.field).join(", ")}.`;return{fromId:M,toId:E,summary:S,changedFields:O}}getHealth(){let E=this.runtimeSnapshotProvider?.(),M=E&&E.queue.lastError?"degraded":"ok";return{status:E?.status??"ok",timestamp:E?.timestamp??new Date().toISOString(),components:{database:{status:"ok"},search:{status:"ok"},config:{status:"ok"},queue:{status:M,detail:E?.queue.lastError??void 0}}}}getMetrics(){let E=this.stats();return{timestamp:this.runtimeSnapshotProvider?.()?.timestamp??new Date().toISOString(),memory:{totalObservations:E.totalObservations,totalSessions:E.totalSessions,totalTokensSaved:E.totalTokensSaved,averageObservationSize:E.averageObservationSize}}}getPlatforms(){return{name:"open-mem",provider:this.config.provider,dashboardEnabled:this.config.dashboardEnabled,vectorEnabled:Boolean(this.config.embeddingDimension&&this.config.embeddingDimension>0)}}getAdapterStatuses(){let E={opencode:this.config.platformOpenCodeEnabled??!0,"claude-code":this.config.platformClaudeCodeEnabled??!1,cursor:this.config.platformCursorEnabled??!1};return[{name:"opencode",version:"1.0",capabilities:{nativeSessionLifecycle:!0,nativeToolCapture:!0,nativeChatCapture:!0,emulatedIdleFlush:!1}},{name:"claude-code",version:"0.1",capabilities:{nativeSessionLifecycle:!0,nativeToolCapture:!0,nativeChatCapture:!0,emulatedIdleFlush:!0}},{name:"cursor",version:"0.1",capabilities:{nativeSessionLifecycle:!1,nativeToolCapture:!0,nativeChatCapture:!0,emulatedIdleFlush:!0}}].map((N)=>({name:N.name,version:N.version,enabled:E[N.name]??!1,capabilities:N.capabilities}))}getConfigAuditTimeline(){if(this.configAuditStore)return this.configAuditStore.list();return[...this.configAuditLogFallback].reverse()}trackConfigAudit(E){if(this.configAuditStore){this.configAuditStore.append(E);return}this.configAuditLogFallback.push(E)}async rollbackConfig(E){let M=this.configAuditStore?this.configAuditStore.getById(E):this.configAuditLogFallback.find((J)=>J.id===E)??null;if(!M)return null;if(!M.previousValues||typeof M.previousValues!=="object")return null;let{patchConfig:N}=await Promise.resolve().then(() => (qE(),hE)),_=M.previousValues;try{await N(this.projectPath,_)}catch(J){let S={id:`rollback-failed-${xE()}`,timestamp:new Date().toISOString(),patch:M.previousValues,previousValues:M.patch,source:"rollback-failed"};throw this.trackConfigAudit(S),J}let O={id:`rollback-${xE()}`,timestamp:new Date().toISOString(),patch:M.previousValues,previousValues:M.patch,source:"rollback"};return this.trackConfigAudit(O),O}getMaintenanceHistory(){if(this.maintenanceHistoryStore)return this.maintenanceHistoryStore.list();return[...this.maintenanceLogFallback].reverse()}trackMaintenanceResult(E){if(this.maintenanceHistoryStore){this.maintenanceHistoryStore.append(E);return}this.maintenanceLogFallback.push(E)}}function x(E){try{let M=JSON.parse(E);return M&&typeof M==="object"?M:{}}catch{return{}}}class EE{db;constructor(E){this.db=E}list(){return this.db.all("SELECT id, timestamp, patch, previous_values, source FROM config_audit_events ORDER BY timestamp DESC").map((E)=>({id:E.id,timestamp:E.timestamp,patch:x(E.patch),previousValues:x(E.previous_values),source:E.source}))}getById(E){let M=this.db.get("SELECT id, timestamp, patch, previous_values, source FROM config_audit_events WHERE id = ?",[E]);if(!M)return null;return{id:M.id,timestamp:M.timestamp,patch:x(M.patch),previousValues:x(M.previous_values),source:M.source}}append(E){this.db.run("INSERT INTO config_audit_events (id, timestamp, patch, previous_values, source) VALUES (?, ?, ?, ?, ?)",[E.id,E.timestamp,JSON.stringify(E.patch??{}),JSON.stringify(E.previousValues??{}),E.source])}}import{Database as uE}from"bun:sqlite";import{existsSync as ME,mkdirSync as K0,unlinkSync as wE}from"fs";import*as lE from"sqlite-vec";class u{db;dbPath;_hasVectorExtension=!1;static enableExtensionSupport(){let E=["/opt/homebrew/opt/sqlite/lib/libsqlite3.dylib","/usr/local/opt/sqlite/lib/libsqlite3.dylib"];for(let M of E)try{if(ME(M))return uE.setCustomSQLite(M),!0}catch{return!1}return!1}constructor(E){this.dbPath=E,this.db=this.open(E),this.configure()}open(E){let M=E.lastIndexOf("/");if(M>0){let N=E.substring(0,M);K0(N,{recursive:!0})}return new uE(E,{create:!0})}configure(){try{this.applyPragmas(),this.loadExtensions()}catch(E){console.warn("[open-mem] Database configure failed, attempting recovery by removing WAL/SHM files:",E.message);try{this.db.close()}catch{}this.deleteSidecarFiles();try{this.db=this.open(this.dbPath),this.applyPragmas(),this.loadExtensions(),console.warn("[open-mem] Recovery successful after removing WAL/SHM files");return}catch(M){console.warn("[open-mem] WAL/SHM cleanup insufficient, recreating database from scratch:",M.message);try{this.db.close()}catch{}this.deleteDatabaseFiles();try{this.db=this.open(this.dbPath),this.applyPragmas(),this.loadExtensions(),console.warn("[open-mem] Recovery successful after full database recreation");return}catch(N){throw console.warn("[open-mem] All recovery attempts failed, filesystem may be broken:",N.message),E}}}}applyPragmas(){this.db.exec("PRAGMA journal_mode = WAL"),this.db.exec("PRAGMA synchronous = NORMAL"),this.db.exec("PRAGMA foreign_keys = ON"),this.db.exec("PRAGMA busy_timeout = 5000")}loadExtensions(){try{lE.load(this.db),this._hasVectorExtension=!0}catch{this._hasVectorExtension=!1}}get hasVectorExtension(){return this._hasVectorExtension}deleteSidecarFiles(){for(let E of["-wal","-shm"]){let M=this.dbPath+E;try{if(ME(M))wE(M)}catch{}}}deleteDatabaseFiles(){this.deleteSidecarFiles();try{if(ME(this.dbPath))wE(this.dbPath)}catch{}}ensureMigrationTable(){this.db.exec(`
31
35
  CREATE TABLE IF NOT EXISTS _migrations (
32
36
  version INTEGER PRIMARY KEY,
33
37
  name TEXT NOT NULL,
34
38
  applied_at TEXT NOT NULL DEFAULT (datetime('now'))
35
39
  )
36
- `)}migrate($){this.ensureMigrationTable();let J=this.db.query("SELECT version FROM _migrations ORDER BY version").all(),S=new Set(J.map((Q)=>Q.version)),M=$.filter((Q)=>!S.has(Q.version)).sort((Q,Z)=>Q.version-Z.version);for(let Q of M)this.db.transaction(()=>{this.db.exec(Q.up),this.db.query("INSERT INTO _migrations (version, name) VALUES ($version, $name)").run({$version:Q.version,$name:Q.name})})()}run($,J){let S=this.db.query($);if(J)S.run(...J);else S.run()}get($,J){let S=this.db.query($);return J?S.get(...J):S.get()}all($,J){let S=this.db.query($);return J?S.all(...J):S.all()}exec($){this.db.exec($)}transaction($){return this.db.transaction($)()}close(){this.db.close()}get isOpen(){try{return this.db.query("SELECT 1").get(),!0}catch{return!1}}get raw(){return this.db}}function O($){return new C($)}import{randomUUID as _$}from"crypto";class u{db;constructor($){this.db=$}upsertEntity($,J){let S=_$(),M=new Date().toISOString();this.db.run(`INSERT INTO entities (id, name, entity_type, first_seen_at, last_seen_at, mention_count)
40
+ `)}migrate(E){this.ensureMigrationTable();let M=this.db.query("SELECT version FROM _migrations ORDER BY version").all(),N=new Set(M.map((O)=>O.version)),_=E.filter((O)=>!N.has(O.version)).sort((O,J)=>O.version-J.version);for(let O of _)this.db.transaction(()=>{this.db.exec(O.up),this.db.query("INSERT INTO _migrations (version, name) VALUES ($version, $name)").run({$version:O.version,$name:O.name})})()}run(E,M){let N=this.db.query(E);if(M)N.run(...M);else N.run()}get(E,M){let N=this.db.query(E);return M?N.get(...M):N.get()}all(E,M){let N=this.db.query(E);return M?N.all(...M):N.all()}exec(E){this.db.exec(E)}transaction(E){return this.db.transaction(E)()}close(){this.db.close()}get isOpen(){try{return this.db.query("SELECT 1").get(),!0}catch{return!1}}get raw(){return this.db}}function w(E){return new u(E)}import{randomUUID as cE}from"crypto";class NE{db;constructor(E){this.db=E}upsertEntity(E,M){let N=cE(),_=new Date().toISOString();this.db.run(`INSERT INTO entities (id, name, entity_type, first_seen_at, last_seen_at, mention_count)
37
41
  VALUES (?, ?, ?, ?, ?, 1)
38
42
  ON CONFLICT(name, entity_type) DO UPDATE SET
39
43
  mention_count = mention_count + 1,
40
- last_seen_at = ?`,[S,$,J,M,M,M]);let Q=this.db.get("SELECT * FROM entities WHERE name = ? AND entity_type = ?",[$,J]);if(!Q)throw Error(`Failed to upsert entity: ${$} (${J})`);return this.mapEntityRow(Q)}createRelation($,J,S,M){let Q=_$(),Z=new Date().toISOString();try{this.db.run(`INSERT OR IGNORE INTO entity_relations
44
+ last_seen_at = ?`,[N,E,M,_,_,_]);let O=this.db.get("SELECT * FROM entities WHERE name = ? AND entity_type = ?",[E,M]);if(!O)throw Error(`Failed to upsert entity: ${E} (${M})`);return this.mapEntityRow(O)}createRelation(E,M,N,_){let O=cE(),J=new Date().toISOString();try{this.db.run(`INSERT OR IGNORE INTO entity_relations
41
45
  (id, source_entity_id, target_entity_id, relationship, observation_id, created_at)
42
- VALUES (?, ?, ?, ?, ?, ?)`,[Q,$,J,S,M,Z])}catch{return null}let X=this.db.get(`SELECT * FROM entity_relations
43
- WHERE source_entity_id = ? AND target_entity_id = ? AND relationship = ?`,[$,J,S]);return X?this.mapRelationRow(X):null}linkObservation($,J){this.db.run("INSERT OR IGNORE INTO entity_observations (entity_id, observation_id) VALUES (?, ?)",[$,J])}findByName($){try{return this.db.all(`SELECT e.*
46
+ VALUES (?, ?, ?, ?, ?, ?)`,[O,E,M,N,_,J])}catch{return null}let S=this.db.get(`SELECT * FROM entity_relations
47
+ WHERE source_entity_id = ? AND target_entity_id = ? AND relationship = ?`,[E,M,N]);return S?this.mapRelationRow(S):null}linkObservation(E,M){this.db.run("INSERT OR IGNORE INTO entity_observations (entity_id, observation_id) VALUES (?, ?)",[E,M])}findByName(E){try{return this.db.all(`SELECT e.*
44
48
  FROM entities e
45
49
  JOIN entities_fts fts ON e._rowid = fts.rowid
46
50
  WHERE entities_fts MATCH ?
47
- ORDER BY rank`,[$]).map((S)=>this.mapEntityRow(S))}catch{return[]}}getRelationsFor($){return this.db.all(`SELECT * FROM entity_relations
48
- WHERE source_entity_id = ? OR target_entity_id = ?`,[$,$]).map((S)=>this.mapRelationRow(S))}traverseRelations($,J=1){let S=Math.min(J,2),M=100,Q=new Set,Z=[{id:$,currentDepth:0}];Q.add($);while(Z.length>0){if(Q.size>=100)break;let X=Z.shift();if(X.currentDepth>=S)continue;let U=this.getRelationsFor(X.id);for(let K of U){let W=K.sourceEntityId===X.id?K.targetEntityId:K.sourceEntityId;if(!Q.has(W))Q.add(W),Z.push({id:W,currentDepth:X.currentDepth+1})}}return Q}getObservationsForEntity($){return this.db.all("SELECT observation_id FROM entity_observations WHERE entity_id = ?",[$]).map((S)=>S.observation_id)}getById($){let J=this.db.get("SELECT * FROM entities WHERE id = ?",[$]);return J?this.mapEntityRow(J):null}mapEntityRow($){return{id:$.id,name:$.name,entityType:$.entity_type,firstSeenAt:$.first_seen_at,lastSeenAt:$.last_seen_at,mentionCount:$.mention_count}}mapRelationRow($){return{id:$.id,sourceEntityId:$.source_entity_id,targetEntityId:$.target_entity_id,relationship:$.relationship,observationId:$.observation_id,createdAt:$.created_at}}}import{randomUUID as y0}from"crypto";import{embed as T0}from"ai";async function x($,J){try{let{embedding:S}=await T0({model:$,value:J});return S}catch{return null}}function B($,J){if($.length!==J.length||$.length===0)return 0;let S=0,M=0,Q=0;for(let X=0;X<$.length;X++)S+=$[X]*J[X],M+=$[X]*$[X],Q+=J[X]*J[X];let Z=Math.sqrt(M)*Math.sqrt(Q);if(Z===0)return 0;return S/Z}function v0($){return $.replace(/[%_\\]/g,"\\$&")}class w{db;constructor($){this.db=$}create($){let J=y0(),S=new Date().toISOString(),M=$.discoveryTokens??0,Q=$.importance??3,Z=$.scope??"project";return this.db.run(`INSERT INTO observations
51
+ ORDER BY rank`,[E]).map((N)=>this.mapEntityRow(N))}catch{return[]}}getRelationsFor(E){return this.db.all(`SELECT * FROM entity_relations
52
+ WHERE source_entity_id = ? OR target_entity_id = ?`,[E,E]).map((N)=>this.mapRelationRow(N))}traverseRelations(E,M=1){let N=Math.min(M,2),_=100,O=new Set,J=[{id:E,currentDepth:0}];O.add(E);while(J.length>0){if(O.size>=100)break;let S=J.shift();if(!S)continue;if(S.currentDepth>=N)continue;let V=this.getRelationsFor(S.id);for(let C of V){let A=C.sourceEntityId===S.id?C.targetEntityId:C.sourceEntityId;if(!O.has(A))O.add(A),J.push({id:A,currentDepth:S.currentDepth+1})}}return O}getObservationsForEntity(E){return this.db.all("SELECT observation_id FROM entity_observations WHERE entity_id = ?",[E]).map((N)=>N.observation_id)}getById(E){let M=this.db.get("SELECT * FROM entities WHERE id = ?",[E]);return M?this.mapEntityRow(M):null}mapEntityRow(E){return{id:E.id,name:E.name,entityType:E.entity_type,firstSeenAt:E.first_seen_at,lastSeenAt:E.last_seen_at,mentionCount:E.mention_count}}mapRelationRow(E){return{id:E.id,sourceEntityId:E.source_entity_id,targetEntityId:E.target_entity_id,relationship:E.relationship,observationId:E.observation_id,createdAt:E.created_at}}}function L0(E){try{let M=JSON.parse(E);return M&&typeof M==="object"?M:{}}catch{return{}}}class _E{db;constructor(E){this.db=E}list(){return this.db.all("SELECT id, timestamp, action, dry_run, result FROM maintenance_history ORDER BY timestamp DESC").map((E)=>({id:E.id,timestamp:E.timestamp,action:E.action,dryRun:E.dry_run===1,result:L0(E.result)}))}append(E){this.db.run("INSERT INTO maintenance_history (id, timestamp, action, dry_run, result) VALUES (?, ?, ?, ?, ?)",[E.id,E.timestamp,E.action,E.dryRun?1:0,JSON.stringify(E.result??{})])}}import{randomUUID as z0}from"crypto";import{embed as Q0}from"ai";async function l(E,M){try{let{embedding:N}=await Q0({model:E,value:M});return N}catch{return null}}function j(E,M){if(E.length!==M.length||E.length===0)return 0;let N=0,_=0,O=0;for(let S=0;S<E.length;S++)N+=E[S]*M[S],_+=E[S]*E[S],O+=M[S]*M[S];let J=Math.sqrt(_)*Math.sqrt(O);if(J===0)return 0;return N/J}function W0(E){return E.replace(/[%_\\]/g,"\\$&")}class OE{db;constructor(E){this.db=E}create(E){let M=z0(),N=new Date().toISOString(),_=E.discoveryTokens??0,O=E.importance??3,J=E.scope??"project";return this.db.run(`INSERT INTO observations
49
53
  (id, session_id, scope, type, title, subtitle, facts, narrative,
50
54
  concepts, files_read, files_modified, raw_tool_output,
51
55
  tool_name, created_at, token_count, discovery_tokens, importance, revision_of, deleted_at)
52
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,[J,$.sessionId,Z,$.type,$.title,$.subtitle,JSON.stringify($.facts),$.narrative,JSON.stringify($.concepts),JSON.stringify($.filesRead),JSON.stringify($.filesModified),$.rawToolOutput,$.toolName,S,$.tokenCount,M,Q,null,null]),{...$,id:J,scope:Z,createdAt:S,discoveryTokens:M,importance:Q,revisionOf:null,deletedAt:null,supersededBy:null,supersededAt:null}}importObservation($){this.db.run(`INSERT INTO observations
56
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,[M,E.sessionId,J,E.type,E.title,E.subtitle,JSON.stringify(E.facts),E.narrative,JSON.stringify(E.concepts),JSON.stringify(E.filesRead),JSON.stringify(E.filesModified),E.rawToolOutput,E.toolName,N,E.tokenCount,_,O,null,null]),{...E,id:M,scope:J,createdAt:N,discoveryTokens:_,importance:O,revisionOf:null,deletedAt:null,supersededBy:null,supersededAt:null}}importObservation(E){this.db.run(`INSERT INTO observations
53
57
  (id, session_id, scope, type, title, subtitle, facts, narrative,
54
58
  concepts, files_read, files_modified, raw_tool_output,
55
59
  tool_name, created_at, token_count, discovery_tokens, importance, revision_of, deleted_at)
56
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,[$.id,$.sessionId,$.scope??"project",$.type,$.title,$.subtitle,JSON.stringify($.facts),$.narrative,JSON.stringify($.concepts),JSON.stringify($.filesRead),JSON.stringify($.filesModified),$.rawToolOutput,$.toolName,$.createdAt,$.tokenCount,$.discoveryTokens??0,$.importance??3,$.revisionOf??null,$.deletedAt??null])}getById($){let J=this.db.get("SELECT * FROM observations WHERE id = ? AND superseded_by IS NULL AND deleted_at IS NULL",[$]);return J?this.mapRow(J):null}getBySession($){return this.db.all("SELECT * FROM observations WHERE session_id = ? AND superseded_by IS NULL AND deleted_at IS NULL ORDER BY created_at ASC",[$]).map((J)=>this.mapRow(J))}getCount($){if($)return this.db.get("SELECT COUNT(*) as count FROM observations WHERE session_id = ?",[$])?.count??0;return this.db.get("SELECT COUNT(*) as count FROM observations")?.count??0}getIndex($,J=20){return this.db.all(`SELECT o.id, o.session_id, o.type, o.title, o.token_count, o.discovery_tokens, o.created_at, o.importance
60
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,[E.id,E.sessionId,E.scope??"project",E.type,E.title,E.subtitle,JSON.stringify(E.facts),E.narrative,JSON.stringify(E.concepts),JSON.stringify(E.filesRead),JSON.stringify(E.filesModified),E.rawToolOutput,E.toolName,E.createdAt,E.tokenCount,E.discoveryTokens??0,E.importance??3,E.revisionOf??null,E.deletedAt??null])}getById(E){let M=this.db.get("SELECT * FROM observations WHERE id = ? AND superseded_by IS NULL AND deleted_at IS NULL",[E]);return M?this.mapRow(M):null}getByIdIncludingArchived(E){let M=this.db.get("SELECT * FROM observations WHERE id = ?",[E]);return M?this.mapRow(M):null}getBySession(E){return this.db.all("SELECT * FROM observations WHERE session_id = ? AND superseded_by IS NULL AND deleted_at IS NULL ORDER BY created_at ASC",[E]).map((M)=>this.mapRow(M))}getCount(E){if(E)return this.db.get("SELECT COUNT(*) as count FROM observations WHERE session_id = ?",[E])?.count??0;return this.db.get("SELECT COUNT(*) as count FROM observations")?.count??0}getIndex(E,M=20){return this.db.all(`SELECT o.id, o.session_id, o.type, o.title, o.token_count, o.discovery_tokens, o.created_at, o.importance
57
61
  FROM observations o
58
62
  JOIN sessions s ON o.session_id = s.id
59
63
  WHERE s.project_path = ? AND o.superseded_by IS NULL AND o.deleted_at IS NULL
60
64
  ORDER BY o.created_at DESC
61
- LIMIT ?`,[$,J]).map((S)=>({id:S.id,sessionId:S.session_id,type:S.type,title:S.title,tokenCount:S.token_count,discoveryTokens:S.discovery_tokens??0,createdAt:S.created_at,importance:S.importance??3}))}search($){let J=!!$.projectPath,S=`
65
+ LIMIT ?`,[E,M]).map((N)=>({id:N.id,sessionId:N.session_id,type:N.type,title:N.title,tokenCount:N.token_count,discoveryTokens:N.discovery_tokens??0,createdAt:N.created_at,importance:N.importance??3}))}listByProject(E,M={}){let{limit:N=50,offset:_=0,type:O,state:J,sessionId:S}=M,V=`SELECT o.*
66
+ FROM observations o
67
+ JOIN sessions s ON o.session_id = s.id
68
+ WHERE s.project_path = ?`,C=[E];if(S)V+=" AND o.session_id = ?",C.push(S);if(O)V+=" AND o.type = ?",C.push(O);if(J==="current")V+=" AND o.superseded_by IS NULL AND o.deleted_at IS NULL";else if(J==="superseded")V+=" AND o.superseded_by IS NOT NULL AND o.deleted_at IS NULL";else if(J==="tombstoned")V+=" AND o.deleted_at IS NOT NULL";else V+=" AND o.superseded_by IS NULL AND o.deleted_at IS NULL";return V+=" ORDER BY o.created_at DESC LIMIT ? OFFSET ?",C.push(N,_),this.db.all(V,C).map((A)=>this.mapRow(A))}search(E){let M=!!E.projectPath,N=`
62
69
  SELECT o.*, rank
63
70
  FROM observations o
64
71
  JOIN observations_fts fts ON o._rowid = fts.rowid
65
- ${J?"JOIN sessions s ON o.session_id = s.id":""}
72
+ ${M?"JOIN sessions s ON o.session_id = s.id":""}
66
73
  WHERE observations_fts MATCH ? AND o.superseded_by IS NULL AND o.deleted_at IS NULL
67
- `,M=[$.query];if(J&&$.projectPath)S+=" AND s.project_path = ?",M.push($.projectPath);if($.sessionId)S+=" AND o.session_id = ?",M.push($.sessionId);if($.type)S+=" AND o.type = ?",M.push($.type);if($.importanceMin!==void 0)S+=" AND o.importance >= ?",M.push($.importanceMin);if($.importanceMax!==void 0)S+=" AND o.importance <= ?",M.push($.importanceMax);if($.createdAfter)S+=" AND o.created_at >= ?",M.push($.createdAfter);if($.createdBefore)S+=" AND o.created_at <= ?",M.push($.createdBefore);if($.concepts&&$.concepts.length>0){let Q=$.concepts.map(()=>"EXISTS (SELECT 1 FROM json_each(o.concepts) WHERE LOWER(value) = LOWER(?))");S+=` AND (${Q.join(" OR ")})`;for(let Z of $.concepts)M.push(Z)}if($.files&&$.files.length>0){let Q=$.files.map(()=>`(EXISTS (SELECT 1 FROM json_each(o.files_read) WHERE LOWER(value) LIKE LOWER(?) ESCAPE '\\')
68
- OR EXISTS (SELECT 1 FROM json_each(o.files_modified) WHERE LOWER(value) LIKE LOWER(?) ESCAPE '\\'))`);S+=` AND (${Q.join(" OR ")})`;for(let Z of $.files){let X=`%${v0(Z)}%`;M.push(X,X)}}return S+=" ORDER BY rank LIMIT ? OFFSET ?",M.push($.limit??10),M.push($.offset??0),this.db.all(S,M).map((Q)=>({observation:this.mapRow(Q),rank:Q.rank,snippet:Q.title}))}searchByConcept($,J=10,S){let M=!!S,Q=`SELECT o.*
74
+ `,_=[E.query];if(M&&E.projectPath)N+=" AND s.project_path = ?",_.push(E.projectPath);if(E.sessionId)N+=" AND o.session_id = ?",_.push(E.sessionId);if(E.type)N+=" AND o.type = ?",_.push(E.type);if(E.importanceMin!==void 0)N+=" AND o.importance >= ?",_.push(E.importanceMin);if(E.importanceMax!==void 0)N+=" AND o.importance <= ?",_.push(E.importanceMax);if(E.createdAfter)N+=" AND o.created_at >= ?",_.push(E.createdAfter);if(E.createdBefore)N+=" AND o.created_at <= ?",_.push(E.createdBefore);if(E.concepts&&E.concepts.length>0){let O=E.concepts.map(()=>"EXISTS (SELECT 1 FROM json_each(o.concepts) WHERE LOWER(value) = LOWER(?))");N+=` AND (${O.join(" OR ")})`;for(let J of E.concepts)_.push(J)}if(E.files&&E.files.length>0){let O=E.files.map(()=>`(EXISTS (SELECT 1 FROM json_each(o.files_read) WHERE LOWER(value) LIKE LOWER(?) ESCAPE '\\')
75
+ OR EXISTS (SELECT 1 FROM json_each(o.files_modified) WHERE LOWER(value) LIKE LOWER(?) ESCAPE '\\'))`);N+=` AND (${O.join(" OR ")})`;for(let J of E.files){let S=`%${W0(J)}%`;_.push(S,S)}}return N+=" ORDER BY rank LIMIT ? OFFSET ?",_.push(E.limit??10),_.push(E.offset??0),this.db.all(N,_).map((O)=>({observation:this.mapRow(O),rank:O.rank,snippet:O.title}))}searchByConcept(E,M=10,N){let _=!!N,O=`SELECT o.*
69
76
  FROM observations o
70
77
  JOIN observations_fts fts ON o._rowid = fts.rowid
71
- ${M?"JOIN sessions s ON o.session_id = s.id":""}
78
+ ${_?"JOIN sessions s ON o.session_id = s.id":""}
72
79
  WHERE observations_fts MATCH ?
73
80
  AND o.superseded_by IS NULL AND o.deleted_at IS NULL
74
- ${M?"AND s.project_path = ?":""}
81
+ ${_?"AND s.project_path = ?":""}
75
82
  ORDER BY rank
76
- LIMIT ?`,Z=[`concepts:${$}`];if(M&&S)Z.push(S);return Z.push(J),this.db.all(Q,Z).map((X)=>this.mapRow(X))}searchByFile($,J=10,S){let M=!!S,Q=`SELECT o.*
83
+ LIMIT ?`,J=[`concepts:${E}`];if(_&&N)J.push(N);return J.push(M),this.db.all(O,J).map((S)=>this.mapRow(S))}searchByFile(E,M=10,N){let _=!!N,O=`SELECT o.*
77
84
  FROM observations o
78
85
  JOIN observations_fts fts ON o._rowid = fts.rowid
79
- ${M?"JOIN sessions s ON o.session_id = s.id":""}
86
+ ${_?"JOIN sessions s ON o.session_id = s.id":""}
80
87
  WHERE observations_fts MATCH ?
81
88
  AND o.superseded_by IS NULL AND o.deleted_at IS NULL
82
- ${M?"AND s.project_path = ?":""}
89
+ ${_?"AND s.project_path = ?":""}
83
90
  ORDER BY rank
84
- LIMIT ?`,Z=[`files_read:"${$.replace(/"/g,'""')}" OR files_modified:"${$.replace(/"/g,'""')}"`];if(M&&S)Z.push(S);return Z.push(J),this.db.all(Q,Z).map((X)=>this.mapRow(X))}setEmbedding($,J){this.db.run("UPDATE observations SET embedding = ? WHERE id = ?",[JSON.stringify(J),$])}getWithEmbeddings($,J){return this.db.all(`SELECT o.id, o.embedding, o.title
91
+ LIMIT ?`,J=[`files_read:"${E.replace(/"/g,'""')}" OR files_modified:"${E.replace(/"/g,'""')}"`];if(_&&N)J.push(N);return J.push(M),this.db.all(O,J).map((S)=>this.mapRow(S))}setEmbedding(E,M){this.db.run("UPDATE observations SET embedding = ? WHERE id = ?",[JSON.stringify(M),E])}getWithEmbeddings(E,M){return this.db.all(`SELECT o.id, o.embedding, o.title
85
92
  FROM observations o
86
93
  JOIN sessions s ON o.session_id = s.id
87
94
  WHERE s.project_path = ? AND o.embedding IS NOT NULL AND o.superseded_by IS NULL AND o.deleted_at IS NULL
88
95
  ORDER BY o.created_at DESC
89
- LIMIT ?`,[$,J]).map((S)=>{try{return{id:S.id,embedding:JSON.parse(S.embedding),title:S.title}}catch{return null}}).filter((S)=>S!==null)}findSimilar($,J,S,M){let Q=this.db.all(`SELECT id, embedding FROM observations
96
+ LIMIT ?`,[E,M]).map((N)=>{try{return{id:N.id,embedding:JSON.parse(N.embedding),title:N.title}}catch{return null}}).filter((N)=>N!==null)}findSimilar(E,M,N,_){let O=this.db.all(`SELECT id, embedding FROM observations
90
97
  WHERE embedding IS NOT NULL AND type = ? AND superseded_by IS NULL AND deleted_at IS NULL
91
98
  ORDER BY created_at DESC
92
- LIMIT 200`,[J]),Z=[];for(let X of Q)try{let U=JSON.parse(X.embedding);if(!Array.isArray(U)||U.length!==$.length)continue;let K=B($,U);if(K>=S)Z.push({id:X.id,similarity:K})}catch{}return Z.sort((X,U)=>U.similarity-X.similarity).slice(0,M)}insertVecEmbedding($,J){let S=new Float32Array(J);this.db.run("BEGIN");try{this.db.run("DELETE FROM observation_embeddings WHERE observation_id = ?",[$]),this.db.run("INSERT INTO observation_embeddings (observation_id, embedding) VALUES (?, ?)",[$,S]),this.db.run("COMMIT")}catch(M){throw this.db.run("ROLLBACK"),M}}migrateExistingEmbeddings($){let J=this.db.all("SELECT id, embedding FROM observations WHERE embedding IS NOT NULL"),S=0,M=0;for(let Q of J)try{let Z=JSON.parse(Q.embedding);if(!Array.isArray(Z)||Z.length!==$){M++;continue}this.insertVecEmbedding(Q.id,Z),S++}catch{M++}return{migrated:S,skipped:M}}getVecEmbeddingMatches($,J){try{let S=new Float32Array($);return this.db.all(`SELECT observation_id, distance
99
+ LIMIT 200`,[M]),J=[];for(let S of O)try{let V=JSON.parse(S.embedding);if(!Array.isArray(V)||V.length!==E.length)continue;let C=j(E,V);if(C>=N)J.push({id:S.id,similarity:C})}catch{}return J.sort((S,V)=>V.similarity-S.similarity).slice(0,_)}insertVecEmbedding(E,M){let N=new Float32Array(M);this.db.run("BEGIN");try{this.db.run("DELETE FROM observation_embeddings WHERE observation_id = ?",[E]),this.db.run("INSERT INTO observation_embeddings (observation_id, embedding) VALUES (?, ?)",[E,N]),this.db.run("COMMIT")}catch(_){throw this.db.run("ROLLBACK"),_}}migrateExistingEmbeddings(E){let M=this.db.all("SELECT id, embedding FROM observations WHERE embedding IS NOT NULL"),N=0,_=0;for(let O of M)try{let J=JSON.parse(O.embedding);if(!Array.isArray(J)||J.length!==E){_++;continue}this.insertVecEmbedding(O.id,J),N++}catch{_++}return{migrated:N,skipped:_}}getVecEmbeddingMatches(E,M){try{let N=new Float32Array(E);return this.db.all(`SELECT observation_id, distance
93
100
  FROM observation_embeddings
94
- WHERE embedding MATCH ? AND k = ?`,[S,J]).map((M)=>({observationId:M.observation_id,distance:M.distance}))}catch{return[]}}searchVecSubset($,J,S){if(J.length===0)return[];try{let M=new Float32Array($),Q=Math.max(S*5,J.length),Z=this.db.all(`SELECT observation_id, distance
101
+ WHERE embedding MATCH ? AND k = ?`,[N,M]).map((_)=>({observationId:_.observation_id,distance:_.distance}))}catch{return[]}}searchVecSubset(E,M,N){if(M.length===0)return[];try{let _=new Float32Array(E),O=Math.max(N*5,M.length),J=this.db.all(`SELECT observation_id, distance
95
102
  FROM observation_embeddings
96
- WHERE embedding MATCH ? AND k = ?`,[M,Q]),X=new Set(J);return Z.filter((U)=>X.has(U.observation_id)).slice(0,S).map((U)=>({observationId:U.observation_id,distance:U.distance}))}catch{return[]}}update($,J){let S=this.getById($);if(!S)return null;if(Object.keys(J).length===0)return S;let M=this.create({sessionId:S.sessionId,scope:S.scope??"project",type:J.type??S.type,title:J.title??S.title,subtitle:J.subtitle??S.subtitle,facts:J.facts??S.facts,narrative:J.narrative??S.narrative,concepts:J.concepts??S.concepts,filesRead:J.filesRead??S.filesRead,filesModified:J.filesModified??S.filesModified,rawToolOutput:S.rawToolOutput,toolName:"mem-update",tokenCount:S.tokenCount,discoveryTokens:S.discoveryTokens,importance:J.importance??S.importance});return this.db.run("UPDATE observations SET revision_of = ? WHERE id = ?",[$,M.id]),this.supersede($,M.id),this.getById(M.id)}supersede($,J){let S=new Date().toISOString();this.db.run("UPDATE observations SET superseded_by = ?, superseded_at = ? WHERE id = ?",[J,S,$])}delete($){if(this.db.all("SELECT id FROM observations WHERE id = ?",[$]).length===0)return!1;let S=new Date().toISOString();return this.db.run("UPDATE observations SET deleted_at = ? WHERE id = ?",[S,$]),this.deleteEmbeddingsForObservations([$]),!0}deleteOlderThan($){return this.db.all(`DELETE FROM observations
103
+ WHERE embedding MATCH ? AND k = ?`,[_,O]),S=new Set(M);return J.filter((V)=>S.has(V.observation_id)).slice(0,N).map((V)=>({observationId:V.observation_id,distance:V.distance}))}catch{return[]}}update(E,M){let N=this.getById(E);if(!N)return null;if(Object.keys(M).length===0)return N;let _=this.create({sessionId:N.sessionId,scope:N.scope??"project",type:M.type??N.type,title:M.title??N.title,subtitle:M.subtitle??N.subtitle,facts:M.facts??N.facts,narrative:M.narrative??N.narrative,concepts:M.concepts??N.concepts,filesRead:M.filesRead??N.filesRead,filesModified:M.filesModified??N.filesModified,rawToolOutput:N.rawToolOutput,toolName:"memory.revise",tokenCount:N.tokenCount,discoveryTokens:N.discoveryTokens,importance:M.importance??N.importance});return this.db.run("UPDATE observations SET revision_of = ? WHERE id = ?",[E,_.id]),this.supersede(E,_.id),this.getById(_.id)}supersede(E,M){let N=new Date().toISOString();this.db.run("UPDATE observations SET superseded_by = ?, superseded_at = ? WHERE id = ?",[M,N,E])}delete(E){if(this.db.all("SELECT id FROM observations WHERE id = ?",[E]).length===0)return!1;let N=new Date().toISOString();return this.db.run("UPDATE observations SET deleted_at = ? WHERE id = ?",[N,E]),this.deleteEmbeddingsForObservations([E]),!0}getLineage(E){let M=this.getByIdIncludingArchived(E);if(!M)return[];let N=new Set([M.id]),_=[M];while(_[0].revisionOf){let O=this.getByIdIncludingArchived(_[0].revisionOf);if(!O||N.has(O.id))break;_.unshift(O),N.add(O.id)}while(_[_.length-1].supersededBy){let O=_[_.length-1].supersededBy;if(!O)break;let J=this.getByIdIncludingArchived(O);if(!J||N.has(J.id))break;_.push(J),N.add(J.id)}return _}deleteOlderThan(E){return this.db.all(`DELETE FROM observations
97
104
  WHERE (created_at < datetime('now', '-' || ? || ' days') OR deleted_at IS NOT NULL)
98
105
  AND session_id NOT IN (SELECT id FROM sessions WHERE status != 'completed')
99
- RETURNING id`,[$]).length}deleteEmbeddingsForObservations($){if($.length===0)return;let J=$.map(()=>"?").join(",");try{this.db.run(`DELETE FROM observation_embeddings WHERE observation_id IN (${J})`,$)}catch{}this.db.run(`UPDATE observations SET embedding = NULL WHERE id IN (${J})`,$)}mapRow($){return{id:$.id,sessionId:$.session_id,scope:$.scope??"project",type:$.type,title:$.title,subtitle:$.subtitle,facts:JSON.parse($.facts),narrative:$.narrative,concepts:JSON.parse($.concepts),filesRead:JSON.parse($.files_read),filesModified:JSON.parse($.files_modified),rawToolOutput:$.raw_tool_output,toolName:$.tool_name,createdAt:$.created_at,tokenCount:$.token_count,discoveryTokens:$.discovery_tokens??0,importance:$.importance??3,revisionOf:$.revision_of??null,deletedAt:$.deleted_at??null,supersededBy:$.superseded_by??null,supersededAt:$.superseded_at??null}}}var I0=[{version:1,name:"create-core-tables",up:`
106
+ RETURNING id`,[E]).length}deleteEmbeddingsForObservations(E){if(E.length===0)return;let M=E.map(()=>"?").join(",");try{this.db.run(`DELETE FROM observation_embeddings WHERE observation_id IN (${M})`,E)}catch{}this.db.run(`UPDATE observations SET embedding = NULL WHERE id IN (${M})`,E)}mapRow(E){return{id:E.id,sessionId:E.session_id,scope:E.scope??"project",type:E.type,title:E.title,subtitle:E.subtitle,facts:JSON.parse(E.facts),narrative:E.narrative,concepts:JSON.parse(E.concepts),filesRead:JSON.parse(E.files_read),filesModified:JSON.parse(E.files_modified),rawToolOutput:E.raw_tool_output,toolName:E.tool_name,createdAt:E.created_at,tokenCount:E.token_count,discoveryTokens:E.discovery_tokens??0,importance:E.importance??3,revisionOf:E.revision_of??null,deletedAt:E.deleted_at??null,supersededBy:E.superseded_by??null,supersededAt:E.superseded_at??null}}}var Y0=[{version:1,name:"create-schema",up:`
100
107
  -- Sessions table
101
108
  CREATE TABLE IF NOT EXISTS sessions (
102
109
  _rowid INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -135,6 +142,15 @@ ${V}`}return W}guide(){return["open-mem workflow:","1) Use mem-search to find ca
135
142
  tool_name TEXT NOT NULL,
136
143
  created_at TEXT NOT NULL DEFAULT (datetime('now')),
137
144
  token_count INTEGER NOT NULL DEFAULT 0,
145
+ discovery_tokens INTEGER NOT NULL DEFAULT 0,
146
+ embedding TEXT,
147
+ importance INTEGER NOT NULL DEFAULT 3,
148
+ superseded_by TEXT,
149
+ superseded_at TEXT,
150
+ scope TEXT NOT NULL DEFAULT 'project'
151
+ CHECK (scope IN ('project','user')),
152
+ revision_of TEXT,
153
+ deleted_at TEXT,
138
154
  FOREIGN KEY (session_id) REFERENCES sessions(id)
139
155
  );
140
156
 
@@ -144,6 +160,23 @@ ${V}`}return W}guide(){return["open-mem workflow:","1) Use mem-search to find ca
144
160
  ON observations(type);
145
161
  CREATE INDEX IF NOT EXISTS idx_observations_created
146
162
  ON observations(created_at DESC);
163
+ CREATE INDEX IF NOT EXISTS idx_observations_superseded
164
+ ON observations(superseded_by);
165
+ CREATE INDEX IF NOT EXISTS idx_observations_scope
166
+ ON observations(scope);
167
+ CREATE INDEX IF NOT EXISTS idx_observations_revision_of
168
+ ON observations(revision_of);
169
+ CREATE INDEX IF NOT EXISTS idx_observations_deleted_at
170
+ ON observations(deleted_at);
171
+
172
+ -- Clean up superseded_by when the superseding observation is deleted
173
+ CREATE TRIGGER IF NOT EXISTS trg_clear_superseded_by
174
+ AFTER DELETE ON observations
175
+ BEGIN
176
+ UPDATE observations
177
+ SET superseded_by = NULL, superseded_at = NULL
178
+ WHERE superseded_by = OLD.id;
179
+ END;
147
180
 
148
181
  -- Session summaries table
149
182
  CREATE TABLE IF NOT EXISTS session_summaries (
@@ -156,6 +189,11 @@ ${V}`}return W}guide(){return["open-mem workflow:","1) Use mem-search to find ca
156
189
  concepts TEXT NOT NULL DEFAULT '[]',
157
190
  created_at TEXT NOT NULL DEFAULT (datetime('now')),
158
191
  token_count INTEGER NOT NULL DEFAULT 0,
192
+ request TEXT NOT NULL DEFAULT '',
193
+ investigated TEXT NOT NULL DEFAULT '',
194
+ learned TEXT NOT NULL DEFAULT '',
195
+ completed TEXT NOT NULL DEFAULT '',
196
+ next_steps TEXT NOT NULL DEFAULT '',
159
197
  FOREIGN KEY (session_id) REFERENCES sessions(id)
160
198
  );
161
199
 
@@ -179,8 +217,83 @@ ${V}`}return W}guide(){return["open-mem workflow:","1) Use mem-search to find ca
179
217
  ON pending_messages(status);
180
218
  CREATE INDEX IF NOT EXISTS idx_pending_session
181
219
  ON pending_messages(session_id);
182
- `},{version:2,name:"create-fts5-tables",up:`
183
- -- FTS5 for observations (title, subtitle, narrative, facts, concepts, files)
220
+
221
+ -- Embedding metadata
222
+ CREATE TABLE IF NOT EXISTS _embedding_meta (
223
+ key TEXT PRIMARY KEY,
224
+ value TEXT NOT NULL
225
+ );
226
+
227
+ -- Config audit events
228
+ CREATE TABLE IF NOT EXISTS config_audit_events (
229
+ _rowid INTEGER PRIMARY KEY AUTOINCREMENT,
230
+ id TEXT UNIQUE NOT NULL,
231
+ timestamp TEXT NOT NULL,
232
+ patch TEXT NOT NULL,
233
+ previous_values TEXT NOT NULL,
234
+ source TEXT NOT NULL
235
+ CHECK (source IN ('api','mode','rollback','rollback-failed'))
236
+ );
237
+ CREATE INDEX IF NOT EXISTS idx_config_audit_timestamp
238
+ ON config_audit_events(timestamp DESC);
239
+
240
+ -- Maintenance history
241
+ CREATE TABLE IF NOT EXISTS maintenance_history (
242
+ _rowid INTEGER PRIMARY KEY AUTOINCREMENT,
243
+ id TEXT UNIQUE NOT NULL,
244
+ timestamp TEXT NOT NULL,
245
+ action TEXT NOT NULL,
246
+ dry_run INTEGER NOT NULL DEFAULT 0,
247
+ result TEXT NOT NULL
248
+ );
249
+ CREATE INDEX IF NOT EXISTS idx_maintenance_history_timestamp
250
+ ON maintenance_history(timestamp DESC);
251
+
252
+ -- Entities table
253
+ CREATE TABLE IF NOT EXISTS entities (
254
+ _rowid INTEGER PRIMARY KEY AUTOINCREMENT,
255
+ id TEXT UNIQUE NOT NULL,
256
+ name TEXT NOT NULL,
257
+ entity_type TEXT NOT NULL
258
+ CHECK (entity_type IN ('technology','library','pattern','concept','file','person','project','other')),
259
+ first_seen_at TEXT NOT NULL DEFAULT (datetime('now')),
260
+ last_seen_at TEXT NOT NULL DEFAULT (datetime('now')),
261
+ mention_count INTEGER NOT NULL DEFAULT 1,
262
+ UNIQUE(name, entity_type)
263
+ );
264
+
265
+ CREATE INDEX IF NOT EXISTS idx_entities_name ON entities(name);
266
+ CREATE INDEX IF NOT EXISTS idx_entities_type ON entities(entity_type);
267
+
268
+ -- Entity relations table
269
+ CREATE TABLE IF NOT EXISTS entity_relations (
270
+ _rowid INTEGER PRIMARY KEY AUTOINCREMENT,
271
+ id TEXT UNIQUE NOT NULL,
272
+ source_entity_id TEXT NOT NULL,
273
+ target_entity_id TEXT NOT NULL,
274
+ relationship TEXT NOT NULL
275
+ CHECK (relationship IN ('uses','depends_on','implements','extends','related_to','replaces','configures')),
276
+ observation_id TEXT NOT NULL,
277
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
278
+ UNIQUE(source_entity_id, target_entity_id, relationship),
279
+ FOREIGN KEY (source_entity_id) REFERENCES entities(id) ON DELETE CASCADE,
280
+ FOREIGN KEY (target_entity_id) REFERENCES entities(id) ON DELETE CASCADE,
281
+ FOREIGN KEY (observation_id) REFERENCES observations(id) ON DELETE CASCADE
282
+ );
283
+
284
+ CREATE INDEX IF NOT EXISTS idx_entity_relations_source ON entity_relations(source_entity_id);
285
+ CREATE INDEX IF NOT EXISTS idx_entity_relations_target ON entity_relations(target_entity_id);
286
+
287
+ -- Entity-Observation junction table
288
+ CREATE TABLE IF NOT EXISTS entity_observations (
289
+ entity_id TEXT NOT NULL,
290
+ observation_id TEXT NOT NULL,
291
+ PRIMARY KEY (entity_id, observation_id),
292
+ FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE CASCADE,
293
+ FOREIGN KEY (observation_id) REFERENCES observations(id) ON DELETE CASCADE
294
+ );
295
+
296
+ -- FTS5 for observations
184
297
  CREATE VIRTUAL TABLE IF NOT EXISTS observations_fts USING fts5(
185
298
  title,
186
299
  subtitle,
@@ -194,7 +307,6 @@ ${V}`}return W}guide(){return["open-mem workflow:","1) Use mem-search to find ca
194
307
  tokenize='porter unicode61'
195
308
  );
196
309
 
197
- -- Triggers to keep FTS5 in sync with observations table
198
310
  CREATE TRIGGER observations_ai AFTER INSERT ON observations BEGIN
199
311
  INSERT INTO observations_fts(
200
312
  rowid, title, subtitle, narrative, facts, concepts,
@@ -251,88 +363,14 @@ ${V}`}return W}guide(){return["open-mem workflow:","1) Use mem-search to find ca
251
363
  VALUES (new._rowid, new.summary, new.key_decisions, new.concepts);
252
364
  END;
253
365
 
254
- CREATE TRIGGER summaries_ad AFTER DELETE ON session_summaries BEGIN
255
- INSERT INTO summaries_fts(
256
- summaries_fts, rowid, summary, key_decisions, concepts
257
- )
258
- VALUES (
259
- 'delete', old._rowid, old.summary, old.key_decisions, old.concepts
260
- );
261
- END;
262
- `},{version:3,name:"add-structured-summary-columns",up:`
263
- ALTER TABLE session_summaries ADD COLUMN request TEXT NOT NULL DEFAULT '';
264
- ALTER TABLE session_summaries ADD COLUMN investigated TEXT NOT NULL DEFAULT '';
265
- ALTER TABLE session_summaries ADD COLUMN learned TEXT NOT NULL DEFAULT '';
266
- ALTER TABLE session_summaries ADD COLUMN completed TEXT NOT NULL DEFAULT '';
267
- ALTER TABLE session_summaries ADD COLUMN next_steps TEXT NOT NULL DEFAULT '';
268
- `},{version:4,name:"add-discovery-tokens",up:`
269
- ALTER TABLE observations ADD COLUMN discovery_tokens INTEGER NOT NULL DEFAULT 0;
270
- `},{version:5,name:"add-embedding-column",up:`
271
- ALTER TABLE observations ADD COLUMN embedding TEXT;
272
- `},{version:6,name:"create-embedding-meta-table",up:`
273
- CREATE TABLE IF NOT EXISTS _embedding_meta (
274
- key TEXT PRIMARY KEY,
275
- value TEXT NOT NULL
276
- );
277
- `},{version:7,name:"add-importance-column",up:`
278
- ALTER TABLE observations ADD COLUMN importance INTEGER NOT NULL DEFAULT 3;
279
- `},{version:8,name:"add-conflict-resolution-columns",up:`
280
- ALTER TABLE observations ADD COLUMN superseded_by TEXT;
281
- ALTER TABLE observations ADD COLUMN superseded_at TEXT;
282
- CREATE INDEX IF NOT EXISTS idx_observations_superseded ON observations(superseded_by);
283
-
284
- -- Clean up superseded_by when the superseding observation is deleted
285
- CREATE TRIGGER IF NOT EXISTS trg_clear_superseded_by
286
- AFTER DELETE ON observations
287
- BEGIN
288
- UPDATE observations
289
- SET superseded_by = NULL, superseded_at = NULL
290
- WHERE superseded_by = OLD.id;
366
+ CREATE TRIGGER summaries_ad AFTER DELETE ON session_summaries BEGIN
367
+ INSERT INTO summaries_fts(
368
+ summaries_fts, rowid, summary, key_decisions, concepts
369
+ )
370
+ VALUES (
371
+ 'delete', old._rowid, old.summary, old.key_decisions, old.concepts
372
+ );
291
373
  END;
292
- `},{version:9,name:"create-entity-graph-tables",up:`
293
- -- Entities table
294
- CREATE TABLE IF NOT EXISTS entities (
295
- _rowid INTEGER PRIMARY KEY AUTOINCREMENT,
296
- id TEXT UNIQUE NOT NULL,
297
- name TEXT NOT NULL,
298
- entity_type TEXT NOT NULL
299
- CHECK (entity_type IN ('technology','library','pattern','concept','file','person','project','other')),
300
- first_seen_at TEXT NOT NULL DEFAULT (datetime('now')),
301
- last_seen_at TEXT NOT NULL DEFAULT (datetime('now')),
302
- mention_count INTEGER NOT NULL DEFAULT 1,
303
- UNIQUE(name, entity_type)
304
- );
305
-
306
- CREATE INDEX IF NOT EXISTS idx_entities_name ON entities(name);
307
- CREATE INDEX IF NOT EXISTS idx_entities_type ON entities(entity_type);
308
-
309
- -- Entity relations table
310
- CREATE TABLE IF NOT EXISTS entity_relations (
311
- _rowid INTEGER PRIMARY KEY AUTOINCREMENT,
312
- id TEXT UNIQUE NOT NULL,
313
- source_entity_id TEXT NOT NULL,
314
- target_entity_id TEXT NOT NULL,
315
- relationship TEXT NOT NULL
316
- CHECK (relationship IN ('uses','depends_on','implements','extends','related_to','replaces','configures')),
317
- observation_id TEXT NOT NULL,
318
- created_at TEXT NOT NULL DEFAULT (datetime('now')),
319
- UNIQUE(source_entity_id, target_entity_id, relationship),
320
- FOREIGN KEY (source_entity_id) REFERENCES entities(id) ON DELETE CASCADE,
321
- FOREIGN KEY (target_entity_id) REFERENCES entities(id) ON DELETE CASCADE,
322
- FOREIGN KEY (observation_id) REFERENCES observations(id) ON DELETE CASCADE
323
- );
324
-
325
- CREATE INDEX IF NOT EXISTS idx_entity_relations_source ON entity_relations(source_entity_id);
326
- CREATE INDEX IF NOT EXISTS idx_entity_relations_target ON entity_relations(target_entity_id);
327
-
328
- -- Entity-Observation junction table
329
- CREATE TABLE IF NOT EXISTS entity_observations (
330
- entity_id TEXT NOT NULL,
331
- observation_id TEXT NOT NULL,
332
- PRIMARY KEY (entity_id, observation_id),
333
- FOREIGN KEY (entity_id) REFERENCES entities(id) ON DELETE CASCADE,
334
- FOREIGN KEY (observation_id) REFERENCES observations(id) ON DELETE CASCADE
335
- );
336
374
 
337
375
  -- FTS5 for entity search
338
376
  CREATE VIRTUAL TABLE IF NOT EXISTS entities_fts USING fts5(
@@ -343,7 +381,6 @@ ${V}`}return W}guide(){return["open-mem workflow:","1) Use mem-search to find ca
343
381
  tokenize='porter unicode61'
344
382
  );
345
383
 
346
- -- FTS5 sync triggers
347
384
  CREATE TRIGGER entities_ai AFTER INSERT ON entities BEGIN
348
385
  INSERT INTO entities_fts(rowid, name, entity_type)
349
386
  VALUES (new._rowid, new.name, new.entity_type);
@@ -360,33 +397,24 @@ ${V}`}return W}guide(){return["open-mem workflow:","1) Use mem-search to find ca
360
397
  INSERT INTO entities_fts(rowid, name, entity_type)
361
398
  VALUES (new._rowid, new.name, new.entity_type);
362
399
  END;
363
- `},{version:10,name:"add-v1-revision-tombstone-columns",up:`
364
- ALTER TABLE observations ADD COLUMN scope TEXT NOT NULL DEFAULT 'project'
365
- CHECK (scope IN ('project','user'));
366
- ALTER TABLE observations ADD COLUMN revision_of TEXT;
367
- ALTER TABLE observations ADD COLUMN deleted_at TEXT;
368
-
369
- CREATE INDEX IF NOT EXISTS idx_observations_scope ON observations(scope);
370
- CREATE INDEX IF NOT EXISTS idx_observations_revision_of ON observations(revision_of);
371
- CREATE INDEX IF NOT EXISTS idx_observations_deleted_at ON observations(deleted_at);
372
- `}];function A$($,J){if($.migrate(I0),J?.hasVectorExtension&&J?.embeddingDimension&&J.embeddingDimension>0)P0($,J.embeddingDimension)}function P0($,J){if($.get("SELECT name FROM sqlite_master WHERE type='table' AND name='observation_embeddings'")){let M=$.get("SELECT value FROM _embedding_meta WHERE key = 'dimension'");if(M&&Number(M.value)!==J){console.warn(`[open-mem] vec0 table exists with dimension ${M.value}, but config specifies ${J}. Drop observation_embeddings to re-create with new dimension.`);return}}else $.exec(`CREATE VIRTUAL TABLE observation_embeddings USING vec0(
400
+ `}];function bE(E,M){if(E.migrate(Y0),M?.hasVectorExtension&&M?.embeddingDimension&&M.embeddingDimension>0)U0(E,M.embeddingDimension)}function U0(E,M){if(E.get("SELECT name FROM sqlite_master WHERE type='table' AND name='observation_embeddings'")){let _=E.get("SELECT value FROM _embedding_meta WHERE key = 'dimension'");if(_&&Number(_.value)!==M){console.warn(`[open-mem] vec0 table exists with dimension ${_.value}, but config specifies ${M}. Drop observation_embeddings to re-create with new dimension.`);return}}else E.exec(`CREATE VIRTUAL TABLE observation_embeddings USING vec0(
373
401
  observation_id TEXT PRIMARY KEY,
374
- embedding float[${J}] distance_metric=cosine
375
- )`);$.run("INSERT OR REPLACE INTO _embedding_meta (key, value) VALUES (?, ?)",["dimension",String(J)])}class c{db;constructor($){this.db=$}create($,J){let S=new Date().toISOString();return this.db.run(`INSERT INTO sessions (id, project_path, started_at, status)
376
- VALUES (?, ?, ?, 'active')`,[$,J,S]),this.getById($)}getOrCreate($,J){let S=this.getById($);if(S)return S;return this.create($,J)}getById($){let J=this.db.get("SELECT * FROM sessions WHERE id = ?",[$]);return J?this.mapRow(J):null}getRecent($,J=10){return this.db.all("SELECT * FROM sessions WHERE project_path = ? ORDER BY started_at DESC LIMIT ?",[$,J]).map((S)=>this.mapRow(S))}getAll($){return this.db.all("SELECT * FROM sessions WHERE project_path = ? ORDER BY started_at DESC",[$]).map((J)=>this.mapRow(J))}getActive(){return this.db.all("SELECT * FROM sessions WHERE status = 'active' ORDER BY started_at DESC").map(($)=>this.mapRow($))}updateStatus($,J){this.db.run("UPDATE sessions SET status = ? WHERE id = ?",[J,$])}markCompleted($){this.db.run("UPDATE sessions SET status = 'completed', ended_at = datetime('now') WHERE id = ?",[$])}incrementObservationCount($){this.db.run("UPDATE sessions SET observation_count = observation_count + 1 WHERE id = ?",[$])}setSummary($,J){this.db.run("UPDATE sessions SET summary_id = ? WHERE id = ?",[J,$])}mapRow($){return{id:$.id,projectPath:$.project_path,startedAt:$.started_at,endedAt:$.ended_at??null,status:$.status,observationCount:$.observation_count,summaryId:$.summary_id??null}}}import{randomUUID as q0}from"crypto";class g{db;constructor($){this.db=$}create($){let J=q0(),S=new Date().toISOString();return this.db.run(`INSERT INTO session_summaries
402
+ embedding float[${M}] distance_metric=cosine
403
+ )`);E.run("INSERT OR REPLACE INTO _embedding_meta (key, value) VALUES (?, ?)",["dimension",String(M)])}class JE{db;constructor(E){this.db=E}create(E,M){let N=new Date().toISOString();return this.db.run(`INSERT INTO sessions (id, project_path, started_at, status)
404
+ VALUES (?, ?, ?, 'active')`,[E,M,N]),this.getById(E)}getOrCreate(E,M){let N=this.getById(E);if(N)return N;return this.create(E,M)}getById(E){let M=this.db.get("SELECT * FROM sessions WHERE id = ?",[E]);return M?this.mapRow(M):null}getRecent(E,M=10){return this.db.all("SELECT * FROM sessions WHERE project_path = ? ORDER BY started_at DESC LIMIT ?",[E,M]).map((N)=>this.mapRow(N))}getAll(E){return this.db.all("SELECT * FROM sessions WHERE project_path = ? ORDER BY started_at DESC",[E]).map((M)=>this.mapRow(M))}getActive(){return this.db.all("SELECT * FROM sessions WHERE status = 'active' ORDER BY started_at DESC").map((E)=>this.mapRow(E))}updateStatus(E,M){this.db.run("UPDATE sessions SET status = ? WHERE id = ?",[M,E])}markCompleted(E){this.db.run("UPDATE sessions SET status = 'completed', ended_at = datetime('now') WHERE id = ?",[E])}incrementObservationCount(E){this.db.run("UPDATE sessions SET observation_count = observation_count + 1 WHERE id = ?",[E])}setSummary(E,M){this.db.run("UPDATE sessions SET summary_id = ? WHERE id = ?",[M,E])}mapRow(E){return{id:E.id,projectPath:E.project_path,startedAt:E.started_at,endedAt:E.ended_at??null,status:E.status,observationCount:E.observation_count,summaryId:E.summary_id??null}}}import{randomUUID as B0}from"crypto";class SE{db;constructor(E){this.db=E}create(E){let M=B0(),N=new Date().toISOString();return this.db.run(`INSERT INTO session_summaries
377
405
  (id, session_id, summary, key_decisions, files_modified,
378
406
  concepts, created_at, token_count,
379
407
  request, investigated, learned, completed, next_steps)
380
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,[J,$.sessionId,$.summary,JSON.stringify($.keyDecisions),JSON.stringify($.filesModified),JSON.stringify($.concepts),S,$.tokenCount,$.request??"",$.investigated??"",$.learned??"",$.completed??"",$.nextSteps??""]),{...$,id:J,createdAt:S}}importSummary($){this.db.run(`INSERT INTO session_summaries
408
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,[M,E.sessionId,E.summary,JSON.stringify(E.keyDecisions),JSON.stringify(E.filesModified),JSON.stringify(E.concepts),N,E.tokenCount,E.request??"",E.investigated??"",E.learned??"",E.completed??"",E.nextSteps??""]),{...E,id:M,createdAt:N}}importSummary(E){this.db.run(`INSERT INTO session_summaries
381
409
  (id, session_id, summary, key_decisions, files_modified,
382
410
  concepts, created_at, token_count,
383
411
  request, investigated, learned, completed, next_steps)
384
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,[$.id,$.sessionId,$.summary,JSON.stringify($.keyDecisions),JSON.stringify($.filesModified),JSON.stringify($.concepts),$.createdAt,$.tokenCount,$.request??"",$.investigated??"",$.learned??"",$.completed??"",$.nextSteps??""])}getBySessionId($){let J=this.db.get("SELECT * FROM session_summaries WHERE session_id = ?",[$]);return J?this.mapRow(J):null}getRecent($=10){return this.db.all("SELECT * FROM session_summaries ORDER BY created_at DESC LIMIT ?",[$]).map((J)=>this.mapRow(J))}search($,J=10){return this.db.all(`SELECT ss.*
412
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,[E.id,E.sessionId,E.summary,JSON.stringify(E.keyDecisions),JSON.stringify(E.filesModified),JSON.stringify(E.concepts),E.createdAt,E.tokenCount,E.request??"",E.investigated??"",E.learned??"",E.completed??"",E.nextSteps??""])}getBySessionId(E){let M=this.db.get("SELECT * FROM session_summaries WHERE session_id = ?",[E]);return M?this.mapRow(M):null}getRecent(E=10){return this.db.all("SELECT * FROM session_summaries ORDER BY created_at DESC LIMIT ?",[E]).map((M)=>this.mapRow(M))}search(E,M=10){return this.db.all(`SELECT ss.*
385
413
  FROM session_summaries ss
386
414
  JOIN summaries_fts fts ON ss._rowid = fts.rowid
387
415
  WHERE summaries_fts MATCH ?
388
416
  ORDER BY rank
389
- LIMIT ?`,[$,J]).map((S)=>this.mapRow(S))}mapRow($){return{id:$.id,sessionId:$.session_id,summary:$.summary,keyDecisions:JSON.parse($.key_decisions),filesModified:JSON.parse($.files_modified),concepts:JSON.parse($.concepts),createdAt:$.created_at,tokenCount:$.token_count,request:$.request||void 0,investigated:$.investigated||void 0,learned:$.learned||void 0,completed:$.completed||void 0,nextSteps:$.next_steps||void 0}}}import{randomUUID as p0}from"crypto";var m0=[{version:1,name:"create-user-observations",up:`
417
+ LIMIT ?`,[E,M]).map((N)=>this.mapRow(N))}mapRow(E){return{id:E.id,sessionId:E.session_id,summary:E.summary,keyDecisions:JSON.parse(E.key_decisions),filesModified:JSON.parse(E.files_modified),concepts:JSON.parse(E.concepts),createdAt:E.created_at,tokenCount:E.token_count,request:E.request||void 0,investigated:E.investigated||void 0,learned:E.learned||void 0,completed:E.completed||void 0,nextSteps:E.next_steps||void 0}}}import{randomUUID as F0}from"crypto";var G0=[{version:1,name:"create-user-observations",up:`
390
418
  CREATE TABLE IF NOT EXISTS user_observations (
391
419
  _rowid INTEGER PRIMARY KEY AUTOINCREMENT,
392
420
  id TEXT UNIQUE NOT NULL,
@@ -457,21 +485,21 @@ ${V}`}return W}guide(){return["open-mem workflow:","1) Use mem-search to find ca
457
485
  new.facts, new.concepts, new.files_read, new.files_modified
458
486
  );
459
487
  END;
460
- `}];class n{db;constructor($){let J=u0($);this.db=O(J),this.initializeUserSchema()}initializeUserSchema(){this.db.migrate(m0)}get database(){return this.db}close(){this.db.close()}}class b{db;constructor($){this.db=$}create($){let J=p0(),S=new Date().toISOString();return this.db.run(`INSERT INTO user_observations
488
+ `}];class VE{db;constructor(E){let M=D0(E);this.db=w(M),this.initializeUserSchema()}initializeUserSchema(){this.db.migrate(G0)}get database(){return this.db}close(){this.db.close()}}class CE{db;constructor(E){this.db=E}create(E){let M=F0(),N=new Date().toISOString();return this.db.run(`INSERT INTO user_observations
461
489
  (id, type, title, subtitle, facts, narrative,
462
490
  concepts, files_read, files_modified, tool_name,
463
491
  created_at, token_count, importance, source_project)
464
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,[J,$.type,$.title,$.subtitle,JSON.stringify($.facts),$.narrative,JSON.stringify($.concepts),JSON.stringify($.filesRead),JSON.stringify($.filesModified),$.toolName,S,$.tokenCount,$.importance??3,$.sourceProject]),{...$,id:J,createdAt:S,importance:$.importance??3}}search($){try{let J=`
492
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,[M,E.type,E.title,E.subtitle,JSON.stringify(E.facts),E.narrative,JSON.stringify(E.concepts),JSON.stringify(E.filesRead),JSON.stringify(E.filesModified),E.toolName,N,E.tokenCount,E.importance??3,E.sourceProject]),{...E,id:M,createdAt:N,importance:E.importance??3}}search(E){try{let M=`
465
493
  SELECT o.*, rank
466
494
  FROM user_observations o
467
495
  JOIN user_observations_fts fts ON o._rowid = fts.rowid
468
496
  WHERE user_observations_fts MATCH ?
469
- `,S=[$.query];if($.sourceProject)J+=" AND o.source_project = ?",S.push($.sourceProject);return J+=" ORDER BY rank LIMIT ?",S.push($.limit??10),this.db.all(J,S).map((M)=>({observation:this.mapRow(M),rank:M.rank}))}catch{return[]}}getIndex($,J){let S=`SELECT id, type, title, token_count, created_at, importance, source_project
470
- FROM user_observations`,M=[];if(J)S+=" WHERE source_project = ?",M.push(J);return S+=" ORDER BY created_at DESC LIMIT ?",M.push($??20),this.db.all(S,M).map((Q)=>({id:Q.id,sessionId:"",type:Q.type,title:Q.title,tokenCount:Q.token_count,discoveryTokens:0,createdAt:Q.created_at,importance:Q.importance??3}))}getById($){let J=this.db.get("SELECT * FROM user_observations WHERE id = ?",[$]);return J?this.mapRow(J):null}delete($){return this.db.all("DELETE FROM user_observations WHERE id = ? RETURNING id",[$]).length>0}mapRow($){return{id:$.id,type:$.type,title:$.title,subtitle:$.subtitle,facts:JSON.parse($.facts),narrative:$.narrative,concepts:JSON.parse($.concepts),filesRead:JSON.parse($.files_read),filesModified:JSON.parse($.files_modified),toolName:$.tool_name,createdAt:$.created_at,tokenCount:$.token_count,importance:$.importance??3,sourceProject:$.source_project}}}function u0($){if($.startsWith("~/")){let J=process.env.HOME||process.env.USERPROFILE||"";if(!J)throw Error("Cannot resolve user DB path: HOME environment variable is not set");let S=`${J}${$.slice(1)}`,M=S.substring(0,S.lastIndexOf("/"));return G("fs").mkdirSync(M,{recursive:!0}),S}return $}function L($,J){if(J.type&&$.type!==J.type)return!1;if(J.importanceMin!==void 0&&$.importance<J.importanceMin)return!1;if(J.importanceMax!==void 0&&$.importance>J.importanceMax)return!1;if(J.createdAfter&&$.createdAt<J.createdAfter)return!1;if(J.createdBefore&&$.createdAt>J.createdBefore)return!1;if(J.concepts&&J.concepts.length>0){if(!J.concepts.some((M)=>$.concepts.some((Q)=>Q.toLowerCase().includes(M.toLowerCase()))))return!1}if(J.files&&J.files.length>0){let S=[...$.filesRead,...$.filesModified];if(!J.files.some((Q)=>S.some((Z)=>Z.toLowerCase().includes(Q.toLowerCase()))))return!1}return!0}async function E$($,J,S,M,Q){if(!$.trim())return J;let Z=w0($),X=new Set;for(let W of Z){let V=S.findByName(W);for(let H of V){let _=S.traverseRelations(H.id,1);for(let t of _){let j=S.getObservationsForEntity(t);for(let v of j)X.add(v)}}}if(X.size===0)return J;let U=new Set(J.map((W)=>W.observation.id)),K=[];for(let W of X){if(U.has(W))continue;let V=M.getById(W);if(!V)continue;if(V.supersededBy)continue;K.push({observation:V,rank:0,snippet:V.title,source:"project"})}return[...J,...K].slice(0,Q)}function w0($){let J=$.split(/\s+/).filter((M)=>M.length>=2),S=[];for(let M of J)S.push(M);for(let M=0;M<J.length-1;M++)S.push(`${J[M]} ${J[M+1]}`);return S}var h$=60;async function j$($,J,S,M){let Q=M.limit??10,Z=c0(J,$,M,Q);if(!S)return Z;let X=await x(S,$);if(!X)return Z;let U=Z.map((W)=>W.observation.id),K=g0(J,X,M.projectPath,M,Q,M.hasVectorExtension??!1,U);if(K.length===0)return Z;return l0(Z,K,Q)}function c0($,J,S,M){try{return $.search({query:J,type:S.type,limit:M,projectPath:S.projectPath,importanceMin:S.importanceMin,importanceMax:S.importanceMax,createdAfter:S.createdAfter,createdBefore:S.createdBefore,concepts:S.concepts,files:S.files})}catch{return[]}}function g0($,J,S,M,Q,Z,X){if(Z)return n0($,J,M,Q,X);return b0($,J,S,M,Q)}function n0($,J,S,M,Q){try{let Z;if(Q.length>0){if(Z=$.searchVecSubset(J,Q,M*3),Z.length===0)Z=$.getVecEmbeddingMatches(J,M*3)}else Z=$.getVecEmbeddingMatches(J,M*3);if(Z.length===0)return[];let X=[];for(let{observationId:U,distance:K}of Z){if(X.length>=M)break;let W=$.getById(U);if(!W)continue;if(!L(W,S))continue;X.push({observation:W,rank:K-1,snippet:W.title})}return X}catch{return[]}}function b0($,J,S,M,Q){let Z=$.getWithEmbeddings(S,Q*10);if(Z.length===0)return[];let X=Z.map((K)=>({id:K.id,similarity:B(J,K.embedding)})).filter(({similarity:K})=>K>=0.3).sort((K,W)=>W.similarity-K.similarity),U=[];for(let{id:K,similarity:W}of X){if(U.length>=Q)break;let V=$.getById(K);if(!V)continue;if(!L(V,M))continue;U.push({observation:V,rank:-W,snippet:V.title})}return U}function l0($,J,S){let M=new Map;for(let Q=0;Q<$.length;Q++){let Z=$[Q],X=1/(h$+Q+1);M.set(Z.observation.id,{score:X,result:Z})}for(let Q=0;Q<J.length;Q++){let Z=J[Q],X=1/(h$+Q+1),U=M.get(Z.observation.id);if(U)U.score+=X;else M.set(Z.observation.id,{score:X,result:Z})}return[...M.values()].sort((Q,Z)=>Z.score-Q.score).slice(0,S).map(({result:Q})=>Q)}class l{observations;embeddingModel;hasVectorExtension;reranker;userObservationRepo;entityRepo;constructor($,J,S,M=null,Q=null,Z=null){this.observations=$;this.embeddingModel=J;this.hasVectorExtension=S;this.reranker=M;this.userObservationRepo=Q;this.entityRepo=Z}async search($,J){let S=J.strategy??"hybrid",M=J.limit??10,Q;switch(S){case"filter-only":Q=this.filterOnlySearch($,J,M);break;case"semantic":Q=await this.semanticSearch($,J,M);break;case"hybrid":Q=await this.hybridSearchStrategy($,J,M);break}for(let Z of Q)Z.source="project";if(this.entityRepo&&$.trim())Q=await E$($,Q,this.entityRepo,this.observations,M);if(this.userObservationRepo){let Z=this.searchUserMemory($,J,M);Q=this.mergeResults(Q,Z,M)}if(this.reranker&&Q.length>1)return this.reranker.rerank($,Q,M);return Q}filterOnlySearch($,J,S){if(J.concept)return this.observations.searchByConcept(J.concept,S,J.projectPath).map((Q)=>({observation:Q,rank:0,snippet:Q.title}));if(J.file)return this.observations.searchByFile(J.file,S,J.projectPath).map((Q)=>({observation:Q,rank:0,snippet:Q.title}));return this.observations.search({query:$,type:J.type,limit:S,projectPath:J.projectPath,importanceMin:J.importanceMin,importanceMax:J.importanceMax,createdAfter:J.createdAfter,createdBefore:J.createdBefore,concepts:J.concepts,files:J.files})}async semanticSearch($,J,S){if(!this.embeddingModel)return this.filterOnlySearch($,J,S);let M=await x(this.embeddingModel,$);if(!M)return this.filterOnlySearch($,J,S);if(this.hasVectorExtension)return this.nativeVectorSearch(M,J,S);return this.jsFallbackVectorSearch(M,J,S)}async hybridSearchStrategy($,J,S){return j$($,this.observations,this.embeddingModel,{type:J.type,limit:S,projectPath:J.projectPath,hasVectorExtension:this.hasVectorExtension,importanceMin:J.importanceMin,importanceMax:J.importanceMax,createdAfter:J.createdAfter,createdBefore:J.createdBefore,concepts:J.concepts,files:J.files})}nativeVectorSearch($,J,S){try{let M=this.observations.getVecEmbeddingMatches($,S*3);if(M.length===0)return[];let Q=[];for(let{observationId:Z,distance:X}of M){if(Q.length>=S)break;let U=this.observations.getById(Z);if(!U)continue;if(!L(U,J))continue;Q.push({observation:U,rank:X-1,snippet:U.title})}return Q}catch{return[]}}jsFallbackVectorSearch($,J,S){let M=this.observations.getWithEmbeddings(J.projectPath,S*10);if(M.length===0)return[];let Q=M.map((X)=>({id:X.id,similarity:B($,X.embedding)})).filter(({similarity:X})=>X>=0.3).sort((X,U)=>U.similarity-X.similarity),Z=[];for(let{id:X,similarity:U}of Q){if(Z.length>=S)break;let K=this.observations.getById(X);if(!K)continue;if(!L(K,J))continue;Z.push({observation:K,rank:-U,snippet:K.title})}return Z}searchUserMemory($,J,S){if(!this.userObservationRepo)return[];try{return this.userObservationRepo.search({query:$,limit:S}).map(({observation:Q,rank:Z})=>({observation:d0(Q),rank:Z,snippet:Q.title,source:"user"}))}catch{return[]}}mergeResults($,J,S){let M=new Set($.map((X)=>X.observation.id)),Q=new Set($.map((X)=>`${X.observation.title}::${X.observation.narrative}`)),Z=J.filter((X)=>{if(M.has(X.observation.id))return!1;let U=`${X.observation.title}::${X.observation.narrative}`;if(Q.has(U))return!1;return Q.add(U),!0});return[...$,...Z].slice(0,S)}}function d0($){return{id:$.id,sessionId:"",type:$.type,title:$.title,subtitle:$.subtitle,facts:$.facts,narrative:$.narrative,concepts:$.concepts,filesRead:$.filesRead,filesModified:$.filesModified,rawToolOutput:"",toolName:$.toolName,createdAt:$.createdAt,tokenCount:$.tokenCount,discoveryTokens:0,importance:$.importance}}import{generateText as r0}from"ai";function D$($,J){let S=J.map((M,Q)=>` <candidate index="${Q}"><title>${M.title}</title><narrative>${M.narrative}</narrative></candidate>`).join(`
497
+ `,N=[E.query];if(E.sourceProject)M+=" AND o.source_project = ?",N.push(E.sourceProject);return M+=" ORDER BY rank LIMIT ?",N.push(E.limit??10),this.db.all(M,N).map((_)=>({observation:this.mapRow(_),rank:_.rank}))}catch{return[]}}getIndex(E,M){let N=`SELECT id, type, title, token_count, created_at, importance, source_project
498
+ FROM user_observations`,_=[];if(M)N+=" WHERE source_project = ?",_.push(M);return N+=" ORDER BY created_at DESC LIMIT ?",_.push(E??20),this.db.all(N,_).map((O)=>({id:O.id,sessionId:"",type:O.type,title:O.title,tokenCount:O.token_count,discoveryTokens:0,createdAt:O.created_at,importance:O.importance??3}))}getById(E){let M=this.db.get("SELECT * FROM user_observations WHERE id = ?",[E]);return M?this.mapRow(M):null}delete(E){return this.db.all("DELETE FROM user_observations WHERE id = ? RETURNING id",[E]).length>0}mapRow(E){return{id:E.id,type:E.type,title:E.title,subtitle:E.subtitle,facts:JSON.parse(E.facts),narrative:E.narrative,concepts:JSON.parse(E.concepts),filesRead:JSON.parse(E.files_read),filesModified:JSON.parse(E.files_modified),toolName:E.tool_name,createdAt:E.created_at,tokenCount:E.token_count,importance:E.importance??3,sourceProject:E.source_project}}}function D0(E){if(E.startsWith("~/")){let M=process.env.HOME||process.env.USERPROFILE||"";if(!M)throw Error("Cannot resolve user DB path: HOME environment variable is not set");let N=`${M}${E.slice(1)}`,_=N.substring(0,N.lastIndexOf("/"));return U("fs").mkdirSync(_,{recursive:!0}),N}return E}function k(E,M){if(M.type&&E.type!==M.type)return!1;if(M.importanceMin!==void 0&&E.importance<M.importanceMin)return!1;if(M.importanceMax!==void 0&&E.importance>M.importanceMax)return!1;if(M.createdAfter&&E.createdAt<M.createdAfter)return!1;if(M.createdBefore&&E.createdAt>M.createdBefore)return!1;if(M.concepts&&M.concepts.length>0){if(!M.concepts.some((_)=>E.concepts.some((O)=>O.toLowerCase().includes(_.toLowerCase()))))return!1}if(M.files&&M.files.length>0){let N=[...E.filesRead,...E.filesModified];if(!M.files.some((O)=>N.some((J)=>J.toLowerCase().includes(O.toLowerCase()))))return!1}return!0}async function nE(E,M,N,_,O){if(!E.trim())return M;let J=y0(E),S=new Set;for(let A of J){let $=N.findByName(A);for(let H of $){let Y=N.traverseRelations(H.id,1);for(let B of Y){let D=N.getObservationsForEntity(B);for(let b of D)S.add(b)}}}if(S.size===0)return M;let V=new Set(M.map((A)=>A.observation.id)),C=[];for(let A of S){if(V.has(A))continue;let $=_.getById(A);if(!$)continue;if($.supersededBy)continue;C.push({observation:$,rank:0,snippet:$.title,source:"project",rankingSource:"graph",explain:{strategy:"hybrid",matchedBy:["graph"]}})}return[...M,...C].slice(0,O)}function y0(E){let M=E.split(/\s+/).filter((_)=>_.length>=2),N=[];for(let _ of M)N.push(_);for(let _=0;_<M.length-1;_++)N.push(`${M[_]} ${M[_+1]}`);return N}var dE=60;async function iE(E,M,N,_){let O=_.limit??10,J=j0(M,E,_,O);if(!N)return J;let S=await l(N,E);if(!S)return J;let V=J.map((A)=>A.observation.id),C=k0(M,S,_.projectPath,_,O,_.hasVectorExtension??!1,V);if(C.length===0)return J;return m0(J,C,O)}function j0(E,M,N,_){try{return E.search({query:M,type:N.type,limit:_,projectPath:N.projectPath,importanceMin:N.importanceMin,importanceMax:N.importanceMax,createdAfter:N.createdAfter,createdBefore:N.createdBefore,concepts:N.concepts,files:N.files})}catch{return[]}}function k0(E,M,N,_,O,J,S){if(J)return f0(E,M,_,O,S);return P0(E,M,N,_,O)}function f0(E,M,N,_,O){try{let J;if(O.length>0){if(J=E.searchVecSubset(M,O,_*3),J.length===0)J=E.getVecEmbeddingMatches(M,_*3)}else J=E.getVecEmbeddingMatches(M,_*3);if(J.length===0)return[];let S=[];for(let{observationId:V,distance:C}of J){if(S.length>=_)break;let A=E.getById(V);if(!A)continue;if(!k(A,N))continue;S.push({observation:A,rank:C-1,snippet:A.title,rankingSource:"vector",explain:{strategy:"hybrid",matchedBy:["vector"],vectorDistance:C}})}return S}catch{return[]}}function P0(E,M,N,_,O){let J=E.getWithEmbeddings(N,O*10);if(J.length===0)return[];let S=J.map((C)=>({id:C.id,similarity:j(M,C.embedding)})).filter(({similarity:C})=>C>=0.3).sort((C,A)=>A.similarity-C.similarity),V=[];for(let{id:C,similarity:A}of S){if(V.length>=O)break;let $=E.getById(C);if(!$)continue;if(!k($,_))continue;V.push({observation:$,rank:-A,snippet:$.title,rankingSource:"vector",explain:{strategy:"hybrid",matchedBy:["vector"],vectorSimilarity:A}})}return V}function m0(E,M,N){let _=new Map;for(let O=0;O<E.length;O++){let J=E[O],S=1/(dE+O+1);_.set(J.observation.id,{score:S,result:{...J,rankingSource:"fts",explain:{strategy:"hybrid",matchedBy:["fts"],ftsRank:J.rank}}})}for(let O=0;O<M.length;O++){let J=M[O],S=1/(dE+O+1),V=_.get(J.observation.id);if(V)V.score+=S,V.result={...V.result,explain:{strategy:"hybrid",matchedBy:["fts","vector"],ftsRank:V.result.explain?.ftsRank??V.result.rank,vectorDistance:J.explain?.vectorDistance,vectorSimilarity:J.explain?.vectorSimilarity}};else _.set(J.observation.id,{score:S,result:{...J,explain:{strategy:"hybrid",matchedBy:["vector"],vectorDistance:J.explain?.vectorDistance,vectorSimilarity:J.explain?.vectorSimilarity}}})}return[..._.values()].sort((O,J)=>J.score-O.score).slice(0,N).map(({score:O,result:J})=>({...J,explain:{...J.explain??{strategy:"hybrid",matchedBy:[]},strategy:"hybrid",matchedBy:J.explain?.matchedBy??[],rrfScore:O,ftsRank:J.explain?.ftsRank,vectorDistance:J.explain?.vectorDistance,vectorSimilarity:J.explain?.vectorSimilarity}}))}class AE{observations;embeddingModel;hasVectorExtension;reranker;userObservationRepo;entityRepo;constructor(E,M,N,_=null,O=null,J=null){this.observations=E;this.embeddingModel=M;this.hasVectorExtension=N;this.reranker=_;this.userObservationRepo=O;this.entityRepo=J}async search(E,M){let N=M.strategy??"hybrid",_=M.limit??10,O;switch(N){case"filter-only":O=this.filterOnlySearch(E,M,_);break;case"semantic":O=await this.semanticSearch(E,M,_);break;case"hybrid":O=await this.hybridSearchStrategy(E,M,_);break}for(let J of O)J.source="project";if(this.entityRepo&&E.trim())O=await nE(E,O,this.entityRepo,this.observations,_);if(this.userObservationRepo){let J=this.searchUserMemory(E,M,_);O=this.mergeResults(O,J,_)}if(this.reranker&&O.length>1)return this.reranker.rerank(E,O,_);return O}filterOnlySearch(E,M,N){if(M.concept)return this.observations.searchByConcept(M.concept,N,M.projectPath).map((O)=>({observation:O,rank:0,snippet:O.title,rankingSource:"graph",explain:{strategy:"filter-only",matchedBy:["concept-filter"]}}));if(M.file)return this.observations.searchByFile(M.file,N,M.projectPath).map((O)=>({observation:O,rank:0,snippet:O.title,rankingSource:"graph",explain:{strategy:"filter-only",matchedBy:["file-filter"]}}));return this.observations.search({query:E,type:M.type,limit:N,projectPath:M.projectPath,importanceMin:M.importanceMin,importanceMax:M.importanceMax,createdAfter:M.createdAfter,createdBefore:M.createdBefore,concepts:M.concepts,files:M.files})}async semanticSearch(E,M,N){if(!this.embeddingModel)return this.filterOnlySearch(E,M,N);let _=await l(this.embeddingModel,E);if(!_)return this.filterOnlySearch(E,M,N);if(this.hasVectorExtension)return this.nativeVectorSearch(_,M,N);return this.jsFallbackVectorSearch(_,M,N)}async hybridSearchStrategy(E,M,N){return iE(E,this.observations,this.embeddingModel,{type:M.type,limit:N,projectPath:M.projectPath,hasVectorExtension:this.hasVectorExtension,importanceMin:M.importanceMin,importanceMax:M.importanceMax,createdAfter:M.createdAfter,createdBefore:M.createdBefore,concepts:M.concepts,files:M.files})}nativeVectorSearch(E,M,N){try{let _=this.observations.getVecEmbeddingMatches(E,N*3);if(_.length===0)return[];let O=[];for(let{observationId:J,distance:S}of _){if(O.length>=N)break;let V=this.observations.getById(J);if(!V)continue;if(!k(V,M))continue;O.push({observation:V,rank:S-1,snippet:V.title,rankingSource:"vector",explain:{strategy:"semantic",matchedBy:["vector"],vectorDistance:S}})}return O}catch{return[]}}jsFallbackVectorSearch(E,M,N){let _=this.observations.getWithEmbeddings(M.projectPath,N*10);if(_.length===0)return[];let O=_.map((S)=>({id:S.id,similarity:j(E,S.embedding)})).filter(({similarity:S})=>S>=0.3).sort((S,V)=>V.similarity-S.similarity),J=[];for(let{id:S,similarity:V}of O){if(J.length>=N)break;let C=this.observations.getById(S);if(!C)continue;if(!k(C,M))continue;J.push({observation:C,rank:-V,snippet:C.title,rankingSource:"vector",explain:{strategy:"semantic",matchedBy:["vector"],vectorSimilarity:V}})}return J}searchUserMemory(E,M,N){if(!this.userObservationRepo)return[];try{return this.userObservationRepo.search({query:E,limit:N}).map(({observation:O,rank:J})=>({observation:T0(O),rank:J,snippet:O.title,source:"user",rankingSource:"user-memory",explain:{strategy:"filter-only",matchedBy:["user-memory"]}}))}catch{return[]}}mergeResults(E,M,N){let _=new Set(E.map((S)=>S.observation.id)),O=new Set(E.map((S)=>`${S.observation.title}::${S.observation.narrative}`)),J=M.filter((S)=>{if(_.has(S.observation.id))return!1;let V=`${S.observation.title}::${S.observation.narrative}`;if(O.has(V))return!1;return O.add(V),!0});return[...E,...J].slice(0,N)}}function T0(E){return{id:E.id,sessionId:"",type:E.type,title:E.title,subtitle:E.subtitle,facts:E.facts,narrative:E.narrative,concepts:E.concepts,filesRead:E.filesRead,filesModified:E.filesModified,rawToolOutput:"",toolName:E.toolName,createdAt:E.createdAt,tokenCount:E.tokenCount,discoveryTokens:0,importance:E.importance}}import{generateText as v0}from"ai";function rE(E,M){let N=M.map((_,O)=>` <candidate index="${O}"><title>${_.title}</title><narrative>${_.narrative}</narrative></candidate>`).join(`
471
499
  `);return`<rerank_request>
472
- <query>${$}</query>
500
+ <query>${E}</query>
473
501
  <candidates>
474
- ${S}
502
+ ${N}
475
503
  </candidates>
476
504
  <instructions>Reorder the candidates by relevance to the query. Return indices from most to least relevant.
477
505
 
@@ -482,32 +510,4 @@ Respond with EXACTLY this XML format:
482
510
  <index>0</index>
483
511
  </reranked>
484
512
  </instructions>
485
- </rerank_request>`}var i0={"gemini-2.5-flash-lite":10,"gemini-2.5-flash":10,"gemini-2.5-pro":5,"gemini-2.0-flash":15,"gemini-2.0-flash-lite":30,"gemini-3-flash":5},R$=0;async function f$($,J){if(!J)return;let S=i0[$]||5,M=Math.ceil(60000/S)+100,Z=Date.now()-R$;if(Z<M){let X=M-Z;await new Promise((U)=>setTimeout(U,X))}R$=Date.now()}class C${languageModel;maxCandidates;provider;modelName;rateLimitingEnabled;_generate=r0;constructor($,J){this.languageModel=$,this.maxCandidates=J.rerankingMaxCandidates,this.provider=J.provider??"",this.modelName=J.model??"",this.rateLimitingEnabled=J.rateLimitingEnabled??!0}async rerank($,J,S){if(J.length<=1)return J;let M=J.slice(0,this.maxCandidates),Q=J.slice(this.maxCandidates),Z=D$($,M.map((U)=>({title:U.observation.title,narrative:U.observation.narrative}))),X=2;for(let U=0;U<=X;U++)try{if(this.provider==="google")await f$(this.modelName,this.rateLimitingEnabled);let{text:K}=await this._generate({model:this.languageModel,maxOutputTokens:512,prompt:Z}),W=a(K);if(!W)return J.slice(0,S);let V=this.applyReranking(M,W,S);for(let H of Q){if(V.length>=S)break;V.push(H)}return V}catch(K){if(t0(K)&&U<X){await e0(2**U*1000);continue}return J.slice(0,S)}return J.slice(0,S)}applyReranking($,J,S){let M=[],Q=new Set;for(let Z of J)if(Z>=0&&Z<$.length&&!Q.has(Z)){if(Q.add(Z),M.push($[Z]),M.length>=S)break}if(M.length<S){for(let Z=0;Z<$.length&&M.length<S;Z++)if(!Q.has(Z))M.push($[Z])}return M}}class O${async rerank($,J,S){if(J.length<=1)return J.slice(0,S);let M=d($),Q=J.map((Z)=>({result:Z,score:this.scoreCandidate(Z,M)}));return Q.sort((Z,X)=>X.score-Z.score),Q.slice(0,S).map((Z)=>Z.result)}scoreCandidate($,J){let S=$.observation,M=d(S.title),Q=d(S.narrative),Z=new Set(S.concepts.map((A)=>A.toLowerCase())),X=0,U=0,K=0;for(let A of J){if(M.has(A))X++;if(Q.has(A))U++;if(Z.has(A))K++}let W=J.size||1,V=X/W*0.4,H=U/W*0.3,_=K/W*0.15,j=(Date.now()-new Date(S.createdAt).getTime())/86400000,v=j<1?0.1:j<7?0.05:0,n$=S.importance/5*0.05;return V+H+_+v+n$}}function x$($,J){if(!$.rerankingEnabled)return null;if(J)return new C$(J,$);return new O$}function d($){return new Set($.toLowerCase().split(/[\s\-_./\\,;:!?()[\]{}'"]+/).filter((J)=>J.length>1))}function t0($){if(typeof $!=="object"||$===null)return!1;let J=$,S=J.status;if(S===429||S===500||S===503)return!0;let M=J.error;if(typeof M==="object"&&M!==null&&M.type==="overloaded_error")return!0;return!1}function e0($){return new Promise((J)=>setTimeout(J,$))}import{createInterface as o0}from"readline";var k$=new Set(["decision","bugfix","feature","refactor","discovery","change"]);function s0($){if(typeof $!=="object"||$===null)return!1;let J=$;return J.jsonrpc==="2.0"&&typeof J.method==="string"}function i($){return typeof $==="string"&&k$.has($)?$:void 0}function k($){return Array.isArray($)?$.filter((J)=>typeof J==="string"):[]}class T{memoryEngine;version;pendingOps=[];constructor($){this.memoryEngine=$.memoryEngine,this.version=$.version}start(){let $=o0({input:process.stdin,terminal:!1});$.on("line",(J)=>{let S=J.trim();if(!S)return;try{let M=JSON.parse(S);if(s0(M))this.handleMessage(M);else this.sendResponse({jsonrpc:"2.0",id:null,error:{code:-32600,message:"Invalid Request"}})}catch{this.sendResponse({jsonrpc:"2.0",id:null,error:{code:-32700,message:"Parse error"}})}}),$.on("close",()=>{Promise.allSettled(this.pendingOps).then(()=>{process.exit(0)})})}handleMessage($){if($.id===void 0||$.id===null)return;let J=$.id;switch($.method){case"initialize":this.sendResponse({jsonrpc:"2.0",id:J,result:{protocolVersion:"2024-11-05",capabilities:{tools:{}},serverInfo:{name:"open-mem",version:this.version}}});return;case"tools/list":this.sendResponse({jsonrpc:"2.0",id:J,result:{tools:this.getToolDefinitions()}});return;case"tools/call":{let S=this.handleToolsCall(J,$.params);this.pendingOps.push(S),S.finally(()=>{let M=this.pendingOps.indexOf(S);if(M>=0)this.pendingOps.splice(M,1)});return}case"ping":this.sendResponse({jsonrpc:"2.0",id:J,result:{}});return;default:this.sendResponse({jsonrpc:"2.0",id:J,error:{code:-32601,message:`Method not found: ${$.method}`}})}}async handleToolsCall($,J){let S=typeof J?.name==="string"?J.name:void 0,M=J?.arguments&&typeof J.arguments==="object"&&!Array.isArray(J.arguments)?J.arguments:{};if(!S){this.sendResponse({jsonrpc:"2.0",id:$,error:{code:-32602,message:"Missing tool name"}});return}try{let Q=await this.executeTool(S,M);this.sendResponse({jsonrpc:"2.0",id:$,result:Q})}catch(Q){let Z=Q instanceof Error?Q.message:String(Q);this.sendResponse({jsonrpc:"2.0",id:$,result:{content:[{type:"text",text:`Error: ${Z}`}],isError:!0}})}}getToolDefinitions(){return[{name:"mem-search",description:"Search through past coding session observations and memories. Supports full-text search with FTS5 across observations and session summaries.",inputSchema:{type:"object",properties:{query:{type:"string",description:"Search query (supports keywords, phrases, file paths)"},type:{type:"string",enum:["decision","bugfix","feature","refactor","discovery","change"],description:"Filter by observation type"},limit:{type:"number",description:"Maximum number of results (1-50, default: 10)"}},required:["query"]}},{name:"mem-recall",description:"Fetch full observation details by ID. Use after mem-search to get complete narratives, facts, concepts, and file lists for specific observations.",inputSchema:{type:"object",properties:{ids:{type:"array",items:{type:"string"},description:"Observation IDs to fetch"},limit:{type:"number",description:"Maximum number of results (1-50, default: 10)"}},required:["ids"]}},{name:"mem-timeline",description:"View a timeline of past coding sessions for this project. Shows recent sessions with summaries, observation counts, and key decisions.",inputSchema:{type:"object",properties:{limit:{type:"number",description:"Number of recent sessions to show (1-20, default: 5)"},sessionId:{type:"string",description:"Show details for a specific session ID"}}}},{name:"mem-save",description:"Manually save an observation to memory. Use this to explicitly record important decisions, discoveries, or context that should be remembered across sessions.",inputSchema:{type:"object",properties:{title:{type:"string",description:"Brief title for the observation (max 80 chars)"},type:{type:"string",enum:["decision","bugfix","feature","refactor","discovery","change"],description:"Type of observation"},narrative:{type:"string",description:"Detailed description of what to remember"},concepts:{type:"array",items:{type:"string"},description:"Related concepts/tags"},files:{type:"array",items:{type:"string"},description:"Related file paths"}},required:["title","type","narrative"]}},{name:"mem-export",description:"Export project memories (observations and session summaries) as portable JSON.",inputSchema:{type:"object",properties:{type:{type:"string",enum:["decision","bugfix","feature","refactor","discovery","change"],description:"Filter by observation type"},limit:{type:"number",description:"Maximum number of observations to export"}}}},{name:"mem-import",description:"Import observations and session summaries from a JSON export.",inputSchema:{type:"object",properties:{data:{type:"string",description:"JSON string from a mem-export output"}},required:["data"]}},{name:"mem-update",description:"Update an existing observation in memory.",inputSchema:{type:"object",properties:{id:{type:"string",description:"Observation ID to update"},title:{type:"string",description:"Updated title (max 80 chars)"},narrative:{type:"string",description:"Updated narrative description"},type:{type:"string",enum:["decision","bugfix","feature","refactor","discovery","change"],description:"Updated observation type"},concepts:{type:"array",items:{type:"string"},description:"Updated concepts/tags"},importance:{type:"number",description:"Updated importance score (1-5)"}},required:["id"]}},{name:"mem-delete",description:"Delete an observation from memory.",inputSchema:{type:"object",properties:{id:{type:"string",description:"Observation ID to delete"}},required:["id"]}},{name:"mem-guide",description:"Show the recommended memory workflow: mem-search -> mem-timeline -> mem-recall, plus write and transfer tools.",inputSchema:{type:"object",properties:{}}}]}async executeTool($,J){switch($){case"mem-search":return this.execSearch(J);case"mem-recall":return this.execRecall(J);case"mem-timeline":return this.execTimeline(J);case"mem-save":return this.execSave(J);case"mem-export":return this.execExport(J);case"mem-import":return this.execImport(J);case"mem-update":return this.execUpdate(J);case"mem-delete":return this.execDelete(J);case"mem-guide":return this.execGuide();default:return{content:[{type:"text",text:`Unknown tool: ${$}`}],isError:!0}}}execGuide(){return{content:[{type:"text",text:this.memoryEngine.guide()}]}}async execSearch($){let J=typeof $.query==="string"?$.query:void 0,S=i($.type),M=typeof $.limit==="number"?Math.max(1,Math.min($.limit,50)):10;if(!J)return{content:[{type:"text",text:"Missing required argument: query"}],isError:!0};try{let Q=await this.memoryEngine.search(J,{type:S,limit:M});if(Q.length===0)return{content:[{type:"text",text:"No matching observations found."}]};return{content:[{type:"text",text:a0(Q)}]}}catch(Q){return{content:[{type:"text",text:`Search error: ${Q}`}],isError:!0}}}async execRecall($){let J=k($.ids),S=typeof $.limit==="number"?Math.max(1,Math.min($.limit,50)):10;if(J.length===0)return{content:[{type:"text",text:"No observation IDs provided."}]};try{let M=J.slice(0,S),Q=await this.memoryEngine.recall(M,S),Z=[];for(let X of M){let U=Q.find((W)=>W.id===X);if(!U){Z.push(`## ID: ${X}
486
- *Not found*`);continue}let K=[];if(K.push(`## [${U.type.toUpperCase()}] ${U.title}`),U.subtitle)K.push(`*${U.subtitle}*`);if(K.push(`
487
- ${U.narrative}`),U.facts.length>0){K.push(`
488
- **Facts:**`);for(let W of U.facts)K.push(`- ${W}`)}if(U.concepts.length>0)K.push(`
489
- **Concepts:** ${U.concepts.join(", ")}`);if(U.filesRead.length>0)K.push(`**Files read:** ${U.filesRead.join(", ")}`);if(U.filesModified.length>0)K.push(`**Files modified:** ${U.filesModified.join(", ")}`);K.push(`
490
- *ID: ${U.id} | Created: ${U.createdAt} | Tokens: ${U.tokenCount}*`),Z.push(K.join(`
491
- `))}return{content:[{type:"text",text:`Recalled ${Z.length} observation(s):
492
-
493
- ${Z.join(`
494
- ---
495
- `)}`}]}}catch(M){return{content:[{type:"text",text:`Recall error: ${M}`}],isError:!0}}}async execTimeline($){let J=typeof $.limit==="number"?Math.max(1,Math.min($.limit,20)):5,S=typeof $.sessionId==="string"?$.sessionId:void 0;try{let M=await this.memoryEngine.timeline({limit:J,sessionId:S});if(S){if(M.length===0)return{content:[{type:"text",text:`Session ${S} not found.`}]};let Z=M[0],X=[`# Session Detail: ${Z.session.id}
496
- `];if(X.push(`- **Started**: ${Z.session.startedAt}`),X.push(`- **Ended**: ${Z.session.endedAt??"Active"}`),X.push(`- **Status**: ${Z.session.status}`),X.push(`- **Observations**: ${Z.session.observationCount}`),Z.summary){if(X.push(`
497
- ## Summary
498
- ${Z.summary.summary}`),Z.summary.keyDecisions.length>0){X.push(`
499
- **Key decisions:**`);for(let U of Z.summary.keyDecisions)X.push(`- ${U}`)}}if(Z.observations.length>0){X.push(`
500
- ## Observations`);for(let U of Z.observations)X.push(`
501
- ### [${U.type.toUpperCase()}] ${U.title}`),X.push(U.narrative)}return{content:[{type:"text",text:X.join(`
502
- `)}]}}if(M.length===0)return{content:[{type:"text",text:"No past sessions found for this project."}]};let Q=[`# Session Timeline (${M.length} sessions)
503
- `];for(let Z of M){if(Q.push(`## Session: ${Z.session.id}`),Q.push(`- **Started**: ${Z.session.startedAt}`),Q.push(`- **Status**: ${Z.session.status}`),Q.push(`- **Observations**: ${Z.session.observationCount}`),Z.summary){if(Q.push(`- **Summary**: ${Z.summary.summary}`),Z.summary.keyDecisions.length>0)Q.push(`- **Key decisions**: ${Z.summary.keyDecisions.join("; ")}`)}Q.push("")}return{content:[{type:"text",text:Q.join(`
504
- `)}]}}catch(M){return{content:[{type:"text",text:`Timeline error: ${M}`}],isError:!0}}}async execSave($){let J=typeof $.title==="string"?$.title:void 0,S=i($.type),M=typeof $.narrative==="string"?$.narrative:void 0,Q=k($.concepts),Z=k($.files);if(!J||!S||!M)return{content:[{type:"text",text:"Missing required arguments: title, type, narrative"}],isError:!0};try{let X=`mcp-${new Date().toISOString().slice(0,10)}`,U=await this.memoryEngine.save({title:J,type:S,narrative:M,concepts:Q,files:Z,sessionId:X});if(!U)return{content:[{type:"text",text:"Save error: unable to save observation."}],isError:!0};return{content:[{type:"text",text:`Saved observation: [${S}] "${J}" (ID: ${U.id})`}]}}catch(X){return{content:[{type:"text",text:`Save error: ${X}`}],isError:!0}}}async execExport($){let J=i($.type),S=typeof $.limit==="number"?Math.max(1,$.limit):void 0;try{let M=await this.memoryEngine.export("project",{type:J,limit:S}),Q=M,Z=Q.observations?.length??0,X=Q.summaries?.length??0,U=JSON.stringify(M,null,2);return{content:[{type:"text",text:`Exported ${Z} observation(s) and ${X} summary(ies).
505
-
506
- ${U}`}]}}catch(M){return{content:[{type:"text",text:`Export error: ${M}`}],isError:!0}}}async execImport($){let J=typeof $.data==="string"?$.data:void 0;if(!J)return{content:[{type:"text",text:"Missing required argument: data"}],isError:!0};try{let S=await this.memoryEngine.import(J,{mode:"skip-duplicates"});return{content:[{type:"text",text:`Imported ${S.imported} observation(s). Skipped ${S.skipped} duplicate/invalid observation(s).`}]}}catch(S){return{content:[{type:"text",text:`Import error: ${S}`}],isError:!0}}}async execUpdate($){let J=typeof $.id==="string"?$.id:void 0;if(!J)return{content:[{type:"text",text:"Missing required argument: id"}],isError:!0};try{let S=await this.memoryEngine.update({id:J,title:typeof $.title==="string"?$.title:void 0,narrative:typeof $.narrative==="string"?$.narrative:void 0,type:typeof $.type==="string"&&k$.has($.type)?$.type:void 0,concepts:Array.isArray($.concepts)?k($.concepts):void 0,importance:typeof $.importance==="number"?$.importance:void 0});if(!S)return{content:[{type:"text",text:`Observation "${J}" not found.`}],isError:!0};let M=Object.keys($).filter((Q)=>Q!=="id");return{content:[{type:"text",text:`Updated observation "${S.title}" (new revision ID: ${S.id}, previous ID: ${J}). Changed: ${M.join(", ")||"nothing"}.`}]}}catch(S){return{content:[{type:"text",text:`Update error: ${S}`}],isError:!0}}}async execDelete($){let J=typeof $.id==="string"?$.id:void 0;if(!J)return{content:[{type:"text",text:"Missing required argument: id"}],isError:!0};try{if(await this.memoryEngine.delete([J])===0)return{content:[{type:"text",text:`Observation "${J}" not found.`}],isError:!0};return{content:[{type:"text",text:`Tombstoned observation (ID: ${J})`}]}}catch(S){return{content:[{type:"text",text:`Delete error: ${S}`}],isError:!0}}}sendResponse($){process.stdout.write(`${JSON.stringify($)}
507
- `)}}function a0($){let J=[`Found ${$.length} observation(s):
508
- `];for(let{observation:S}of $){if(J.push(`## [${S.type.toUpperCase()}] ${S.title}`),S.subtitle)J.push(`*${S.subtitle}*`);if(J.push(`
509
- ${S.narrative}`),S.facts.length>0){J.push(`
510
- **Facts:**`);for(let M of S.facts)J.push(`- ${M}`)}if(S.concepts.length>0)J.push(`
511
- **Concepts:** ${S.concepts.join(", ")}`);if(S.filesModified.length>0)J.push(`**Files modified:** ${S.filesModified.join(", ")}`);if(S.filesRead.length>0)J.push(`**Files read:** ${S.filesRead.join(", ")}`);J.push(`
512
- *Session: ${S.sessionId} | ${S.createdAt}*`),J.push("---")}return J.join(`
513
- `)}function T$($){return $}function y$($){return $}function v$($){return $}function I$($){if(!$)return null;return $}import{spawnSync as P$}from"child_process";import{dirname as $2,resolve as q$}from"path";function J2($){try{let J=P$("git",["rev-parse","--git-common-dir"],{cwd:$,encoding:"utf-8",timeout:5000});if(J.status!==0||!J.stdout)return null;let S=J.stdout.trim();if(S===".git")return null;let M=P$("git",["rev-parse","--git-dir"],{cwd:$,encoding:"utf-8",timeout:5000});if(M.status!==0||!M.stdout)return null;let Q=M.stdout.trim(),Z=q$($,S),X=q$($,Q);if(Z===X)return null;let U=$2(Z);if(U===Z||U==="/")return null;return U}catch{return null}}function p$($){return J2($)??$}var __dirname="/Users/clopca/dev/github/open-mem/src",{values:m$}=Q2({options:{project:{type:"string",short:"p"}},strict:!1}),Z2=typeof m$.project==="string"?m$.project:process.cwd(),u$=p$(Z2),Y=s(u$);C.enableExtensionSupport();var z=O(Y.dbPath);A$(z,{hasVectorExtension:z.hasVectorExtension,embeddingDimension:Y.embeddingDimension});var X2=new c(z),w$=new w(z),U2=new g(z),F=null,r=null;if(Y.userMemoryEnabled)try{F=new n(Y.userMemoryDbPath),r=new b(F.database)}catch($){console.error(`[open-mem-mcp] Failed to initialize user-level memory: ${$}`)}var c$=Y.provider!=="bedrock",K2=Y.compressionEnabled&&(!c$||Y.apiKey)?o({provider:Y.provider,model:Y.model,apiKey:Y.apiKey}):null,W2=x$(Y,Y.rerankingEnabled&&(!c$||Y.apiKey)?e({provider:Y.provider,model:Y.model,apiKey:Y.apiKey}):null),V2=new u(z),Y2=new l(w$,K2,z.hasVectorExtension,W2,r,V2),H2=JSON.parse(S2(M2(__dirname,"..","package.json"),"utf-8")),N2=new T({memoryEngine:new p({observations:T$(w$),sessions:y$(X2),summaries:v$(U2),searchOrchestrator:Y2,projectPath:u$,config:Y,userObservationRepo:I$(r)}),version:H2.version}),y=!1,g$=()=>{if(!y){if(y=!0,F)F.close();z.close()}process.exit(0)};process.on("SIGINT",g$);process.on("SIGTERM",g$);process.on("beforeExit",()=>{if(!y){if(y=!0,F)F.close();z.close()}});N2.start();
513
+ </rerank_request>`}var p0={"gemini-2.5-flash-lite":10,"gemini-2.5-flash":10,"gemini-2.5-pro":5,"gemini-2.0-flash":15,"gemini-2.0-flash-lite":30,"gemini-3-flash":5},oE=0;async function aE(E,M){if(!M)return;let N=p0[E]||5,_=Math.ceil(60000/N)+100,J=Date.now()-oE;if(J<_){let S=_-J;await new Promise((V)=>setTimeout(V,S))}oE=Date.now()}class eE{languageModel;maxCandidates;provider;modelName;rateLimitingEnabled;_generate=v0;constructor(E,M){this.languageModel=E,this.maxCandidates=M.rerankingMaxCandidates,this.provider=M.provider??"",this.modelName=M.model??"",this.rateLimitingEnabled=M.rateLimitingEnabled??!0}async rerank(E,M,N){if(M.length<=1)return M;let _=M.slice(0,this.maxCandidates),O=M.slice(this.maxCandidates),J=rE(E,_.map((V)=>({title:V.observation.title,narrative:V.observation.narrative}))),S=2;for(let V=0;V<=S;V++)try{if(this.provider==="google")await aE(this.modelName,this.rateLimitingEnabled);let{text:C}=await this._generate({model:this.languageModel,maxOutputTokens:512,prompt:J}),A=QE(C);if(!A)return M.slice(0,N);let $=this.applyReranking(_,A,N);for(let H of O){if($.length>=N)break;$.push(H)}return $}catch(C){if(g0(C)&&V<S){await I0(2**V*1000);continue}return M.slice(0,N)}return M.slice(0,N)}applyReranking(E,M,N){let _=[],O=new Set;for(let J of M)if(J>=0&&J<E.length&&!O.has(J)){if(O.add(J),_.push(E[J]),_.length>=N)break}if(_.length<N){for(let J=0;J<E.length&&_.length<N;J++)if(!O.has(J))_.push(E[J])}return _}}class tE{async rerank(E,M,N){if(M.length<=1)return M.slice(0,N);let _=$E(E),O=M.map((J)=>({result:J,score:this.scoreCandidate(J,_)}));return O.sort((J,S)=>S.score-J.score),O.slice(0,N).map((J)=>J.result)}scoreCandidate(E,M){let N=E.observation,_=$E(N.title),O=$E(N.narrative),J=new Set(N.concepts.map((P)=>P.toLowerCase())),S=0,V=0,C=0;for(let P of M){if(_.has(P))S++;if(O.has(P))V++;if(J.has(P))C++}let A=M.size||1,$=S/A*0.4,H=V/A*0.3,Y=C/A*0.15,D=(Date.now()-new Date(N.createdAt).getTime())/86400000,b=D<1?0.1:D<7?0.05:0,ZM=N.importance/5*0.05;return $+H+Y+b+ZM}}function sE(E,M){if(!E.rerankingEnabled)return null;if(M)return new eE(M,E);return new tE}function $E(E){return new Set(E.toLowerCase().split(/[\s\-_./\\,;:!?()[\]{}'"]+/).filter((M)=>M.length>1))}function g0(E){if(typeof E!=="object"||E===null)return!1;let M=E,N=M.status;if(N===429||N===500||N===503)return!0;let _=M.error;if(typeof _==="object"&&_!==null&&_.type==="overloaded_error")return!0;return!1}function I0(E){return new Promise((M)=>setTimeout(M,E))}function EM(E){return E}function MM(E){return E}function NM(E){return E}function _M(E){if(!E)return null;return E}import{spawnSync as OM}from"child_process";import{dirname as h0,resolve as JM}from"path";function q0(E){try{let M=OM("git",["rev-parse","--git-common-dir"],{cwd:E,encoding:"utf-8",timeout:5000});if(M.status!==0||!M.stdout)return null;let N=M.stdout.trim();if(N===".git")return null;let _=OM("git",["rev-parse","--git-dir"],{cwd:E,encoding:"utf-8",timeout:5000});if(_.status!==0||!_.stdout)return null;let O=_.stdout.trim(),J=JM(E,N),S=JM(E,O);if(J===S)return null;let V=h0(J);if(V===J||V==="/")return null;return V}catch{return null}}function SM(E){return q0(E)??E}var __dirname="/Users/clopca/dev/github/open-mem/src",{values:VM}=w0({options:{project:{type:"string",short:"p"}},strict:!1}),l0=typeof VM.project==="string"?VM.project:process.cwd(),CM=SM(l0),R=m(CM);u.enableExtensionSupport();var L=w(R.dbPath);bE(L,{hasVectorExtension:L.hasVectorExtension,embeddingDimension:R.embeddingDimension});var c0=new JE(L),AM=new OE(L),b0=new SE(L),n0=new EE(L),d0=new _E(L),f=null,XE=null;if(R.userMemoryEnabled)try{f=new VE(R.userMemoryDbPath),XE=new CE(f.database)}catch(E){console.error(`[open-mem-mcp] Failed to initialize user-level memory: ${E}`)}var $M=R.provider!=="bedrock",i0=R.compressionEnabled&&(!$M||R.apiKey)?KE({provider:R.provider,model:R.model,apiKey:R.apiKey}):null,r0=sE(R,R.rerankingEnabled&&(!$M||R.apiKey)?HE({provider:R.provider,model:R.model,apiKey:R.apiKey}):null),o0=new NE(L),a0=new AE(AM,i0,L.hasVectorExtension,r0,XE,o0),e0=JSON.parse(x0(u0(__dirname,"..","package.json"),"utf-8")),t0=new n({memoryEngine:new s({observations:EM(AM),sessions:MM(c0),summaries:NM(b0),searchOrchestrator:a0,projectPath:CM,config:R,userObservationRepo:_M(XE),configAuditStore:n0,maintenanceHistoryStore:d0}),version:e0.version,compatibilityMode:R.mcpCompatibilityMode,protocolVersion:R.mcpProtocolVersion,supportedProtocolVersions:R.mcpSupportedProtocolVersions}),c=!1,XM=()=>{if(!c){if(c=!0,f)f.close();L.close()}process.exit(0)};process.on("SIGINT",XM);process.on("SIGTERM",XM);process.on("beforeExit",()=>{if(!c){if(c=!0,f)f.close();L.close()}});t0.start();