open-mem 0.10.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/README.md +56 -2
- package/dist/adapters/http/server.d.ts.map +1 -1
- package/dist/ai/prompts.d.ts +3 -2
- package/dist/ai/prompts.d.ts.map +1 -1
- package/dist/claude-code.js +40 -45
- package/dist/config.d.ts.map +1 -1
- package/dist/cursor.js +40 -45
- package/dist/daemon.js +37 -42
- package/dist/hooks/compaction.d.ts +5 -1
- package/dist/hooks/compaction.d.ts.map +1 -1
- package/dist/index.js +89 -90
- package/dist/maintenance.js +34 -34
- package/dist/mcp.js +44 -44
- package/dist/modes/loader.d.ts +7 -0
- package/dist/modes/loader.d.ts.map +1 -0
- package/dist/types.d.ts +11 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +3 -1
package/dist/daemon.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
// @bun
|
|
3
|
-
var A=import.meta.require;import{parseArgs as
|
|
3
|
+
var A=import.meta.require;import{parseArgs as MX}from"util";import{generateText as pJ}from"ai";function L(J){if(typeof J!=="object"||J===null)return!1;let X=J,$=X.status;if($===429||$===500||$===503)return!0;let Q=X.error;if(typeof Q==="object"&&Q!==null&&Q.type==="overloaded_error")return!0;return!1}function w(J){if(J&&typeof J==="object"){let X=J.status;if(typeof X==="number")return X===400||X===401||X===403}return!1}function R(J){return new Promise((X)=>setTimeout(X,J))}var hJ=new Set(["decision","bugfix","feature","refactor","discovery","change"]);function z(J,X){let $=new RegExp(`<${X}[^>]*>([\\s\\S]*?)</${X}>`,"i"),Q=J.match($);return Q?Q[1].trim():""}function M(J,X){let $=new RegExp(`<${X}[^>]*>([\\s\\S]*?)</${X}>`,"gi"),Q=[];for(let Z of J.matchAll($)){let H=Z[1].trim();if(H)Q.push(H)}return Q}function $J(J){let X=z(J,"observation");if(!X)return null;let $=z(X,"type").toLowerCase(),Q=hJ.has($)?$:"discovery",Z=z(X,"title")||"Untitled observation",H=z(X,"subtitle"),Y=z(X,"narrative"),V=M(z(X,"facts"),"fact"),W=M(z(X,"concepts"),"concept"),K=M(z(X,"files_read"),"file"),B=M(z(X,"files_modified"),"file"),U=z(X,"importance"),_=Number.parseInt(U,10),F=Number.isNaN(_)?3:Math.max(1,Math.min(5,_));return{type:Q,title:Z,subtitle:H,facts:V,narrative:Y,concepts:W,filesRead:K,filesModified:B,importance:F}}function QJ(J){let X=z(J,"session_summary");if(!X)return null;let $=z(X,"summary")||"No summary available",Q=M(z(X,"key_decisions"),"decision"),Z=M(z(X,"files_modified"),"file"),H=M(z(X,"concepts"),"concept"),Y=z(X,"request")||void 0,V=z(X,"investigated")||void 0,W=z(X,"learned")||void 0,K=z(X,"completed")||void 0,B=z(X,"next_steps")||void 0;return{summary:$,keyDecisions:Q,filesModified:Z,concepts:H,request:Y,investigated:V,learned:W,completed:K,nextSteps:B}}var yJ=new Set(["new_fact","update","duplicate"]);function ZJ(J){let X=z(J,"evaluation");if(!X)return null;let $=z(X,"outcome").toLowerCase().trim();if(!yJ.has($))return null;let Q=$,Z=z(X,"reason");if(!Z)return null;let H=z(X,"supersedes"),Y={outcome:Q,reason:Z};if(Q==="update"&&H)Y.supersedesId=H;if(Q==="update"&&!Y.supersedesId)return null;return Y}var wJ=new Set(["technology","library","pattern","concept","file","person","project","other"]),vJ=new Set(["uses","depends_on","implements","extends","related_to","replaces","configures"]);function HJ(J){let X=z(J,"extraction");if(!X)return null;let $=z(X,"entities"),Q=z(X,"relations"),Z=M($,"entity"),H=[];for(let W of Z){let K=z(W,"name");if(!K)continue;let B=z(W,"type").toLowerCase(),U=wJ.has(B)?B:"other";H.push({name:K,entityType:U})}let Y=M(Q,"relation"),V=[];for(let W of Y){let K=z(W,"source"),B=z(W,"target"),U=z(W,"relationship").toLowerCase();if(!K||!B||!U)continue;if(!vJ.has(U))continue;V.push({sourceName:K,targetName:B,relationship:U})}return{entities:H,relations:V}}function O(J){return Math.ceil(J.length/4)}function YJ(J,X,$,Q){let Z=$?`<session_context>
|
|
4
4
|
${$}
|
|
5
5
|
</session_context>
|
|
6
6
|
|
|
7
|
-
`:"";return
|
|
7
|
+
`:"",H=Q?Q.observationTypes.join("|"):"decision|bugfix|feature|refactor|discovery|change",V=(Q?Q.conceptVocabulary:["how-it-works","why-it-exists","what-changed","problem-solution","gotcha","pattern","trade-off"]).map((W)=>{let B={"how-it-works":"Technical mechanisms and behaviors","why-it-exists":"Rationale and motivations","what-changed":"Modifications and their effects","problem-solution":"Issues encountered and how they were resolved",gotcha:"Surprising behaviors, edge cases, or pitfalls",pattern:"Recurring design patterns or approaches","trade-off":"Deliberate compromises between competing concerns",hypothesis:"Proposed explanations or predictions",finding:"Key results or discoveries",methodology:"Research methods and approaches",evidence:"Supporting data or observations",limitation:"Known constraints or boundaries",implication:"Consequences or downstream effects",comparison:"Similarities and differences between approaches"}[W];return B?`- ${W}: ${B}`:`- ${W}`}).join(`
|
|
8
|
+
`);return`<task>
|
|
8
9
|
Analyze the following tool output and extract a structured observation.
|
|
9
10
|
</task>
|
|
10
11
|
|
|
@@ -14,22 +15,16 @@ Analyze the following tool output and extract a structured observation.
|
|
|
14
15
|
${X}
|
|
15
16
|
</tool_output>
|
|
16
17
|
|
|
17
|
-
${
|
|
18
|
+
${Z}<instructions>
|
|
18
19
|
Extract a structured observation from the tool output. Determine the most appropriate type and provide a concise but informative summary.
|
|
19
20
|
|
|
20
21
|
When extracting concepts, prefer established vocabulary where appropriate:
|
|
21
|
-
|
|
22
|
-
- why-it-exists: Rationale and motivations
|
|
23
|
-
- what-changed: Modifications and their effects
|
|
24
|
-
- problem-solution: Issues encountered and how they were resolved
|
|
25
|
-
- gotcha: Surprising behaviors, edge cases, or pitfalls
|
|
26
|
-
- pattern: Recurring design patterns or approaches
|
|
27
|
-
- trade-off: Deliberate compromises between competing concerns
|
|
22
|
+
${V}
|
|
28
23
|
You may also use any domain-specific concepts relevant to the observation.
|
|
29
24
|
|
|
30
25
|
Respond with EXACTLY this XML format:
|
|
31
26
|
<observation>
|
|
32
|
-
<type
|
|
27
|
+
<type>${H}</type>
|
|
33
28
|
<title>Brief descriptive title (max 80 chars)</title>
|
|
34
29
|
<subtitle>One-line elaboration</subtitle>
|
|
35
30
|
<importance>1-5 (1=trivial/routine, 2=low, 3=normal, 4=significant, 5=critical decision or discovery)</importance>
|
|
@@ -49,7 +44,7 @@ Respond with EXACTLY this XML format:
|
|
|
49
44
|
<file>path/to/file/modified</file>
|
|
50
45
|
</files_modified>
|
|
51
46
|
</observation>
|
|
52
|
-
</instructions>`}function
|
|
47
|
+
</instructions>`}function VJ(J,X){let $=J.map((Q,Z)=>` <obs index="${Z+1}" type="${Q.type}">
|
|
53
48
|
<title>${Q.title}</title>
|
|
54
49
|
<narrative>${Q.narrative}</narrative>
|
|
55
50
|
</obs>`).join(`
|
|
@@ -84,7 +79,7 @@ Respond with EXACTLY this XML format:
|
|
|
84
79
|
<concept>key-concept</concept>
|
|
85
80
|
</concepts>
|
|
86
81
|
</session_summary>
|
|
87
|
-
</instructions>`}function
|
|
82
|
+
</instructions>`}function WJ(J,X){let $=X.map((Q)=>` <candidate id="${Q.id}">
|
|
88
83
|
<title>${Q.title}</title>
|
|
89
84
|
<narrative>${Q.narrative}</narrative>
|
|
90
85
|
<concepts>${Q.concepts.join(", ")}</concepts>
|
|
@@ -113,22 +108,22 @@ Respond with EXACTLY this XML format:
|
|
|
113
108
|
<reason>Brief explanation</reason>
|
|
114
109
|
</evaluation>
|
|
115
110
|
</instructions>
|
|
116
|
-
</conflict_evaluation>`}function
|
|
111
|
+
</conflict_evaluation>`}function KJ(J,X){let $=[...J.filesRead,...J.filesModified],Q=X?X.entityTypes.join(", "):"technology, library, pattern, concept, file, person, project, other",Z=X?X.relationshipTypes.join(", "):"uses, depends_on, implements, extends, related_to, replaces, configures";return`<entity_extraction>
|
|
117
112
|
<observation>
|
|
118
113
|
<title>${J.title}</title>
|
|
119
114
|
<type>${J.type}</type>
|
|
120
115
|
<narrative>${J.narrative}</narrative>
|
|
121
116
|
<facts>${J.facts.join(`
|
|
122
117
|
`)}</facts>
|
|
123
|
-
<files>${
|
|
118
|
+
<files>${$.join(`
|
|
124
119
|
`)}</files>
|
|
125
120
|
<concepts>${J.concepts.join(", ")}</concepts>
|
|
126
121
|
</observation>
|
|
127
122
|
<instructions>
|
|
128
123
|
Extract entities and relationships from this observation.
|
|
129
124
|
|
|
130
|
-
Entity types:
|
|
131
|
-
Relationship types:
|
|
125
|
+
Entity types: ${Q}
|
|
126
|
+
Relationship types: ${Z}
|
|
132
127
|
|
|
133
128
|
Extract entities that are clearly mentioned or strongly implied. For example, "React hooks" implies a relationship between React and hooks. Do not extract speculative relationships.
|
|
134
129
|
Respond with EXACTLY this XML format:
|
|
@@ -142,32 +137,32 @@ Respond with EXACTLY this XML format:
|
|
|
142
137
|
</relations>
|
|
143
138
|
</extraction>
|
|
144
139
|
</instructions>
|
|
145
|
-
</entity_extraction>`}class
|
|
140
|
+
</entity_extraction>`}class v{specificationVersion;provider;modelId;supportedUrls;providers;constructor(J){if(J.length===0)throw Error("At least one provider required");let X=J[0].model;this.specificationVersion=X.specificationVersion,this.provider=X.provider,this.modelId=X.modelId,this.supportedUrls=X.supportedUrls,this.providers=J}async doGenerate(J){let X;for(let $=0;$<this.providers.length;$++){let Q=this.providers[$];try{return await Q.model.doGenerate(J)}catch(Z){if(X=Z,w(Z))throw Z;if(L(Z)&&$<this.providers.length-1){let H=this.providers[$+1],Y=Z.status??"unknown";console.error(`[open-mem] Provider ${Q.name} failed (${Y}), falling over to ${H.name}`);continue}throw Z}}throw X}async doStream(J){let X;for(let $=0;$<this.providers.length;$++){let Q=this.providers[$];try{return await Q.model.doStream(J)}catch(Z){if(X=Z,w(Z))throw Z;if(L(Z)&&$<this.providers.length-1){let H=this.providers[$+1],Y=Z.status??"unknown";console.error(`[open-mem] Provider ${Q.name} failed (${Y}), falling over to ${H.name}`);continue}throw Z}}throw X}}var fJ={"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 uJ(J){if(J.includes("."))return J;return fJ[J]||`us.anthropic.${J}-v1:0`}function zJ(J){switch(J.provider){case"anthropic":{let{createAnthropic:X}=A("@ai-sdk/anthropic");return X({apiKey:J.apiKey})(J.model)}case"bedrock":{let{createAmazonBedrock:X}=A("@ai-sdk/amazon-bedrock");return X()(uJ(J.model))}case"openai":{let{createOpenAI:X}=A("@ai-sdk/openai");return X({apiKey:J.apiKey})(J.model)}case"google":{let{createGoogleGenerativeAI:X}=A("@ai-sdk/google");return X({apiKey:J.apiKey})(J.model)}case"openrouter":{let{createOpenRouter:X}=A("@openrouter/ai-sdk-provider");return X({apiKey:J.apiKey})(J.model)}default:throw Error(`Unknown provider: ${J.provider}. Supported: anthropic, bedrock, openai, google, openrouter`)}}function GJ(J){try{switch(J.provider){case"google":{let{createGoogleGenerativeAI:X}=A("@ai-sdk/google");return X({apiKey:J.apiKey}).embedding("text-embedding-004")}case"openai":{let{createOpenAI:X}=A("@ai-sdk/openai");return X({apiKey:J.apiKey}).embedding("text-embedding-3-small")}case"bedrock":{let{createAmazonBedrock:X}=A("@ai-sdk/amazon-bedrock");return X().embedding("amazon.titan-embed-text-v2:0")}case"anthropic":return null;case"openrouter":return null;default:return null}}catch{return null}}var bJ={google:"gemini-2.5-flash-lite",anthropic:"claude-sonnet-4-20250514",openai:"gpt-4o-mini",bedrock:"us.anthropic.claude-3-5-haiku-20241022-v1:0",openrouter:"google/gemini-2.5-flash-lite"};function gJ(J){switch(J){case"google":return process.env.GOOGLE_GENERATIVE_AI_API_KEY||process.env.GEMINI_API_KEY;case"anthropic":return process.env.ANTHROPIC_API_KEY;case"openai":return process.env.OPENAI_API_KEY;case"openrouter":return process.env.OPENROUTER_API_KEY;case"bedrock":return;default:return}}function S(J){if(!J.fallbackProviders||J.fallbackProviders.length===0)return[];return J.fallbackProviders.map((X)=>({provider:X,model:bJ[X]??"gemini-2.5-flash-lite",apiKey:gJ(X)}))}function j(J,X=[]){let $=zJ(J);if(X.length===0)return $;let Q=[{name:J.provider,model:$},...X.map((Z)=>({name:Z.provider,model:zJ(Z)}))];return new v(Q)}var mJ={"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},BJ=0;async function D(J,X){if(!X)return;let $=mJ[J]||5,Q=Math.ceil(60000/$)+100,H=Date.now()-BJ;if(H<Q){let Y=Q-H;await new Promise((V)=>setTimeout(V,Y))}BJ=Date.now()}class x{model;config;_generate=pJ;constructor(J){this.config=J,this.model=null;let X=J.provider!=="bedrock";if(J.compressionEnabled&&(!X||J.apiKey))try{this.model=j({provider:J.provider,model:J.model,apiKey:J.apiKey},S(J))}catch{}}static MAX_INPUT_LENGTH=50000;async compress(J,X,$){if(!this.config.compressionEnabled||!this.model)return null;if(X.length<this.config.minOutputLength)return null;let Q=O(X),Z=X.length>x.MAX_INPUT_LENGTH?`${X.substring(0,x.MAX_INPUT_LENGTH)}
|
|
146
141
|
|
|
147
|
-
[... truncated ...]`:X,Y=ZJ(J,Z,$),H=2;for(let V=0;V<=H;V++)try{if(this.config.provider==="google")await D(this.config.model,this.config.rateLimitingEnabled);let{text:W}=await this._generate({model:this.model,maxOutputTokens:this.config.maxTokensPerCompression,prompt:Y}),K=JJ(W);if(K)K.discoveryTokens=Q;return K}catch(W){if(L(W)&&V<H){let K=2**V*1000;await E(K);continue}return null}return null}async compressBatch(J){let X=new Map;for(let $=0;$<J.length;$++){let Q=J[$],Z=await this.compress(Q.toolName,Q.toolOutput,Q.sessionContext);if(X.set(Q.callId,Z),$<J.length-1)await E(200)}return X}createFallbackObservation(J,X){let $=mJ(X),Q=bJ[J]??"discovery";return{type:Q,title:`${J} execution`,subtitle:X.substring(0,100).replace(/\n/g," "),facts:[],narrative:`Tool ${J} was executed. Output length: ${X.length} chars.`,concepts:[],filesRead:Q==="discovery"?$:[],filesModified:Q==="change"?$:[],discoveryTokens:R(X),importance:2}}async isAvailable(){if(!this.model)return!1;try{return await this._generate({model:this.model,maxOutputTokens:10,prompt:"ping"}),!0}catch{return!1}}}var bJ={Read:"discovery",Write:"change",Edit:"change",Bash:"change",Glob:"discovery",Grep:"discovery"},gJ=/(?:^|\s)((?:\.\/|\/|src\/|tests\/|lib\/)\S+\.\w+)/gm;function mJ(J){let X=[];for(let $ of J.matchAll(gJ))X.push($[1]);return[...new Set(X)]}import{generateText as pJ}from"ai";class v{model;config;_generate=pJ;constructor(J){if(this.config=J,this.model=null,J.provider==="bedrock"||J.apiKey)try{this.model=C({provider:J.provider,model:J.model,apiKey:J.apiKey},S(J))}catch{}}async evaluate(J,X){if(!this.model||X.length===0)return null;let $=YJ(J,X),Q=2;for(let Z=0;Z<=Q;Z++)try{if(this.config.provider==="google")await D(this.config.model,this.config.rateLimitingEnabled);let{text:Y}=await this._generate({model:this.model,maxOutputTokens:512,prompt:$});return $J(Y)}catch(Y){if(L(Y)&&Z<Q){let H=2**Z*1000;await E(H);continue}return null}return null}}import{generateText as lJ}from"ai";class f{model;config;_generate=lJ;constructor(J){if(this.config=J,this.model=null,J.provider==="bedrock"||J.apiKey)try{this.model=C({provider:J.provider,model:J.model,apiKey:J.apiKey},S(J))}catch{}}async extract(J){if(!this.model)return null;let X=VJ(J),$=2;for(let Q=0;Q<=$;Q++)try{if(this.config.provider==="google")await D(this.config.model,this.config.rateLimitingEnabled);let{text:Z}=await this._generate({model:this.model,maxOutputTokens:1024,prompt:X});return QJ(Z)}catch(Z){if(L(Z)&&Q<$){let Y=2**Q*1000;await E(Y);continue}return null}return null}}import{generateText as cJ}from"ai";class u{model;config;_generate=cJ;constructor(J){this.config=J,this.model=null;let X=J.provider!=="bedrock";if(J.compressionEnabled&&(!X||J.apiKey))try{this.model=C({provider:J.provider,model:J.model,apiKey:J.apiKey},S(J))}catch{}}async summarize(J,X){if(X.length===0)return null;if(!this.config.compressionEnabled||!this.model)return this.createFallbackSummary(X);let $=HJ(X.map((Q)=>({type:Q.type,title:Q.title,narrative:Q.narrative})),J);try{if(this.config.provider==="google")await D(this.config.model,this.config.rateLimitingEnabled);let{text:Q}=await this._generate({model:this.model,maxOutputTokens:this.config.maxTokensPerCompression,prompt:$}),Z=XJ(Q);if(!Z)return this.createFallbackSummary(X);return Z}catch{return this.createFallbackSummary(X)}}createFallbackSummary(J){let X=new Set,$=new Set,Q=[];for(let V of J){for(let W of V.filesModified)X.add(W);for(let W of V.concepts)$.add(W);if(V.type==="decision")Q.push(V.title)}let Z=new Map;for(let V of J)Z.set(V.type,(Z.get(V.type)??0)+1);let Y=Array.from(Z.entries()).map(([V,W])=>`${W} ${V}${W>1?"s":""}`).join(", "),H=Array.from($).slice(0,5).join(", ");return{summary:`Session with ${J.length} observations: ${Y}. Files modified: ${X.size}. Key concepts: ${H}.`,keyDecisions:Q.slice(0,5),filesModified:Array.from(X),concepts:Array.from($)}}shouldSummarize(J){return J>=2}}import{existsSync as dJ,readFileSync as nJ}from"fs";var sJ={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,folderContextMode:"dispersed",folderContextFilename:"AGENTS.md",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,fallbackProviders:void 0};function iJ(){let J={};if(process.env.OPEN_MEM_DB_PATH)J.dbPath=process.env.OPEN_MEM_DB_PATH;if(process.env.OPEN_MEM_PROVIDER)J.provider=process.env.OPEN_MEM_PROVIDER;if(process.env.OPEN_MEM_MODEL)J.model=process.env.OPEN_MEM_MODEL;if(process.env.OPEN_MEM_MAX_CONTEXT_TOKENS)J.maxContextTokens=Number.parseInt(process.env.OPEN_MEM_MAX_CONTEXT_TOKENS,10);if(process.env.OPEN_MEM_COMPRESSION==="false")J.compressionEnabled=!1;if(process.env.OPEN_MEM_CONTEXT_INJECTION==="false")J.contextInjectionEnabled=!1;if(process.env.OPEN_MEM_IGNORED_TOOLS)J.ignoredTools=process.env.OPEN_MEM_IGNORED_TOOLS.split(",").map((X)=>X.trim());if(process.env.OPEN_MEM_BATCH_SIZE)J.batchSize=Number.parseInt(process.env.OPEN_MEM_BATCH_SIZE,10);if(process.env.OPEN_MEM_RETENTION_DAYS)J.retentionDays=Number.parseInt(process.env.OPEN_MEM_RETENTION_DAYS,10);if(process.env.OPEN_MEM_LOG_LEVEL)J.logLevel=process.env.OPEN_MEM_LOG_LEVEL;if(process.env.OPEN_MEM_CONTEXT_SHOW_TOKEN_COSTS==="false")J.contextShowTokenCosts=!1;if(process.env.OPEN_MEM_CONTEXT_TYPES)J.contextObservationTypes=process.env.OPEN_MEM_CONTEXT_TYPES==="all"?"all":process.env.OPEN_MEM_CONTEXT_TYPES.split(",").map((X)=>X.trim());if(process.env.OPEN_MEM_CONTEXT_FULL_COUNT)J.contextFullObservationCount=Number.parseInt(process.env.OPEN_MEM_CONTEXT_FULL_COUNT,10);if(process.env.OPEN_MEM_MAX_OBSERVATIONS)J.maxObservations=Number.parseInt(process.env.OPEN_MEM_MAX_OBSERVATIONS,10);if(process.env.OPEN_MEM_CONTEXT_SHOW_LAST_SUMMARY==="false")J.contextShowLastSummary=!1;if(process.env.OPEN_MEM_RATE_LIMITING==="false")J.rateLimitingEnabled=!1;if(process.env.OPEN_MEM_FOLDER_CONTEXT==="false")J.folderContextEnabled=!1;if(process.env.OPEN_MEM_FOLDER_CONTEXT_MAX_DEPTH)J.folderContextMaxDepth=Number.parseInt(process.env.OPEN_MEM_FOLDER_CONTEXT_MAX_DEPTH,10);if(process.env.OPEN_MEM_FOLDER_CONTEXT_MODE==="single")J.folderContextMode="single";if(process.env.OPEN_MEM_FOLDER_CONTEXT_MODE==="dispersed")J.folderContextMode="dispersed";if(process.env.OPEN_MEM_FOLDER_CONTEXT_FILENAME)J.folderContextFilename=process.env.OPEN_MEM_FOLDER_CONTEXT_FILENAME;if(process.env.OPEN_MEM_DAEMON==="true")J.daemonEnabled=!0;if(process.env.OPEN_MEM_DASHBOARD==="true")J.dashboardEnabled=!0;if(process.env.OPEN_MEM_DASHBOARD_PORT)J.dashboardPort=Number.parseInt(process.env.OPEN_MEM_DASHBOARD_PORT,10);if(process.env.OPEN_MEM_PLATFORM_OPENCODE==="false")J.platformOpenCodeEnabled=!1;if(process.env.OPEN_MEM_PLATFORM_CLAUDE_CODE==="true")J.platformClaudeCodeEnabled=!0;if(process.env.OPEN_MEM_PLATFORM_CURSOR==="true")J.platformCursorEnabled=!0;if(process.env.OPEN_MEM_MCP_COMPAT_MODE)J.mcpCompatibilityMode=process.env.OPEN_MEM_MCP_COMPAT_MODE;if(process.env.OPEN_MEM_MCP_PROTOCOL_VERSION)J.mcpProtocolVersion=process.env.OPEN_MEM_MCP_PROTOCOL_VERSION;if(process.env.OPEN_MEM_MCP_SUPPORTED_PROTOCOLS)J.mcpSupportedProtocolVersions=process.env.OPEN_MEM_MCP_SUPPORTED_PROTOCOLS.split(",").map((X)=>X.trim()).filter(Boolean);if(process.env.OPEN_MEM_EMBEDDING_DIMENSION)J.embeddingDimension=Number.parseInt(process.env.OPEN_MEM_EMBEDDING_DIMENSION,10);if(process.env.OPEN_MEM_CONFLICT_RESOLUTION==="true")J.conflictResolutionEnabled=!0;if(process.env.OPEN_MEM_CONFLICT_BAND_LOW){let X=Number.parseFloat(process.env.OPEN_MEM_CONFLICT_BAND_LOW);if(!Number.isNaN(X))J.conflictSimilarityBandLow=X}if(process.env.OPEN_MEM_CONFLICT_BAND_HIGH){let X=Number.parseFloat(process.env.OPEN_MEM_CONFLICT_BAND_HIGH);if(!Number.isNaN(X))J.conflictSimilarityBandHigh=X}if(process.env.OPEN_MEM_USER_MEMORY==="true")J.userMemoryEnabled=!0;if(process.env.OPEN_MEM_USER_MEMORY_DB_PATH)J.userMemoryDbPath=process.env.OPEN_MEM_USER_MEMORY_DB_PATH;if(process.env.OPEN_MEM_USER_MEMORY_MAX_TOKENS)J.userMemoryMaxContextTokens=Number.parseInt(process.env.OPEN_MEM_USER_MEMORY_MAX_TOKENS,10);if(process.env.OPEN_MEM_RERANKING==="true")J.rerankingEnabled=!0;if(process.env.OPEN_MEM_RERANKING_MAX_CANDIDATES)J.rerankingMaxCandidates=Number.parseInt(process.env.OPEN_MEM_RERANKING_MAX_CANDIDATES,10);if(process.env.OPEN_MEM_ENTITY_EXTRACTION==="true")J.entityExtractionEnabled=!0;if(process.env.OPEN_MEM_FALLBACK_PROVIDERS)J.fallbackProviders=process.env.OPEN_MEM_FALLBACK_PROVIDERS.split(",").map((X)=>X.trim()).filter(Boolean);return J}function aJ(J){let X=`${J}/.open-mem/config.json`;if(!dJ(X))return{};try{let $=nJ(X,"utf-8"),Q=JSON.parse($);if(!Q||typeof Q!=="object"||Array.isArray(Q))return{};return Q}catch{return{}}}function rJ(J){switch(J){case"google":return 768;case"openai":return 1536;case"bedrock":return 1024;case"anthropic":return 0;case"openrouter":return 0;default:return 768}}function GJ(J,X){let $=aJ(J),Q=iJ(),Z={...sJ,...$,...Q,...X};if(!Z.dbPath.startsWith("/"))Z.dbPath=`${J}/${Z.dbPath}`;if(!process.env.OPEN_MEM_PROVIDER&&!X?.provider){if(process.env.GOOGLE_GENERATIVE_AI_API_KEY||process.env.GEMINI_API_KEY)Z.provider="google";else if(process.env.ANTHROPIC_API_KEY)Z.provider="anthropic";else if(process.env.AWS_BEARER_TOKEN_BEDROCK||process.env.AWS_ACCESS_KEY_ID||process.env.AWS_PROFILE)Z.provider="bedrock";else if(process.env.OPENROUTER_API_KEY)Z.provider="openrouter"}if(!Z.apiKey)switch(Z.provider){case"google":Z.apiKey=process.env.GOOGLE_GENERATIVE_AI_API_KEY||process.env.GEMINI_API_KEY;break;case"anthropic":Z.apiKey=process.env.ANTHROPIC_API_KEY;break;case"openai":Z.apiKey=process.env.OPENAI_API_KEY;break;case"openrouter":Z.apiKey=process.env.OPENROUTER_API_KEY;break;case"bedrock":break}if(Z.provider==="openrouter"&&Z.model==="gemini-2.5-flash-lite")Z.model="google/gemini-2.5-flash-lite";if(Z.embeddingDimension===void 0)Z.embeddingDimension=rJ(Z.provider);return Z}import{existsSync as K2,mkdirSync as oJ,readFileSync as z2,unlinkSync as tJ,writeFileSync as eJ}from"fs";function BJ(J){let X=J.lastIndexOf("/");if(X>0){let $=J.substring(0,X);oJ($,{recursive:!0})}eJ(J,String(process.pid),"utf-8")}function UJ(J){try{tJ(J)}catch{}}function _J(J){let X=J.lastIndexOf("/");if(X>=0)return`${J.substring(0,X)}/worker.pid`;return"worker.pid"}class b{queueProcessor;pollIntervalMs;timer=null;lastActiveAt=Date.now();processing=!1;constructor(J){this.queueProcessor=J.queueProcessor,this.pollIntervalMs=J.pollIntervalMs}start(){if(this.timer)return;this.lastActiveAt=Date.now(),this.timer=setInterval(async()=>{if(this.processing)return;this.processing=!0;try{if(await this.queueProcessor.processBatch()>0)this.lastActiveAt=Date.now()}catch{}finally{this.processing=!1}},this.pollIntervalMs)}stop(){if(this.timer)clearInterval(this.timer),this.timer=null}get isRunning(){return this.timer!==null}get idleMs(){return Date.now()-this.lastActiveAt}get shouldAutoExit(){return this.idleMs>=60000&&!process.send}handleMessage(J){if(J==="SHUTDOWN")this.stop();else if(J==="PROCESS_NOW"){if(!this.processing)this.processing=!0,this.queueProcessor.processBatch().then((X)=>{if(X>0)this.lastActiveAt=Date.now()}).catch(()=>{}).finally(()=>{this.processing=!1})}}}import{Database as NJ}from"bun:sqlite";import{existsSync as g,mkdirSync as JX,unlinkSync as FJ}from"fs";import*as LJ from"sqlite-vec";class I{db;dbPath;_hasVectorExtension=!1;static enableExtensionSupport(){let J=["/opt/homebrew/opt/sqlite/lib/libsqlite3.dylib","/usr/local/opt/sqlite/lib/libsqlite3.dylib"];for(let X of J)try{if(g(X))return NJ.setCustomSQLite(X),!0}catch{return!1}return!1}constructor(J){this.dbPath=J,this.db=this.open(J),this.configure()}open(J){let X=J.lastIndexOf("/");if(X>0){let $=J.substring(0,X);JX($,{recursive:!0})}return new NJ(J,{create:!0})}configure(){try{this.applyPragmas(),this.loadExtensions()}catch(J){console.warn("[open-mem] Database configure failed, attempting recovery by removing WAL/SHM files:",J.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(X){console.warn("[open-mem] WAL/SHM cleanup insufficient, recreating database from scratch:",X.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($){throw console.warn("[open-mem] All recovery attempts failed, filesystem may be broken:",$.message),J}}}}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{LJ.load(this.db),this._hasVectorExtension=!0}catch{this._hasVectorExtension=!1}}get hasVectorExtension(){return this._hasVectorExtension}deleteSidecarFiles(){for(let J of["-wal","-shm"]){let X=this.dbPath+J;try{if(g(X))FJ(X)}catch{}}}deleteDatabaseFiles(){this.deleteSidecarFiles();try{if(g(this.dbPath))FJ(this.dbPath)}catch{}}ensureMigrationTable(){this.db.exec(`
|
|
142
|
+
[... truncated ...]`:X,H=YJ(J,Z,$),Y=2;for(let V=0;V<=Y;V++)try{if(this.config.provider==="google")await D(this.config.model,this.config.rateLimitingEnabled);let{text:W}=await this._generate({model:this.model,maxOutputTokens:this.config.maxTokensPerCompression,prompt:H}),K=$J(W);if(K)K.discoveryTokens=Q;return K}catch(W){if(L(W)&&V<Y){let K=2**V*1000;await R(K);continue}return null}return null}async compressBatch(J){let X=new Map;for(let $=0;$<J.length;$++){let Q=J[$],Z=await this.compress(Q.toolName,Q.toolOutput,Q.sessionContext);if(X.set(Q.callId,Z),$<J.length-1)await R(200)}return X}createFallbackObservation(J,X){let $=dJ(X),Q=lJ[J]??"discovery";return{type:Q,title:`${J} execution`,subtitle:X.substring(0,100).replace(/\n/g," "),facts:[],narrative:`Tool ${J} was executed. Output length: ${X.length} chars.`,concepts:[],filesRead:Q==="discovery"?$:[],filesModified:Q==="change"?$:[],discoveryTokens:O(X),importance:2}}async isAvailable(){if(!this.model)return!1;try{return await this._generate({model:this.model,maxOutputTokens:10,prompt:"ping"}),!0}catch{return!1}}}var lJ={Read:"discovery",Write:"change",Edit:"change",Bash:"change",Glob:"discovery",Grep:"discovery"},cJ=/(?:^|\s)((?:\.\/|\/|src\/|tests\/|lib\/)\S+\.\w+)/gm;function dJ(J){let X=[];for(let $ of J.matchAll(cJ))X.push($[1]);return[...new Set(X)]}import{generateText as nJ}from"ai";class f{model;config;_generate=nJ;constructor(J){if(this.config=J,this.model=null,J.provider==="bedrock"||J.apiKey)try{this.model=j({provider:J.provider,model:J.model,apiKey:J.apiKey},S(J))}catch{}}async evaluate(J,X){if(!this.model||X.length===0)return null;let $=WJ(J,X),Q=2;for(let Z=0;Z<=Q;Z++)try{if(this.config.provider==="google")await D(this.config.model,this.config.rateLimitingEnabled);let{text:H}=await this._generate({model:this.model,maxOutputTokens:512,prompt:$});return ZJ(H)}catch(H){if(L(H)&&Z<Q){let Y=2**Z*1000;await R(Y);continue}return null}return null}}import{generateText as sJ}from"ai";class u{model;config;_generate=sJ;constructor(J){if(this.config=J,this.model=null,J.provider==="bedrock"||J.apiKey)try{this.model=j({provider:J.provider,model:J.model,apiKey:J.apiKey},S(J))}catch{}}async extract(J){if(!this.model)return null;let X=KJ(J),$=2;for(let Q=0;Q<=$;Q++)try{if(this.config.provider==="google")await D(this.config.model,this.config.rateLimitingEnabled);let{text:Z}=await this._generate({model:this.model,maxOutputTokens:1024,prompt:X});return HJ(Z)}catch(Z){if(L(Z)&&Q<$){let H=2**Q*1000;await R(H);continue}return null}return null}}import{generateText as iJ}from"ai";class b{model;config;_generate=iJ;constructor(J){this.config=J,this.model=null;let X=J.provider!=="bedrock";if(J.compressionEnabled&&(!X||J.apiKey))try{this.model=j({provider:J.provider,model:J.model,apiKey:J.apiKey},S(J))}catch{}}async summarize(J,X){if(X.length===0)return null;if(!this.config.compressionEnabled||!this.model)return this.createFallbackSummary(X);let $=VJ(X.map((Q)=>({type:Q.type,title:Q.title,narrative:Q.narrative})),J);try{if(this.config.provider==="google")await D(this.config.model,this.config.rateLimitingEnabled);let{text:Q}=await this._generate({model:this.model,maxOutputTokens:this.config.maxTokensPerCompression,prompt:$}),Z=QJ(Q);if(!Z)return this.createFallbackSummary(X);return Z}catch{return this.createFallbackSummary(X)}}createFallbackSummary(J){let X=new Set,$=new Set,Q=[];for(let V of J){for(let W of V.filesModified)X.add(W);for(let W of V.concepts)$.add(W);if(V.type==="decision")Q.push(V.title)}let Z=new Map;for(let V of J)Z.set(V.type,(Z.get(V.type)??0)+1);let H=Array.from(Z.entries()).map(([V,W])=>`${W} ${V}${W>1?"s":""}`).join(", "),Y=Array.from($).slice(0,5).join(", ");return{summary:`Session with ${J.length} observations: ${H}. Files modified: ${X.size}. Key concepts: ${Y}.`,keyDecisions:Q.slice(0,5),filesModified:Array.from(X),concepts:Array.from($)}}shouldSummarize(J){return J>=2}}import{existsSync as eJ,readFileSync as JX}from"fs";import{existsSync as aJ,readdirSync as rJ,readFileSync as tJ}from"fs";import{join as UJ}from"path";var g=UJ(import.meta.dir,"."),T=null;function oJ(){if(T)return T;if(T=new Map,!aJ(g))return T;for(let J of rJ(g)){if(!J.endsWith(".json"))continue;try{let X=tJ(UJ(g,J),"utf-8"),$=JSON.parse(X);if($.id&&$.observationTypes&&$.conceptVocabulary)T.set($.id,$)}catch{}}return T}function NJ(){return[...oJ().keys()].sort()}var XX={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,folderContextMode:"dispersed",folderContextFilename:"AGENTS.md",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,fallbackProviders:void 0,mode:"code"};function $X(){let J={};if(process.env.OPEN_MEM_DB_PATH)J.dbPath=process.env.OPEN_MEM_DB_PATH;if(process.env.OPEN_MEM_PROVIDER)J.provider=process.env.OPEN_MEM_PROVIDER;if(process.env.OPEN_MEM_MODEL)J.model=process.env.OPEN_MEM_MODEL;if(process.env.OPEN_MEM_MAX_CONTEXT_TOKENS)J.maxContextTokens=Number.parseInt(process.env.OPEN_MEM_MAX_CONTEXT_TOKENS,10);if(process.env.OPEN_MEM_COMPRESSION==="false")J.compressionEnabled=!1;if(process.env.OPEN_MEM_CONTEXT_INJECTION==="false")J.contextInjectionEnabled=!1;if(process.env.OPEN_MEM_IGNORED_TOOLS)J.ignoredTools=process.env.OPEN_MEM_IGNORED_TOOLS.split(",").map((X)=>X.trim());if(process.env.OPEN_MEM_BATCH_SIZE)J.batchSize=Number.parseInt(process.env.OPEN_MEM_BATCH_SIZE,10);if(process.env.OPEN_MEM_RETENTION_DAYS)J.retentionDays=Number.parseInt(process.env.OPEN_MEM_RETENTION_DAYS,10);if(process.env.OPEN_MEM_LOG_LEVEL)J.logLevel=process.env.OPEN_MEM_LOG_LEVEL;if(process.env.OPEN_MEM_CONTEXT_SHOW_TOKEN_COSTS==="false")J.contextShowTokenCosts=!1;if(process.env.OPEN_MEM_CONTEXT_TYPES)J.contextObservationTypes=process.env.OPEN_MEM_CONTEXT_TYPES==="all"?"all":process.env.OPEN_MEM_CONTEXT_TYPES.split(",").map((X)=>X.trim());if(process.env.OPEN_MEM_CONTEXT_FULL_COUNT)J.contextFullObservationCount=Number.parseInt(process.env.OPEN_MEM_CONTEXT_FULL_COUNT,10);if(process.env.OPEN_MEM_MAX_OBSERVATIONS)J.maxObservations=Number.parseInt(process.env.OPEN_MEM_MAX_OBSERVATIONS,10);if(process.env.OPEN_MEM_CONTEXT_SHOW_LAST_SUMMARY==="false")J.contextShowLastSummary=!1;if(process.env.OPEN_MEM_RATE_LIMITING==="false")J.rateLimitingEnabled=!1;if(process.env.OPEN_MEM_FOLDER_CONTEXT==="false")J.folderContextEnabled=!1;if(process.env.OPEN_MEM_FOLDER_CONTEXT_MAX_DEPTH)J.folderContextMaxDepth=Number.parseInt(process.env.OPEN_MEM_FOLDER_CONTEXT_MAX_DEPTH,10);if(process.env.OPEN_MEM_FOLDER_CONTEXT_MODE==="single")J.folderContextMode="single";if(process.env.OPEN_MEM_FOLDER_CONTEXT_MODE==="dispersed")J.folderContextMode="dispersed";if(process.env.OPEN_MEM_FOLDER_CONTEXT_FILENAME)J.folderContextFilename=process.env.OPEN_MEM_FOLDER_CONTEXT_FILENAME;if(process.env.OPEN_MEM_DAEMON==="true")J.daemonEnabled=!0;if(process.env.OPEN_MEM_DASHBOARD==="true")J.dashboardEnabled=!0;if(process.env.OPEN_MEM_DASHBOARD_PORT)J.dashboardPort=Number.parseInt(process.env.OPEN_MEM_DASHBOARD_PORT,10);if(process.env.OPEN_MEM_PLATFORM_OPENCODE==="false")J.platformOpenCodeEnabled=!1;if(process.env.OPEN_MEM_PLATFORM_CLAUDE_CODE==="true")J.platformClaudeCodeEnabled=!0;if(process.env.OPEN_MEM_PLATFORM_CURSOR==="true")J.platformCursorEnabled=!0;if(process.env.OPEN_MEM_MCP_COMPAT_MODE)J.mcpCompatibilityMode=process.env.OPEN_MEM_MCP_COMPAT_MODE;if(process.env.OPEN_MEM_MCP_PROTOCOL_VERSION)J.mcpProtocolVersion=process.env.OPEN_MEM_MCP_PROTOCOL_VERSION;if(process.env.OPEN_MEM_MCP_SUPPORTED_PROTOCOLS)J.mcpSupportedProtocolVersions=process.env.OPEN_MEM_MCP_SUPPORTED_PROTOCOLS.split(",").map((X)=>X.trim()).filter(Boolean);if(process.env.OPEN_MEM_EMBEDDING_DIMENSION)J.embeddingDimension=Number.parseInt(process.env.OPEN_MEM_EMBEDDING_DIMENSION,10);if(process.env.OPEN_MEM_CONFLICT_RESOLUTION==="true")J.conflictResolutionEnabled=!0;if(process.env.OPEN_MEM_CONFLICT_BAND_LOW){let X=Number.parseFloat(process.env.OPEN_MEM_CONFLICT_BAND_LOW);if(!Number.isNaN(X))J.conflictSimilarityBandLow=X}if(process.env.OPEN_MEM_CONFLICT_BAND_HIGH){let X=Number.parseFloat(process.env.OPEN_MEM_CONFLICT_BAND_HIGH);if(!Number.isNaN(X))J.conflictSimilarityBandHigh=X}if(process.env.OPEN_MEM_USER_MEMORY==="true")J.userMemoryEnabled=!0;if(process.env.OPEN_MEM_USER_MEMORY_DB_PATH)J.userMemoryDbPath=process.env.OPEN_MEM_USER_MEMORY_DB_PATH;if(process.env.OPEN_MEM_USER_MEMORY_MAX_TOKENS)J.userMemoryMaxContextTokens=Number.parseInt(process.env.OPEN_MEM_USER_MEMORY_MAX_TOKENS,10);if(process.env.OPEN_MEM_RERANKING==="true")J.rerankingEnabled=!0;if(process.env.OPEN_MEM_RERANKING_MAX_CANDIDATES)J.rerankingMaxCandidates=Number.parseInt(process.env.OPEN_MEM_RERANKING_MAX_CANDIDATES,10);if(process.env.OPEN_MEM_ENTITY_EXTRACTION==="true")J.entityExtractionEnabled=!0;if(process.env.OPEN_MEM_FALLBACK_PROVIDERS)J.fallbackProviders=process.env.OPEN_MEM_FALLBACK_PROVIDERS.split(",").map((X)=>X.trim()).filter(Boolean);if(process.env.OPEN_MEM_MODE)J.mode=process.env.OPEN_MEM_MODE;return J}function QX(J){let X=`${J}/.open-mem/config.json`;if(!eJ(X))return{};try{let $=JX(X,"utf-8"),Q=JSON.parse($);if(!Q||typeof Q!=="object"||Array.isArray(Q))return{};return Q}catch{return{}}}function ZX(J){switch(J){case"google":return 768;case"openai":return 1536;case"bedrock":return 1024;case"anthropic":return 0;case"openrouter":return 0;default:return 768}}function _J(J,X){let $=QX(J),Q=$X(),Z={...XX,...$,...Q,...X};if(!Z.dbPath.startsWith("/"))Z.dbPath=`${J}/${Z.dbPath}`;if(!process.env.OPEN_MEM_PROVIDER&&!X?.provider){if(process.env.GOOGLE_GENERATIVE_AI_API_KEY||process.env.GEMINI_API_KEY)Z.provider="google";else if(process.env.ANTHROPIC_API_KEY)Z.provider="anthropic";else if(process.env.AWS_BEARER_TOKEN_BEDROCK||process.env.AWS_ACCESS_KEY_ID||process.env.AWS_PROFILE)Z.provider="bedrock";else if(process.env.OPENROUTER_API_KEY)Z.provider="openrouter"}if(!Z.apiKey)switch(Z.provider){case"google":Z.apiKey=process.env.GOOGLE_GENERATIVE_AI_API_KEY||process.env.GEMINI_API_KEY;break;case"anthropic":Z.apiKey=process.env.ANTHROPIC_API_KEY;break;case"openai":Z.apiKey=process.env.OPENAI_API_KEY;break;case"openrouter":Z.apiKey=process.env.OPENROUTER_API_KEY;break;case"bedrock":break}if(Z.provider==="openrouter"&&Z.model==="gemini-2.5-flash-lite")Z.model="google/gemini-2.5-flash-lite";if(Z.embeddingDimension===void 0)Z.embeddingDimension=ZX(Z.provider);if(Z.mode&&!NJ().includes(Z.mode))Z.mode="code";return Z}import{existsSync as j2,mkdirSync as HX,readFileSync as D2,unlinkSync as YX,writeFileSync as VX}from"fs";function FJ(J){let X=J.lastIndexOf("/");if(X>0){let $=J.substring(0,X);HX($,{recursive:!0})}VX(J,String(process.pid),"utf-8")}function LJ(J){try{YX(J)}catch{}}function MJ(J){let X=J.lastIndexOf("/");if(X>=0)return`${J.substring(0,X)}/worker.pid`;return"worker.pid"}class m{queueProcessor;pollIntervalMs;timer=null;lastActiveAt=Date.now();processing=!1;constructor(J){this.queueProcessor=J.queueProcessor,this.pollIntervalMs=J.pollIntervalMs}start(){if(this.timer)return;this.lastActiveAt=Date.now(),this.timer=setInterval(async()=>{if(this.processing)return;this.processing=!0;try{if(await this.queueProcessor.processBatch()>0)this.lastActiveAt=Date.now()}catch{}finally{this.processing=!1}},this.pollIntervalMs)}stop(){if(this.timer)clearInterval(this.timer),this.timer=null}get isRunning(){return this.timer!==null}get idleMs(){return Date.now()-this.lastActiveAt}get shouldAutoExit(){return this.idleMs>=60000&&!process.send}handleMessage(J){if(J==="SHUTDOWN")this.stop();else if(J==="PROCESS_NOW"){if(!this.processing)this.processing=!0,this.queueProcessor.processBatch().then((X)=>{if(X>0)this.lastActiveAt=Date.now()}).catch(()=>{}).finally(()=>{this.processing=!1})}}}import{Database as AJ}from"bun:sqlite";import{existsSync as p,mkdirSync as WX,unlinkSync as SJ}from"fs";import*as jJ from"sqlite-vec";class h{db;dbPath;_hasVectorExtension=!1;static enableExtensionSupport(){let J=["/opt/homebrew/opt/sqlite/lib/libsqlite3.dylib","/usr/local/opt/sqlite/lib/libsqlite3.dylib"];for(let X of J)try{if(p(X))return AJ.setCustomSQLite(X),!0}catch{return!1}return!1}constructor(J){this.dbPath=J,this.db=this.open(J),this.configure()}open(J){let X=J.lastIndexOf("/");if(X>0){let $=J.substring(0,X);WX($,{recursive:!0})}return new AJ(J,{create:!0})}configure(){try{this.applyPragmas(),this.loadExtensions()}catch(J){console.warn("[open-mem] Database configure failed, attempting recovery by removing WAL/SHM files:",J.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(X){console.warn("[open-mem] WAL/SHM cleanup insufficient, recreating database from scratch:",X.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($){throw console.warn("[open-mem] All recovery attempts failed, filesystem may be broken:",$.message),J}}}}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{jJ.load(this.db),this._hasVectorExtension=!0}catch{this._hasVectorExtension=!1}}get hasVectorExtension(){return this._hasVectorExtension}deleteSidecarFiles(){for(let J of["-wal","-shm"]){let X=this.dbPath+J;try{if(p(X))SJ(X)}catch{}}}deleteDatabaseFiles(){this.deleteSidecarFiles();try{if(p(this.dbPath))SJ(this.dbPath)}catch{}}ensureMigrationTable(){this.db.exec(`
|
|
148
143
|
CREATE TABLE IF NOT EXISTS _migrations (
|
|
149
144
|
version INTEGER PRIMARY KEY,
|
|
150
145
|
name TEXT NOT NULL,
|
|
151
146
|
applied_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
152
147
|
)
|
|
153
|
-
`)}migrate(J){this.ensureMigrationTable();let X=this.db.query("SELECT version FROM _migrations ORDER BY version").all(),$=new Set(X.map((Z)=>Z.version)),Q=J.filter((Z)=>!$.has(Z.version)).sort((Z,
|
|
148
|
+
`)}migrate(J){this.ensureMigrationTable();let X=this.db.query("SELECT version FROM _migrations ORDER BY version").all(),$=new Set(X.map((Z)=>Z.version)),Q=J.filter((Z)=>!$.has(Z.version)).sort((Z,H)=>Z.version-H.version);for(let Z of Q)this.db.transaction(()=>{this.db.exec(Z.up),this.db.query("INSERT INTO _migrations (version, name) VALUES ($version, $name)").run({$version:Z.version,$name:Z.name})})()}run(J,X){let $=this.db.query(J);if(X)$.run(...X);else $.run()}get(J,X){let $=this.db.query(J);return X?$.get(...X):$.get()}all(J,X){let $=this.db.query(J);return X?$.all(...X):$.all()}exec(J){this.db.exec(J)}transaction(J){return this.db.transaction(J)()}close(){this.db.close()}get isOpen(){try{return this.db.query("SELECT 1").get(),!0}catch{return!1}}get raw(){return this.db}}function DJ(J){return new h(J)}import{randomUUID as EJ}from"crypto";class l{db;constructor(J){this.db=J}upsertEntity(J,X){let $=EJ(),Q=new Date().toISOString();this.db.run(`INSERT INTO entities (id, name, entity_type, first_seen_at, last_seen_at, mention_count)
|
|
154
149
|
VALUES (?, ?, ?, ?, ?, 1)
|
|
155
150
|
ON CONFLICT(name, entity_type) DO UPDATE SET
|
|
156
151
|
mention_count = mention_count + 1,
|
|
157
|
-
last_seen_at = ?`,[$,J,X,Q,Q,Q]);let Z=this.db.get("SELECT * FROM entities WHERE name = ? AND entity_type = ?",[J,X]);if(!Z)throw Error(`Failed to upsert entity: ${J} (${X})`);return this.mapEntityRow(Z)}createRelation(J,X,$,Q){let Z=
|
|
152
|
+
last_seen_at = ?`,[$,J,X,Q,Q,Q]);let Z=this.db.get("SELECT * FROM entities WHERE name = ? AND entity_type = ?",[J,X]);if(!Z)throw Error(`Failed to upsert entity: ${J} (${X})`);return this.mapEntityRow(Z)}createRelation(J,X,$,Q){let Z=EJ(),H=new Date().toISOString();try{this.db.run(`INSERT OR IGNORE INTO entity_relations
|
|
158
153
|
(id, source_entity_id, target_entity_id, relationship, observation_id, created_at)
|
|
159
|
-
VALUES (?, ?, ?, ?, ?, ?)`,[Z,J,X,$,Q,
|
|
160
|
-
WHERE source_entity_id = ? AND target_entity_id = ? AND relationship = ?`,[J,X,$]);return
|
|
154
|
+
VALUES (?, ?, ?, ?, ?, ?)`,[Z,J,X,$,Q,H])}catch{return null}let Y=this.db.get(`SELECT * FROM entity_relations
|
|
155
|
+
WHERE source_entity_id = ? AND target_entity_id = ? AND relationship = ?`,[J,X,$]);return Y?this.mapRelationRow(Y):null}linkObservation(J,X){this.db.run("INSERT OR IGNORE INTO entity_observations (entity_id, observation_id) VALUES (?, ?)",[J,X])}findByName(J){try{return this.db.all(`SELECT e.*
|
|
161
156
|
FROM entities e
|
|
162
157
|
JOIN entities_fts fts ON e._rowid = fts.rowid
|
|
163
158
|
WHERE entities_fts MATCH ?
|
|
164
159
|
ORDER BY rank`,[J]).map(($)=>this.mapEntityRow($))}catch{return[]}}getRelationsFor(J){return this.db.all(`SELECT * FROM entity_relations
|
|
165
|
-
WHERE source_entity_id = ? OR target_entity_id = ?`,[J,J]).map(($)=>this.mapRelationRow($))}traverseRelations(J,X=1){let $=Math.min(X,2),Q=100,Z=new Set,
|
|
166
|
-
`)}function
|
|
160
|
+
WHERE source_entity_id = ? OR target_entity_id = ?`,[J,J]).map(($)=>this.mapRelationRow($))}traverseRelations(J,X=1){let $=Math.min(X,2),Q=100,Z=new Set,H=[{id:J,currentDepth:0}];Z.add(J);while(H.length>0){if(Z.size>=100)break;let Y=H.shift();if(!Y)continue;if(Y.currentDepth>=$)continue;let V=this.getRelationsFor(Y.id);for(let W of V){let K=W.sourceEntityId===Y.id?W.targetEntityId:W.sourceEntityId;if(!Z.has(K))Z.add(K),H.push({id:K,currentDepth:Y.currentDepth+1})}}return Z}getObservationsForEntity(J){return this.db.all("SELECT observation_id FROM entity_observations WHERE entity_id = ?",[J]).map(($)=>$.observation_id)}getById(J){let X=this.db.get("SELECT * FROM entities WHERE id = ?",[J]);return X?this.mapEntityRow(X):null}mapEntityRow(J){return{id:J.id,name:J.name,entityType:J.entity_type,firstSeenAt:J.first_seen_at,lastSeenAt:J.last_seen_at,mentionCount:J.mention_count}}mapRelationRow(J){return{id:J.id,sourceEntityId:J.source_entity_id,targetEntityId:J.target_entity_id,relationship:J.relationship,observationId:J.observation_id,createdAt:J.created_at}}}import{randomUUID as zX}from"crypto";import{embed as KX}from"ai";async function c(J,X){try{let{embedding:$}=await KX({model:J,value:X});return $}catch{return null}}function RJ(J,X){if(J.length!==X.length||J.length===0)return 0;let $=0,Q=0,Z=0;for(let Y=0;Y<J.length;Y++)$+=J[Y]*X[Y],Q+=J[Y]*J[Y],Z+=X[Y]*X[Y];let H=Math.sqrt(Q)*Math.sqrt(Z);if(H===0)return 0;return $/H}function d(J){let X=[J.title,J.narrative];if(J.concepts.length>0)X.push(J.concepts.join(", "));return X.join(`
|
|
161
|
+
`)}function GX(J){return J.replace(/[%_\\]/g,"\\$&")}class n{db;constructor(J){this.db=J}create(J){let X=zX(),$=new Date().toISOString(),Q=J.discoveryTokens??0,Z=J.importance??3,H=J.scope??"project";return this.db.run(`INSERT INTO observations
|
|
167
162
|
(id, session_id, scope, type, title, subtitle, facts, narrative,
|
|
168
163
|
concepts, files_read, files_modified, raw_tool_output,
|
|
169
164
|
tool_name, created_at, token_count, discovery_tokens, importance, revision_of, deleted_at)
|
|
170
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,[X,J.sessionId,
|
|
165
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,[X,J.sessionId,H,J.type,J.title,J.subtitle,JSON.stringify(J.facts),J.narrative,JSON.stringify(J.concepts),JSON.stringify(J.filesRead),JSON.stringify(J.filesModified),J.rawToolOutput,J.toolName,$,J.tokenCount,Q,Z,null,null]),{...J,id:X,scope:H,createdAt:$,discoveryTokens:Q,importance:Z,revisionOf:null,deletedAt:null,supersededBy:null,supersededAt:null}}importObservation(J){this.db.run(`INSERT INTO observations
|
|
171
166
|
(id, session_id, scope, type, title, subtitle, facts, narrative,
|
|
172
167
|
concepts, files_read, files_modified, raw_tool_output,
|
|
173
168
|
tool_name, created_at, token_count, discovery_tokens, importance, revision_of, deleted_at)
|
|
@@ -182,23 +177,23 @@ Respond with EXACTLY this XML format:
|
|
|
182
177
|
WHERE s.project_path = ? AND o.created_at < ?
|
|
183
178
|
AND o.superseded_by IS NULL AND o.deleted_at IS NULL
|
|
184
179
|
ORDER BY o.created_at DESC
|
|
185
|
-
LIMIT ?`,[Q,J,X]).reverse():[],
|
|
180
|
+
LIMIT ?`,[Q,J,X]).reverse():[],H=$>0?this.db.all(`SELECT o.*
|
|
186
181
|
FROM observations o
|
|
187
182
|
JOIN sessions s ON o.session_id = s.id
|
|
188
183
|
WHERE s.project_path = ? AND o.created_at > ?
|
|
189
184
|
AND o.superseded_by IS NULL AND o.deleted_at IS NULL
|
|
190
185
|
ORDER BY o.created_at ASC
|
|
191
|
-
LIMIT ?`,[Q,J,$]):[];return[...Z,...
|
|
186
|
+
LIMIT ?`,[Q,J,$]):[];return[...Z,...H].map((Y)=>this.mapRow(Y))}listByProject(J,X={}){let{limit:$=50,offset:Q=0,type:Z,state:H,sessionId:Y}=X,V=`SELECT o.*
|
|
192
187
|
FROM observations o
|
|
193
188
|
JOIN sessions s ON o.session_id = s.id
|
|
194
|
-
WHERE s.project_path = ?`,W=[J];if(
|
|
189
|
+
WHERE s.project_path = ?`,W=[J];if(Y)V+=" AND o.session_id = ?",W.push(Y);if(Z)V+=" AND o.type = ?",W.push(Z);if(H==="current")V+=" AND o.superseded_by IS NULL AND o.deleted_at IS NULL";else if(H==="superseded")V+=" AND o.superseded_by IS NOT NULL AND o.deleted_at IS NULL";else if(H==="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 ?",W.push($,Q),this.db.all(V,W).map((K)=>this.mapRow(K))}search(J){let X=!!J.projectPath,$=`
|
|
195
190
|
SELECT o.*, rank
|
|
196
191
|
FROM observations o
|
|
197
192
|
JOIN observations_fts fts ON o._rowid = fts.rowid
|
|
198
193
|
${X?"JOIN sessions s ON o.session_id = s.id":""}
|
|
199
194
|
WHERE observations_fts MATCH ? AND o.superseded_by IS NULL AND o.deleted_at IS NULL
|
|
200
|
-
`,Q=[J.query];if(X&&J.projectPath)$+=" AND s.project_path = ?",Q.push(J.projectPath);if(J.sessionId)$+=" AND o.session_id = ?",Q.push(J.sessionId);if(J.type)$+=" AND o.type = ?",Q.push(J.type);if(J.importanceMin!==void 0)$+=" AND o.importance >= ?",Q.push(J.importanceMin);if(J.importanceMax!==void 0)$+=" AND o.importance <= ?",Q.push(J.importanceMax);if(J.createdAfter)$+=" AND o.created_at >= ?",Q.push(J.createdAfter);if(J.createdBefore)$+=" AND o.created_at <= ?",Q.push(J.createdBefore);if(J.concepts&&J.concepts.length>0){let Z=J.concepts.map(()=>"EXISTS (SELECT 1 FROM json_each(o.concepts) WHERE LOWER(value) = LOWER(?))");$+=` AND (${Z.join(" OR ")})`;for(let
|
|
201
|
-
OR EXISTS (SELECT 1 FROM json_each(o.files_modified) WHERE LOWER(value) LIKE LOWER(?) ESCAPE '\\'))`);$+=` AND (${Z.join(" OR ")})`;for(let
|
|
195
|
+
`,Q=[J.query];if(X&&J.projectPath)$+=" AND s.project_path = ?",Q.push(J.projectPath);if(J.sessionId)$+=" AND o.session_id = ?",Q.push(J.sessionId);if(J.type)$+=" AND o.type = ?",Q.push(J.type);if(J.importanceMin!==void 0)$+=" AND o.importance >= ?",Q.push(J.importanceMin);if(J.importanceMax!==void 0)$+=" AND o.importance <= ?",Q.push(J.importanceMax);if(J.createdAfter)$+=" AND o.created_at >= ?",Q.push(J.createdAfter);if(J.createdBefore)$+=" AND o.created_at <= ?",Q.push(J.createdBefore);if(J.concepts&&J.concepts.length>0){let Z=J.concepts.map(()=>"EXISTS (SELECT 1 FROM json_each(o.concepts) WHERE LOWER(value) = LOWER(?))");$+=` AND (${Z.join(" OR ")})`;for(let H of J.concepts)Q.push(H)}if(J.files&&J.files.length>0){let Z=J.files.map(()=>`(EXISTS (SELECT 1 FROM json_each(o.files_read) WHERE LOWER(value) LIKE LOWER(?) ESCAPE '\\')
|
|
196
|
+
OR EXISTS (SELECT 1 FROM json_each(o.files_modified) WHERE LOWER(value) LIKE LOWER(?) ESCAPE '\\'))`);$+=` AND (${Z.join(" OR ")})`;for(let H of J.files){let Y=`%${GX(H)}%`;Q.push(Y,Y)}}return $+=" ORDER BY rank LIMIT ? OFFSET ?",Q.push(J.limit??10),Q.push(J.offset??0),this.db.all($,Q).map((Z)=>({observation:this.mapRow(Z),rank:Z.rank,snippet:Z.title}))}searchByConcept(J,X=10,$){let Q=!!$,Z=`SELECT o.*
|
|
202
197
|
FROM observations o
|
|
203
198
|
JOIN observations_fts fts ON o._rowid = fts.rowid
|
|
204
199
|
${Q?"JOIN sessions s ON o.session_id = s.id":""}
|
|
@@ -206,7 +201,7 @@ Respond with EXACTLY this XML format:
|
|
|
206
201
|
AND o.superseded_by IS NULL AND o.deleted_at IS NULL
|
|
207
202
|
${Q?"AND s.project_path = ?":""}
|
|
208
203
|
ORDER BY rank
|
|
209
|
-
LIMIT ?`,
|
|
204
|
+
LIMIT ?`,H=[`concepts:${J}`];if(Q&&$)H.push($);return H.push(X),this.db.all(Z,H).map((Y)=>this.mapRow(Y))}searchByFile(J,X=10,$){let Q=!!$,Z=`SELECT o.*
|
|
210
205
|
FROM observations o
|
|
211
206
|
JOIN observations_fts fts ON o._rowid = fts.rowid
|
|
212
207
|
${Q?"JOIN sessions s ON o.session_id = s.id":""}
|
|
@@ -214,7 +209,7 @@ Respond with EXACTLY this XML format:
|
|
|
214
209
|
AND o.superseded_by IS NULL AND o.deleted_at IS NULL
|
|
215
210
|
${Q?"AND s.project_path = ?":""}
|
|
216
211
|
ORDER BY rank
|
|
217
|
-
LIMIT ?`,
|
|
212
|
+
LIMIT ?`,H=[`files_read:"${J.replace(/"/g,'""')}" OR files_modified:"${J.replace(/"/g,'""')}"`];if(Q&&$)H.push($);return H.push(X),this.db.all(Z,H).map((Y)=>this.mapRow(Y))}setEmbedding(J,X){this.db.run("UPDATE observations SET embedding = ? WHERE id = ?",[JSON.stringify(X),J])}getWithEmbeddings(J,X){return this.db.all(`SELECT o.id, o.embedding, o.title
|
|
218
213
|
FROM observations o
|
|
219
214
|
JOIN sessions s ON o.session_id = s.id
|
|
220
215
|
WHERE s.project_path = ? AND o.embedding IS NOT NULL AND o.superseded_by IS NULL AND o.deleted_at IS NULL
|
|
@@ -222,14 +217,14 @@ Respond with EXACTLY this XML format:
|
|
|
222
217
|
LIMIT ?`,[J,X]).map(($)=>{try{return{id:$.id,embedding:JSON.parse($.embedding),title:$.title}}catch{return null}}).filter(($)=>$!==null)}findSimilar(J,X,$,Q){let Z=this.db.all(`SELECT id, embedding FROM observations
|
|
223
218
|
WHERE embedding IS NOT NULL AND type = ? AND superseded_by IS NULL AND deleted_at IS NULL
|
|
224
219
|
ORDER BY created_at DESC
|
|
225
|
-
LIMIT 200`,[X]),
|
|
220
|
+
LIMIT 200`,[X]),H=[];for(let Y of Z)try{let V=JSON.parse(Y.embedding);if(!Array.isArray(V)||V.length!==J.length)continue;let W=RJ(J,V);if(W>=$)H.push({id:Y.id,similarity:W})}catch{}return H.sort((Y,V)=>V.similarity-Y.similarity).slice(0,Q)}insertVecEmbedding(J,X){let $=new Float32Array(X);this.db.run("BEGIN");try{this.db.run("DELETE FROM observation_embeddings WHERE observation_id = ?",[J]),this.db.run("INSERT INTO observation_embeddings (observation_id, embedding) VALUES (?, ?)",[J,$]),this.db.run("COMMIT")}catch(Q){throw this.db.run("ROLLBACK"),Q}}migrateExistingEmbeddings(J){let X=this.db.all("SELECT id, embedding FROM observations WHERE embedding IS NOT NULL"),$=0,Q=0;for(let Z of X)try{let H=JSON.parse(Z.embedding);if(!Array.isArray(H)||H.length!==J){Q++;continue}this.insertVecEmbedding(Z.id,H),$++}catch{Q++}return{migrated:$,skipped:Q}}getVecEmbeddingMatches(J,X){try{let $=new Float32Array(J);return this.db.all(`SELECT observation_id, distance
|
|
226
221
|
FROM observation_embeddings
|
|
227
|
-
WHERE embedding MATCH ? AND k = ?`,[$,X]).map((Q)=>({observationId:Q.observation_id,distance:Q.distance}))}catch{return[]}}searchVecSubset(J,X,$){if(X.length===0)return[];try{let Q=new Float32Array(J),Z=Math.max($*5,X.length),
|
|
222
|
+
WHERE embedding MATCH ? AND k = ?`,[$,X]).map((Q)=>({observationId:Q.observation_id,distance:Q.distance}))}catch{return[]}}searchVecSubset(J,X,$){if(X.length===0)return[];try{let Q=new Float32Array(J),Z=Math.max($*5,X.length),H=this.db.all(`SELECT observation_id, distance
|
|
228
223
|
FROM observation_embeddings
|
|
229
|
-
WHERE embedding MATCH ? AND k = ?`,[Q,Z]),
|
|
224
|
+
WHERE embedding MATCH ? AND k = ?`,[Q,Z]),Y=new Set(X);return H.filter((V)=>Y.has(V.observation_id)).slice(0,$).map((V)=>({observationId:V.observation_id,distance:V.distance}))}catch{return[]}}update(J,X){let $=this.getById(J);if(!$)return null;if(Object.keys(X).length===0)return $;let Q=this.create({sessionId:$.sessionId,scope:$.scope??"project",type:X.type??$.type,title:X.title??$.title,subtitle:X.subtitle??$.subtitle,facts:X.facts??$.facts,narrative:X.narrative??$.narrative,concepts:X.concepts??$.concepts,filesRead:X.filesRead??$.filesRead,filesModified:X.filesModified??$.filesModified,rawToolOutput:$.rawToolOutput,toolName:"mem-revise",tokenCount:$.tokenCount,discoveryTokens:$.discoveryTokens,importance:X.importance??$.importance});return this.db.run("UPDATE observations SET revision_of = ? WHERE id = ?",[J,Q.id]),this.supersede(J,Q.id),this.getById(Q.id)}supersede(J,X){let $=new Date().toISOString();this.db.run("UPDATE observations SET superseded_by = ?, superseded_at = ? WHERE id = ?",[X,$,J])}delete(J){if(this.db.all("SELECT id FROM observations WHERE id = ?",[J]).length===0)return!1;let $=new Date().toISOString();return this.db.run("UPDATE observations SET deleted_at = ? WHERE id = ?",[$,J]),this.deleteEmbeddingsForObservations([J]),!0}getLineage(J){let X=this.getByIdIncludingArchived(J);if(!X)return[];let $=new Set([X.id]),Q=[X];while(Q[0].revisionOf){let Z=this.getByIdIncludingArchived(Q[0].revisionOf);if(!Z||$.has(Z.id))break;Q.unshift(Z),$.add(Z.id)}while(Q[Q.length-1].supersededBy){let Z=Q[Q.length-1].supersededBy;if(!Z)break;let H=this.getByIdIncludingArchived(Z);if(!H||$.has(H.id))break;Q.push(H),$.add(H.id)}return Q}deleteOlderThan(J){return this.db.all(`DELETE FROM observations
|
|
230
225
|
WHERE (created_at < datetime('now', '-' || ? || ' days') OR deleted_at IS NOT NULL)
|
|
231
226
|
AND session_id NOT IN (SELECT id FROM sessions WHERE status != 'completed')
|
|
232
|
-
RETURNING id`,[J]).length}deleteEmbeddingsForObservations(J){if(J.length===0)return;let X=J.map(()=>"?").join(",");try{this.db.run(`DELETE FROM observation_embeddings WHERE observation_id IN (${X})`,J)}catch{}this.db.run(`UPDATE observations SET embedding = NULL WHERE id IN (${X})`,J)}mapRow(J){return{id:J.id,sessionId:J.session_id,scope:J.scope??"project",type:J.type,title:J.title,subtitle:J.subtitle,facts:JSON.parse(J.facts),narrative:J.narrative,concepts:JSON.parse(J.concepts),filesRead:JSON.parse(J.files_read),filesModified:JSON.parse(J.files_modified),rawToolOutput:J.raw_tool_output,toolName:J.tool_name,createdAt:J.created_at,tokenCount:J.token_count,discoveryTokens:J.discovery_tokens??0,importance:J.importance??3,revisionOf:J.revision_of??null,deletedAt:J.deleted_at??null,supersededBy:J.superseded_by??null,supersededAt:J.superseded_at??null}}}import{randomUUID as
|
|
227
|
+
RETURNING id`,[J]).length}deleteEmbeddingsForObservations(J){if(J.length===0)return;let X=J.map(()=>"?").join(",");try{this.db.run(`DELETE FROM observation_embeddings WHERE observation_id IN (${X})`,J)}catch{}this.db.run(`UPDATE observations SET embedding = NULL WHERE id IN (${X})`,J)}mapRow(J){return{id:J.id,sessionId:J.session_id,scope:J.scope??"project",type:J.type,title:J.title,subtitle:J.subtitle,facts:JSON.parse(J.facts),narrative:J.narrative,concepts:JSON.parse(J.concepts),filesRead:JSON.parse(J.files_read),filesModified:JSON.parse(J.files_modified),rawToolOutput:J.raw_tool_output,toolName:J.tool_name,createdAt:J.created_at,tokenCount:J.token_count,discoveryTokens:J.discovery_tokens??0,importance:J.importance??3,revisionOf:J.revision_of??null,deletedAt:J.deleted_at??null,supersededBy:J.superseded_by??null,supersededAt:J.superseded_at??null}}}import{randomUUID as BX}from"crypto";class s{db;constructor(J){this.db=J}create(J){let X=BX(),$=new Date().toISOString();return this.db.run(`INSERT INTO pending_messages
|
|
233
228
|
(id, session_id, tool_name, tool_output, call_id, created_at)
|
|
234
229
|
VALUES (?, ?, ?, ?, ?, ?)`,[X,J.sessionId,J.toolName,J.toolOutput,J.callId,$]),{...J,id:X,createdAt:$,status:"pending",retryCount:0,error:null}}getPending(J=10){return this.db.all("SELECT * FROM pending_messages WHERE status = 'pending' ORDER BY created_at ASC LIMIT ?",[J]).map((X)=>this.mapRow(X))}getByStatus(J){return this.db.all("SELECT * FROM pending_messages WHERE status = ? ORDER BY created_at ASC",[J]).map((X)=>this.mapRow(X))}markProcessing(J){this.db.run("UPDATE pending_messages SET status = 'processing' WHERE id = ?",[J])}markCompleted(J){this.db.run("UPDATE pending_messages SET status = 'completed' WHERE id = ?",[J])}markFailed(J,X){this.db.run("UPDATE pending_messages SET status = 'failed', error = ?, retry_count = retry_count + 1 WHERE id = ?",[X,J])}resetStale(J=5){return this.db.all(`UPDATE pending_messages SET status = 'pending'
|
|
235
230
|
WHERE status = 'processing'
|
|
@@ -237,7 +232,7 @@ Respond with EXACTLY this XML format:
|
|
|
237
232
|
RETURNING id`,[`-${J}`]).length}deleteCompletedOlderThan(J){return this.db.all(`DELETE FROM pending_messages
|
|
238
233
|
WHERE status = 'completed'
|
|
239
234
|
AND created_at < datetime('now', '-' || ? || ' days')
|
|
240
|
-
RETURNING id`,[J]).length}mapRow(J){return{id:J.id,sessionId:J.session_id,toolName:J.tool_name,toolOutput:J.tool_output,callId:J.call_id,createdAt:J.created_at,status:J.status,retryCount:J.retry_count,error:J.error??null}}}var
|
|
235
|
+
RETURNING id`,[J]).length}mapRow(J){return{id:J.id,sessionId:J.session_id,toolName:J.tool_name,toolOutput:J.tool_output,callId:J.call_id,createdAt:J.created_at,status:J.status,retryCount:J.retry_count,error:J.error??null}}}var UX=[{version:1,name:"create-schema",up:`
|
|
241
236
|
-- Sessions table
|
|
242
237
|
CREATE TABLE IF NOT EXISTS sessions (
|
|
243
238
|
_rowid INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
@@ -531,11 +526,11 @@ Respond with EXACTLY this XML format:
|
|
|
531
526
|
INSERT INTO entities_fts(rowid, name, entity_type)
|
|
532
527
|
VALUES (new._rowid, new.name, new.entity_type);
|
|
533
528
|
END;
|
|
534
|
-
`}];function
|
|
529
|
+
`}];function OJ(J,X){if(J.migrate(UX),X?.hasVectorExtension&&X?.embeddingDimension&&X.embeddingDimension>0)NX(J,X.embeddingDimension)}function NX(J,X){if(J.get("SELECT name FROM sqlite_master WHERE type='table' AND name='observation_embeddings'")){let Q=J.get("SELECT value FROM _embedding_meta WHERE key = 'dimension'");if(Q&&Number(Q.value)!==X){console.warn(`[open-mem] vec0 table exists with dimension ${Q.value}, but config specifies ${X}. Drop observation_embeddings to re-create with new dimension.`);return}}else J.exec(`CREATE VIRTUAL TABLE observation_embeddings USING vec0(
|
|
535
530
|
observation_id TEXT PRIMARY KEY,
|
|
536
531
|
embedding float[${X}] distance_metric=cosine
|
|
537
|
-
)`);J.run("INSERT OR REPLACE INTO _embedding_meta (key, value) VALUES (?, ?)",["dimension",String(X)])}class
|
|
538
|
-
VALUES (?, ?, ?, 'active')`,[J,X,$]),this.getById(J)}getOrCreate(J,X){let $=this.getById(J);if($)return $;return this.create(J,X)}getById(J){let X=this.db.get("SELECT * FROM sessions WHERE id = ?",[J]);return X?this.mapRow(X):null}getRecent(J,X=10){return this.db.all("SELECT * FROM sessions WHERE project_path = ? ORDER BY started_at DESC LIMIT ?",[J,X]).map(($)=>this.mapRow($))}getAll(J){return this.db.all("SELECT * FROM sessions WHERE project_path = ? ORDER BY started_at DESC",[J]).map((X)=>this.mapRow(X))}getActive(){return this.db.all("SELECT * FROM sessions WHERE status = 'active' ORDER BY started_at DESC").map((J)=>this.mapRow(J))}updateStatus(J,X){this.db.run("UPDATE sessions SET status = ? WHERE id = ?",[X,J])}markCompleted(J){this.db.run("UPDATE sessions SET status = 'completed', ended_at = datetime('now') WHERE id = ?",[J])}incrementObservationCount(J){this.db.run("UPDATE sessions SET observation_count = observation_count + 1 WHERE id = ?",[J])}setSummary(J,X){this.db.run("UPDATE sessions SET summary_id = ? WHERE id = ?",[X,J])}mapRow(J){return{id:J.id,projectPath:J.project_path,startedAt:J.started_at,endedAt:J.ended_at??null,status:J.status,observationCount:J.observation_count,summaryId:J.summary_id??null}}}import{randomUUID as
|
|
532
|
+
)`);J.run("INSERT OR REPLACE INTO _embedding_meta (key, value) VALUES (?, ?)",["dimension",String(X)])}class i{db;constructor(J){this.db=J}create(J,X){let $=new Date().toISOString();return this.db.run(`INSERT INTO sessions (id, project_path, started_at, status)
|
|
533
|
+
VALUES (?, ?, ?, 'active')`,[J,X,$]),this.getById(J)}getOrCreate(J,X){let $=this.getById(J);if($)return $;return this.create(J,X)}getById(J){let X=this.db.get("SELECT * FROM sessions WHERE id = ?",[J]);return X?this.mapRow(X):null}getRecent(J,X=10){return this.db.all("SELECT * FROM sessions WHERE project_path = ? ORDER BY started_at DESC LIMIT ?",[J,X]).map(($)=>this.mapRow($))}getAll(J){return this.db.all("SELECT * FROM sessions WHERE project_path = ? ORDER BY started_at DESC",[J]).map((X)=>this.mapRow(X))}getActive(){return this.db.all("SELECT * FROM sessions WHERE status = 'active' ORDER BY started_at DESC").map((J)=>this.mapRow(J))}updateStatus(J,X){this.db.run("UPDATE sessions SET status = ? WHERE id = ?",[X,J])}markCompleted(J){this.db.run("UPDATE sessions SET status = 'completed', ended_at = datetime('now') WHERE id = ?",[J])}incrementObservationCount(J){this.db.run("UPDATE sessions SET observation_count = observation_count + 1 WHERE id = ?",[J])}setSummary(J,X){this.db.run("UPDATE sessions SET summary_id = ? WHERE id = ?",[X,J])}mapRow(J){return{id:J.id,projectPath:J.project_path,startedAt:J.started_at,endedAt:J.ended_at??null,status:J.status,observationCount:J.observation_count,summaryId:J.summary_id??null}}}import{randomUUID as _X}from"crypto";class a{db;constructor(J){this.db=J}create(J){let X=_X(),$=new Date().toISOString();return this.db.run(`INSERT INTO session_summaries
|
|
539
534
|
(id, session_id, summary, key_decisions, files_modified,
|
|
540
535
|
concepts, created_at, token_count,
|
|
541
536
|
request, investigated, learned, completed, next_steps)
|
|
@@ -548,4 +543,4 @@ Respond with EXACTLY this XML format:
|
|
|
548
543
|
JOIN summaries_fts fts ON ss._rowid = fts.rowid
|
|
549
544
|
WHERE summaries_fts MATCH ?
|
|
550
545
|
ORDER BY rank
|
|
551
|
-
LIMIT ?`,[J,X]).map(($)=>this.mapRow($))}mapRow(J){return{id:J.id,sessionId:J.session_id,summary:J.summary,keyDecisions:JSON.parse(J.key_decisions),filesModified:JSON.parse(J.files_modified),concepts:JSON.parse(J.concepts),createdAt:J.created_at,tokenCount:J.token_count,request:J.request||void 0,investigated:J.investigated||void 0,learned:J.learned||void 0,completed:J.completed||void 0,nextSteps:J.next_steps||void 0}}}class
|
|
546
|
+
LIMIT ?`,[J,X]).map(($)=>this.mapRow($))}mapRow(J){return{id:J.id,sessionId:J.session_id,summary:J.summary,keyDecisions:JSON.parse(J.key_decisions),filesModified:JSON.parse(J.files_modified),concepts:JSON.parse(J.concepts),createdAt:J.created_at,tokenCount:J.token_count,request:J.request||void 0,investigated:J.investigated||void 0,learned:J.learned||void 0,completed:J.completed||void 0,nextSteps:J.next_steps||void 0}}}class r{config;compressor;summarizer;pendingRepo;observationRepo;sessionRepo;summaryRepo;embeddingModel;conflictEvaluator;entityExtractor;entityRepo;observer;processing=!1;timer=null;mode="in-process";onEnqueue=null;constructor(J,X,$,Q,Z,H,Y,V=null,W=null,K=null,B=null,U=null){this.config=J;this.compressor=X;this.summarizer=$;this.pendingRepo=Q;this.observationRepo=Z;this.sessionRepo=H;this.summaryRepo=Y;this.embeddingModel=V;this.conflictEvaluator=W;this.entityExtractor=K;this.entityRepo=B;this.observer=U}setMode(J){if(this.mode=J,J==="enqueue-only")this.stop()}getMode(){return this.mode}setOnEnqueue(J){this.onEnqueue=J}enqueue(J,X,$,Q){if(this.pendingRepo.create({sessionId:J,toolName:X,toolOutput:$,callId:Q}),this.observer?.onEnqueue?.({sessionId:J,toolName:X,createdAt:new Date().toISOString()}),this.mode==="enqueue-only")this.onEnqueue?.()}async processBatch(){if(this.mode==="enqueue-only")return 0;if(this.processing)return 0;this.processing=!0;let J=0,X=0,$=Date.now();try{this.pendingRepo.resetStale(5);let Q=this.pendingRepo.getPending(this.config.batchSize);if(this.observer?.onBatchStart?.({pending:Q.length,mode:this.mode,startedAt:new Date($).toISOString()}),Q.length===0)return 0;for(let Z of Q)try{this.pendingRepo.markProcessing(Z.id);let Y=await this.compressor.compress(Z.toolName,Z.toolOutput)??this.compressor.createFallbackObservation(Z.toolName,Z.toolOutput),V=!1,W=null;if(this.embeddingModel)try{let B=d({title:Y.title,narrative:Y.narrative,concepts:Y.concepts}),U=await c(this.embeddingModel,B);if(U){let _=this.config.conflictResolutionEnabled&&this.conflictEvaluator,F=this.config.conflictSimilarityBandLow??0.7,q=this.config.conflictSimilarityBandHigh??0.92;if(_){let C=this.observationRepo.findSimilar(U,Y.type,F,5),y=C.find((I)=>I.similarity>q);if(y)console.log(`[open-mem] Dedup: skipping duplicate of ${y.id} (similarity: ${y.similarity.toFixed(3)})`),V=!0;else{let I=C.filter((P)=>P.similarity>=F&&P.similarity<=q);if(I.length>0)try{let P=I.map((N)=>{let k=this.observationRepo.getById(N.id);return k?{id:k.id,title:k.title,narrative:k.narrative,concepts:k.concepts,type:k.type}:null}).filter((N)=>N!==null);if(P.length>0&&this.conflictEvaluator){let N=await this.conflictEvaluator.evaluate({title:Y.title,narrative:Y.narrative,concepts:Y.concepts,type:Y.type},P);if(N&&N.outcome==="duplicate")console.log(`[open-mem] Conflict eval: duplicate (${N.reason})`),V=!0;else if(N&&N.outcome==="update"&&N.supersedesId)console.log(`[open-mem] Conflict eval: update supersedes ${N.supersedesId} (${N.reason})`),W=N.supersedesId}}catch{}}}else{let C=this.observationRepo.findSimilar(U,Y.type,0.92,1);if(C.length>0)console.log(`[open-mem] Dedup: skipping duplicate of ${C[0].id} (similarity: ${C[0].similarity.toFixed(3)})`),V=!0}}}catch{}if(V){this.pendingRepo.markCompleted(Z.id);continue}let K=this.observationRepo.create({sessionId:Z.sessionId,type:Y.type,title:Y.title,subtitle:Y.subtitle,facts:Y.facts,narrative:Y.narrative,concepts:Y.concepts,filesRead:Y.filesRead,filesModified:Y.filesModified,rawToolOutput:Z.toolOutput,toolName:Z.toolName,tokenCount:O(`${Y.title} ${Y.narrative} ${Y.facts.join(" ")}`),discoveryTokens:Y.discoveryTokens??O(Z.toolOutput),importance:Y.importance??3});if(this.embeddingModel)try{let B=d({title:K.title,narrative:K.narrative,concepts:K.concepts}),U=await c(this.embeddingModel,B);if(U)this.observationRepo.setEmbedding(K.id,U)}catch{}if(W)try{this.observationRepo.supersede(W,K.id),console.log(`[open-mem] Superseded observation ${W} with ${K.id}`)}catch(B){console.error(`[open-mem] Failed to supersede ${W}:`,B)}if(this.config.entityExtractionEnabled&&this.entityExtractor&&this.entityRepo)try{let B=await this.entityExtractor.extract({title:K.title,narrative:K.narrative,concepts:K.concepts,facts:K.facts,filesRead:K.filesRead,filesModified:K.filesModified,type:K.type});if(B){let U=new Map;for(let _ of B.entities){let F=this.entityRepo.upsertEntity(_.name,_.entityType);U.set(_.name,F.id),this.entityRepo.linkObservation(F.id,K.id)}for(let _ of B.relations){let F=U.get(_.sourceName),q=U.get(_.targetName);if(F&&q)this.entityRepo.createRelation(F,q,_.relationship,K.id)}}}catch{}this.sessionRepo.incrementObservationCount(Z.sessionId),this.pendingRepo.markCompleted(Z.id),J++}catch(H){this.pendingRepo.markFailed(Z.id,String(H)),X++,this.observer?.onItemFailed?.({pendingId:Z.id,error:String(H),failedAt:new Date().toISOString()})}return J}finally{this.observer?.onBatchEnd?.({processed:J,failed:X,durationMs:Date.now()-$,finishedAt:new Date().toISOString()}),this.processing=!1}}async summarizeSession(J){let X=this.observationRepo.getBySession(J);if(!this.summarizer.shouldSummarize(X.length))return;if(this.summaryRepo.getBySessionId(J))return;let Q=await this.summarizer.summarize(J,X);if(!Q)return;let Z=this.summaryRepo.create({sessionId:J,summary:Q.summary,keyDecisions:Q.keyDecisions,filesModified:Q.filesModified,concepts:Q.concepts,tokenCount:O(Q.summary)});this.sessionRepo.setSummary(J,Z.id)}start(){if(this.mode==="enqueue-only")return;if(this.timer)return;this.timer=setInterval(async()=>{try{await this.processBatch()}catch{}},this.config.batchIntervalMs)}stop(){if(this.timer)clearInterval(this.timer),this.timer=null}get isRunning(){return this.timer!==null}get isProcessing(){return this.processing}getStats(){return{pending:this.pendingRepo.getPending(1000).length,processing:this.processing}}}import{spawnSync as CJ}from"child_process";import{dirname as FX,resolve as kJ}from"path";function LX(J){try{let X=CJ("git",["rev-parse","--git-common-dir"],{cwd:J,encoding:"utf-8",timeout:5000});if(X.status!==0||!X.stdout)return null;let $=X.stdout.trim();if($===".git")return null;let Q=CJ("git",["rev-parse","--git-dir"],{cwd:J,encoding:"utf-8",timeout:5000});if(Q.status!==0||!Q.stdout)return null;let Z=Q.stdout.trim(),H=kJ(J,$),Y=kJ(J,Z);if(H===Y)return null;let V=FX(H);if(V===H||V==="/")return null;return V}catch{return null}}function TJ(J){return LX(J)??J}var AX=5000,{values:t}=MX({options:{project:{type:"string",short:"p"},"poll-interval":{type:"string"}},strict:!1}),xJ=typeof t.project==="string"?t.project:null;if(!xJ)console.error("Usage: open-mem-daemon --project <path> [--poll-interval <ms>]"),process.exit(1);var qJ=t["poll-interval"],o=typeof qJ==="string"?Number.parseInt(qJ,10):AX;if(Number.isNaN(o)||o<100)console.error("--poll-interval must be a number >= 100"),process.exit(1);var SX=TJ(xJ),G=_J(SX);h.enableExtensionSupport();var E=DJ(G.dbPath);OJ(E,{hasVectorExtension:E.hasVectorExtension,embeddingDimension:G.embeddingDimension});var jX=new s(E),DX=new n(E),EX=new i(E),RX=new a(E),OX=new x(G),CX=new b(G),e=G.provider!=="bedrock",kX=G.compressionEnabled&&(!e||G.apiKey)?GJ({provider:G.provider,model:G.model,apiKey:G.apiKey}):null,TX=G.conflictResolutionEnabled&&(!e||G.apiKey)?new f({provider:G.provider,apiKey:G.apiKey,model:G.model,rateLimitingEnabled:G.rateLimitingEnabled}):null,qX=G.entityExtractionEnabled&&(!e||G.apiKey)?new u({provider:G.provider,apiKey:G.apiKey,model:G.model,rateLimitingEnabled:G.rateLimitingEnabled}):null,PX=new l(E),xX=new r(G,OX,CX,jX,DX,EX,RX,kX,TX,qX,PX),IJ=MJ(G.dbPath);FJ(IJ);var JJ=new m({queueProcessor:xX,pollIntervalMs:o});if(process.send)process.on("message",(J)=>{JJ.handleMessage(J)});var PJ=!1,XJ=()=>{if(PJ)return;PJ=!0,JJ.stop(),LJ(IJ),E.close()};process.on("SIGTERM",()=>{XJ(),process.exit(0)});process.on("SIGINT",()=>{XJ(),process.exit(0)});process.on("beforeExit",XJ);JJ.start();
|
|
@@ -2,7 +2,11 @@ import type { ObservationRepository } from "../db/observations";
|
|
|
2
2
|
import type { SessionRepository } from "../db/sessions";
|
|
3
3
|
import type { SummaryRepository } from "../db/summaries";
|
|
4
4
|
import type { UserObservationRepository } from "../db/user-memory";
|
|
5
|
-
import type { OpenMemConfig } from "../types";
|
|
5
|
+
import type { Observation, OpenMemConfig } from "../types";
|
|
6
|
+
/** Build a plain-text section highlighting key decisions from observations. */
|
|
7
|
+
export declare function buildDecisionsSection(decisions: Observation[]): string;
|
|
8
|
+
/** Build a plain-text section with compressed full observation details. */
|
|
9
|
+
export declare function buildFullObservationsSection(observations: Observation[]): string;
|
|
6
10
|
/** Create the session compaction hook that injects memory context during compaction. */
|
|
7
11
|
export declare function createCompactionHook(config: OpenMemConfig, observations: ObservationRepository, sessions: SessionRepository, summaries: SummaryRepository, projectPath: string, userObservationRepo?: UserObservationRepository | null): (_input: {
|
|
8
12
|
sessionID: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compaction.d.ts","sourceRoot":"","sources":["../../src/hooks/compaction.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"compaction.d.ts","sourceRoot":"","sources":["../../src/hooks/compaction.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAChE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AACnE,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAe3D,+EAA+E;AAC/E,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,WAAW,EAAE,GAAG,MAAM,CAQtE;AAED,2EAA2E;AAC3E,wBAAgB,4BAA4B,CAAC,YAAY,EAAE,WAAW,EAAE,GAAG,MAAM,CAYhF;AAED,wFAAwF;AACxF,wBAAgB,oBAAoB,CACnC,MAAM,EAAE,aAAa,EACrB,YAAY,EAAE,qBAAqB,EACnC,QAAQ,EAAE,iBAAiB,EAC3B,SAAS,EAAE,iBAAiB,EAC5B,WAAW,EAAE,MAAM,EACnB,mBAAmB,CAAC,EAAE,yBAAyB,GAAG,IAAI,IAGrD,QAAQ;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,EAC7B,QAAQ;IAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,KAC5C,OAAO,CAAC,IAAI,CAAC,CA2FhB"}
|