open-mem 0.11.0 → 0.12.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 +7 -0
- package/README.md +73 -565
- package/dist/adapters/http/loopback.d.ts +3 -0
- package/dist/adapters/http/loopback.d.ts.map +1 -0
- package/dist/adapters/http/server.d.ts.map +1 -1
- package/dist/adapters/mcp/server.d.ts +0 -2
- package/dist/adapters/mcp/server.d.ts.map +1 -1
- package/dist/adapters/opencode/tools.d.ts.map +1 -1
- package/dist/ai/fallback-policy.d.ts +18 -0
- package/dist/ai/fallback-policy.d.ts.map +1 -0
- package/dist/ai/fallback.d.ts +3 -1
- package/dist/ai/fallback.d.ts.map +1 -1
- package/dist/ai/provider.d.ts +2 -1
- package/dist/ai/provider.d.ts.map +1 -1
- package/dist/claude-code.js +87 -87
- package/dist/config/store.d.ts.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/contracts/api.d.ts +2 -120
- package/dist/contracts/api.d.ts.map +1 -1
- package/dist/contracts/schemas.d.ts +134 -0
- package/dist/contracts/schemas.d.ts.map +1 -0
- package/dist/cursor.js +87 -87
- package/dist/daemon.js +70 -70
- package/dist/db/observations.d.ts.map +1 -1
- package/dist/doctor.d.ts +3 -0
- package/dist/doctor.d.ts.map +1 -0
- package/dist/doctor.js +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +122 -122
- package/dist/maintenance.js +43 -43
- package/dist/mcp.js +73 -73
- package/dist/modes/loader.d.ts.map +1 -1
- package/dist/modes/resolver.d.ts +21 -0
- package/dist/modes/resolver.d.ts.map +1 -0
- package/dist/platform-worker.d.ts.map +1 -1
- package/dist/search/orchestrator.d.ts +4 -13
- package/dist/search/orchestrator.d.ts.map +1 -1
- package/dist/search/registry.d.ts +19 -0
- package/dist/search/registry.d.ts.map +1 -0
- package/dist/search/strategies/filter-only.d.ts +4 -0
- package/dist/search/strategies/filter-only.d.ts.map +1 -0
- package/dist/search/strategies/hybrid.d.ts +3 -0
- package/dist/search/strategies/hybrid.d.ts.map +1 -0
- package/dist/search/strategies/semantic.d.ts +4 -0
- package/dist/search/strategies/semantic.d.ts.map +1 -0
- package/dist/search/strategies/types.d.ts +22 -0
- package/dist/search/strategies/types.d.ts.map +1 -0
- package/dist/services/readiness.d.ts +26 -0
- package/dist/services/readiness.d.ts.map +1 -0
- package/dist/services/setup-diagnostics.d.ts +23 -0
- package/dist/services/setup-diagnostics.d.ts.map +1 -0
- package/dist/types.d.ts +3 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +8 -9
package/dist/claude-code.js
CHANGED
|
@@ -1,48 +1,48 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
// @bun
|
|
3
|
-
var
|
|
4
|
-
`);await
|
|
5
|
-
`)}async function
|
|
6
|
-
${
|
|
7
|
-
${
|
|
8
|
-
`;let
|
|
9
|
-
${
|
|
10
|
-
${
|
|
11
|
-
|
|
12
|
-
${
|
|
13
|
-
${
|
|
14
|
-
${
|
|
15
|
-
`}function
|
|
3
|
+
var D=import.meta.require;import{createInterface as L0}from"readline";import{parseArgs as X0}from"util";var Ny=new Set(["127.0.0.1","::1","localhost"]);function Ey(u){return u.trim().toLowerCase()}function Wy(u){return Ny.has(Ey(u))}function Zu(u,y){if(Wy(u))return;throw Error(`[open-mem] ${y} must bind to loopback only (127.0.0.1, ::1, localhost). Received "${u}".`)}var Su={name:"claude-code",version:"0.1",capabilities:{nativeSessionLifecycle:!0,nativeToolCapture:!0,nativeChatCapture:!0,emulatedIdleFlush:!0}},Uu={name:"cursor",version:"0.1",capabilities:{nativeSessionLifecycle:!1,nativeToolCapture:!0,nativeChatCapture:!0,emulatedIdleFlush:!0}};function d(){return new Date().toISOString()}function I(u){if(!u||typeof u!=="object"||Array.isArray(u))return null;return u}function L(u){return typeof u==="string"&&u.trim().length>0?u:null}function n(u,y){let B=I(y);if(!B)return null;let $=L(B.kind),A=L(B.sessionId);if(!$||!A)return null;if($==="session.start"||$==="session.end"||$==="idle.flush")return{kind:$,platform:u,sessionId:A,occurredAt:L(B.occurredAt)??d(),metadata:I(B.metadata)??void 0};if($==="chat.message"){let J=L(B.text);if(!J)return null;let K=L(B.role);return{kind:$,platform:u,sessionId:A,text:J,role:K==="assistant"||K==="system"?K:"user",occurredAt:L(B.occurredAt)??d(),metadata:I(B.metadata)??void 0}}if($==="tool.execute"){let J=L(B.toolName),K=L(B.output);if(!J||!K)return null;return{kind:$,platform:u,sessionId:A,callId:L(B.callId)??`${u}-${Date.now()}`,toolName:J,output:K,occurredAt:L(B.occurredAt)??d(),metadata:I(B.metadata)??void 0}}return null}function Hy(u){let y=u.type??u.event;if(!y)return null;if(y==="session.start")return"session.start";if(y==="session.end")return"session.end";if(y==="idle.flush")return"idle.flush";if(y==="tool.execute")return"tool.execute";if(y==="chat.message")return"chat.message";return null}class ku{descriptor=Su;normalize(u){if(!u||typeof u!=="object"||Array.isArray(u))return null;let y=u,B=Hy(y);if(!B||!y.sessionId)return null;return n("claude-code",{kind:B,sessionId:y.sessionId,callId:y.callId,toolName:y.toolName,output:y.output,role:y.role,text:y.text,occurredAt:y.occurredAt,metadata:y.metadata})}}function Mu(){return new ku}function Qy(u){let y=u.eventName??u.event;if(!y)return null;if(y==="sessionStart")return"session.start";if(y==="sessionEnd")return"session.end";if(y==="idleFlush")return"idle.flush";if(y==="toolExecute")return"tool.execute";if(y==="chatMessage")return"chat.message";return null}class fu{descriptor=Uu;normalize(u){if(!u||typeof u!=="object"||Array.isArray(u))return null;let y=u,B=Qy(y),$=y.sessionId??y.session;if(!B||!$)return null;return n("cursor",{kind:B,sessionId:$,callId:y.callId??y.invocationId,toolName:y.toolName??y.tool,output:y.output,role:y.role,text:y.text??y.message,occurredAt:y.occurredAt??y.timestamp,metadata:y.metadata??y.meta})}}function Lu(){return new fu}function g(u,y=""){if(!u)return u;return u.replace(/<private>[\s\S]*?<\/private>/gi,y)}var Xu=200,Zy=/(\([\s\S]*[+*]\)\s*[+*?])|(\(\.\*\)\+)|(\(\.\+\)\+)/;function c(u,y,B="[REDACTED]"){if(!u||y.length===0)return u;let $=u;for(let A of y){if(A.length>Xu){console.warn(`[open-mem] Skipping oversized redaction pattern (${A.length} chars, max ${Xu})`);continue}if(Zy.test(A)){console.warn("[open-mem] Skipping potentially dangerous redaction pattern (nested quantifiers detected)");continue}try{$=$.replace(new RegExp(A,"g"),B)}catch{}}return $}var Sy=20,Yu=2000,Du=60;function Uy(u){let y=u.toLowerCase().replace(/[^a-z0-9\s-]/g," ").split(/\s+/).filter((B)=>B.length>4);return[...new Set(y)].slice(0,5)}function mu(u){let{observations:y,sessions:B,projectPath:$,sessionId:A,text:J,agent:K,sensitivePatterns:V=[]}=u;if(K!==void 0&&K!=="user")return!1;let R=c(g(J),V);if(R.length<Sy)return!1;B.getOrCreate(A,$);let N=`User request: ${R.length>Du?`${R.slice(0,Du)}...`:R}`,E=R.length>Yu?`${R.slice(0,Yu)}...`:R;return y.create({sessionId:A,type:"discovery",title:N,subtitle:"",facts:[],narrative:E,concepts:Uy(R),filesRead:[],filesModified:[],rawToolOutput:"",toolName:"chat.message",tokenCount:Math.ceil(E.length/4),discoveryTokens:0,importance:3}),!0}import{existsSync as Fy}from"fs";import{readFile as Gy,writeFile as Oy}from"fs/promises";import{join as Py}from"path";import{existsSync as Cu}from"fs";import{mkdir as ky,readFile as My,rename as fy,unlink as Ly,writeFile as Xy}from"fs/promises";import{dirname as v,isAbsolute as t,join as h,normalize as Yy,relative as o,resolve as j,sep as i}from"path";var p="<!-- open-mem-context -->",G="<!-- /open-mem-context -->",Fu={bugfix:"\uD83D\uDD34",feature:"\uD83D\uDFE3",refactor:"\uD83D\uDD04",change:"\u2705",discovery:"\uD83D\uDD35",decision:"\u2696\uFE0F"},_u=new Map,Dy=new Set(["node_modules",".git","dist","coverage",".open-mem","build","__pycache__",".next",".nuxt"]);async function Gu(u,y,B){if(y.length===0)return;if(B.mode==="single")return my(u,y,B);let{maxDepth:$,filename:A}=B,J=[];for(let R of y){for(let z of R.filesModified)J.push(z);for(let z of R.filesRead)J.push(z)}let K=Pu(J,u,$);if(K.size===0)return;let V=Tu(y,K,u);for(let[R,z]of V)try{let N=_y(R,z,u);await Ou(R,N,A)}catch(N){console.error(`[open-mem] Failed to update AGENTS.md in ${R}:`,N)}}async function my(u,y,B){let{maxDepth:$,filename:A}=B,J=y.filter(s);if(J.length===0)return;let K=[];for(let Q of J){for(let U of Q.filesModified)K.push(U);for(let U of Q.filesRead)K.push(U)}let V=Pu(K,u,$),R=Tu(J,V,u),z=J.filter((Q)=>{return[...Q.filesModified,...Q.filesRead].some((k)=>{if(!k)return!1;let M=t(k)?k:h(u,k);return j(v(M))===j(u)})});if(z.length>0)R.set(j(u),z);if(R.size===0)return;let N=[];N.push("## Project Activity (auto-generated by open-mem)"),N.push("");let E=[...R.entries()].map(([Q,U])=>({relPath:o(u,Q)||".",observations:U})).sort((Q,U)=>Q.relPath.localeCompare(U.relPath));for(let{relPath:Q,observations:U}of E){let k=U.filter(s).sort((Z,S)=>S.createdAt.localeCompare(Z.createdAt)).slice(0,10);if(k.length===0)continue;N.push(`### ${Q}/`),N.push("| ID | Type | Title | Date |"),N.push("|----|------|-------|------|");for(let Z of k){let S=Fu[Z.type]||"\uD83D\uDCDD",Y=Z.createdAt.split("T")[0],Vy=Z.title.replace(/\|/g,"\\|");N.push(`| ${Z.id} | ${S} ${Z.type} | ${Vy} | ${Y} |`)}let M=new Set;for(let Z of k)for(let S of Z.concepts)M.add(S);if(M.size>0){let Z=[...M].slice(0,10).join(", ");N.push(""),N.push(`**Key concepts:** ${Z}`)}let f=k.filter((Z)=>Z.type==="decision").map((Z)=>Z.title);if(f.length>0)N.push(""),N.push(`**Recent decisions:** ${f.slice(0,5).join("; ")}`);N.push("")}N.push("\uD83D\uDCA1 *Use `mem-find` to search full details. Use `mem-create` to save important decisions.*");let H=N.join(`
|
|
4
|
+
`);await Ou(u,H,A)}function s(u){return!/^\w[\w-]*\s+execution$/i.test(u.title)}function _y(u,y,B){let $=[...y].filter(s).sort((z,N)=>N.createdAt.localeCompare(z.createdAt)).slice(0,10),A=o(B,u)||".",J=[];J.push(`## Recent Activity in \`${A}/\` (auto-generated by open-mem)`),J.push(""),J.push("| ID | Type | Title | Date |"),J.push("|----|------|-------|------|");for(let z of $){let N=Fu[z.type]||"\uD83D\uDCDD",E=z.createdAt.split("T")[0],H=z.title.replace(/\|/g,"\\|");J.push(`| ${z.id} | ${N} ${z.type} | ${H} | ${E} |`)}let K=new Set;for(let z of $)for(let N of z.concepts)K.add(N);if(K.size>0){let z=[...K].slice(0,10).join(", ");J.push(""),J.push(`**Key concepts:** ${z}`)}let V=$.filter((z)=>z.type==="decision").map((z)=>z.title);if(V.length>0)J.push(""),J.push(`**Recent decisions:** ${V.slice(0,5).join("; ")}`);let R=$.filter((z)=>z.type==="decision"&&z.narrative).slice(0,3);if(R.length>0){J.push(""),J.push("**Decision details:**");for(let z of R){let N=z.narrative.split(/[.!?]\s/)[0],E=N.length>120?`${N.slice(0,117)}...`:N;J.push(`- \u2696\uFE0F ${z.title}: ${E}`)}}return J.push(""),J.push("\uD83D\uDCA1 *Use `mem-find` to search full details across all sessions. Use `mem-create` to save important decisions.*"),J.join(`
|
|
5
|
+
`)}async function Ou(u,y,B){if(!Cu(u))return;let A=(_u.get(u)??Promise.resolve()).then(async()=>{let J=h(u,B),K=h(u,`.${B}.tmp`),V="";try{V=await My(J,"utf-8")}catch{}let R=Cy(V,y);try{await ky(v(K),{recursive:!0}),await Xy(K,R,"utf-8"),await fy(K,J)}catch(z){try{await Ly(K)}catch{}throw z}});return _u.set(u,A.catch(()=>{})),A}function Cy(u,y){if(!u)return`${p}
|
|
6
|
+
${y}
|
|
7
|
+
${G}
|
|
8
|
+
`;let B=u.indexOf(p),$=u.indexOf(G);if(B!==-1&&$!==-1&&$>B){let J=u.substring(0,B),K=u.substring($+G.length);return`${J}${p}
|
|
9
|
+
${y}
|
|
10
|
+
${G}${K}`}let A=u;if(B!==-1&&$===-1)A=A.replace(p,"").trim();else if(B===-1&&$!==-1)A=A.replace(G,"").trim();else if(B!==-1&&$!==-1&&$<=B)A=A.replace(G,"").replace(p,"").trim();return`${A}
|
|
11
|
+
|
|
12
|
+
${p}
|
|
13
|
+
${y}
|
|
14
|
+
${G}
|
|
15
|
+
`}function Pu(u,y,B){let $=new Set,A=j(y);for(let J of u){if(!J||!J.trim())continue;if(J.startsWith("~")||J.startsWith("http"))continue;let K=t(J)?J:h(y,J),V=v(K),R=j(V);if(!R.startsWith(A+i)&&R!==A)continue;if(R===A)continue;let z=o(A,R);if(z.split(i).length>B)continue;if(Yy(z).split(i).some((H)=>Dy.has(H)))continue;if(!Cu(R))continue;$.add(R)}return $}function Tu(u,y,B){let $=new Map;for(let A of u){let J=[...A.filesModified,...A.filesRead],K=new Set;for(let V of J){if(!V)continue;let R=t(V)?V:h(B,V),z=j(v(R));if(y.has(z))K.add(z)}for(let V of K){let R=$.get(V)??[];R.push(A),$.set(V,R)}}return $}function pu(u,y,B){if(u.retentionDays===0)return;try{let $=y.deleteOlderThan(u.retentionDays),A=B.deleteCompletedOlderThan(u.retentionDays);if($>0||A>0)console.log(`[open-mem] Retention: deleted ${$} observations, ${A} pending messages`)}catch($){console.error("[open-mem] Retention enforcement error:",$)}}async function l(u,y,B){let{queue:$,sessions:A,projectPath:J,config:K,observations:V,pendingMessages:R}=u;switch(y){case"session.created":{if(B)A.getOrCreate(B,J);try{pu(K,V,R)}catch(z){console.error("[open-mem] Retention enforcement error:",z)}try{await Ty(J)}catch(z){console.error("[open-mem] Gitignore entry error:",z)}break}case"session.idle":{if($.processBatch().catch((z)=>{console.error("[open-mem] Background processing error:",z)}),B)A.updateStatus(B,"idle"),ju(B,J,K,V).catch((z)=>{console.error("[open-mem] Folder context error:",z)});break}case"session.completed":case"session.ended":{if(B)await $.processBatch(),await $.summarizeSession(B),A.markCompleted(B),await ju(B,J,K,V);break}}}async function ju(u,y,B,$){if(!B.folderContextEnabled)return;try{let A=$.getBySession(u);if(A.length>0)await Gu(y,A,{mode:B.folderContextMode,filename:B.folderContextFilename,maxDepth:B.folderContextMaxDepth})}catch(A){console.error("[open-mem] Folder context update error:",A)}}async function Ty(u){let y=Py(u,".gitignore");if(!Fy(y))return;let B=await Gy(y,"utf-8");if(B.includes("AGENTS.md"))return;let $=`
|
|
16
16
|
# open-mem: Auto-generated folder context files.
|
|
17
17
|
# Uncomment to exclude from version control (recommended for large projects):
|
|
18
18
|
# **/AGENTS.md
|
|
19
|
-
`;await
|
|
20
|
-
`)?
|
|
21
|
-
${
|
|
22
|
-
${
|
|
19
|
+
`;await Oy(y,B.endsWith(`
|
|
20
|
+
`)?B+$:`${B}
|
|
21
|
+
${$}`,"utf-8")}function qu(u){let{config:y,queue:B,sessions:$,projectPath:A,tool:J,sessionId:K,callId:V,toolOutput:R}=u;if(y.ignoredTools.includes(J))return!1;if(!R||R.length<y.minOutputLength)return!1;let z=c(R,y.sensitivePatterns);return z=g(z,"[PRIVATE]"),$.getOrCreate(K,A),B.enqueue(K,J,z,V),!0}class e{adapter;lifecycleDeps;queue;sessions;observations;projectPath;config;constructor(u){this.adapter=u.adapter,this.queue=u.queue,this.sessions=u.sessions,this.observations=u.observations,this.projectPath=u.projectPath,this.config=u.config,this.lifecycleDeps={queue:u.queue,sessions:u.sessions,projectPath:u.projectPath,config:u.config,observations:u.observations,pendingMessages:u.pendingMessages}}platform(){return this.adapter.descriptor.name}normalize(u){return this.adapter.normalize(u)}async ingestRaw(u){let y=this.normalize(u);if(!y)return!1;return await this.ingestNormalized(y),!0}async ingestNormalized(u){switch(u.kind){case"session.start":await l(this.lifecycleDeps,"session.created",u.sessionId);return;case"session.end":await l(this.lifecycleDeps,"session.ended",u.sessionId);return;case"idle.flush":await l(this.lifecycleDeps,"session.idle",u.sessionId);return;case"tool.execute":qu({config:this.config,queue:this.queue,sessions:this.sessions,projectPath:this.projectPath,tool:u.toolName,sessionId:u.sessionId,callId:u.callId,toolOutput:u.output});return;case"chat.message":mu({observations:this.observations,sessions:this.sessions,projectPath:this.projectPath,sessionId:u.sessionId,text:u.text,agent:u.role==="user"?"user":u.role,sensitivePatterns:this.config.sensitivePatterns});return}}}import{generateText as cy}from"ai";function m(u){if(typeof u!=="object"||u===null)return!1;let y=u,B=y.status;if(B===429||B===500||B===503)return!0;let $=y.error;if(typeof $==="object"&&$!==null&&$.type==="overloaded_error")return!0;return!1}function x(u){if(u&&typeof u==="object"){let y=u.status;if(typeof y==="number")return y===400||y===401||y===403}return!1}function O(u){return new Promise((y)=>setTimeout(y,u))}var py=new Set(["decision","bugfix","feature","refactor","discovery","change"]);function W(u,y){let B=new RegExp(`<${y}[^>]*>([\\s\\S]*?)</${y}>`,"i"),$=u.match(B);return $?$[1].trim():""}function X(u,y){let B=new RegExp(`<${y}[^>]*>([\\s\\S]*?)</${y}>`,"gi"),$=[];for(let A of u.matchAll(B)){let J=A[1].trim();if(J)$.push(J)}return $}function hu(u){let y=W(u,"observation");if(!y)return null;let B=W(y,"type").toLowerCase(),$=py.has(B)?B:"discovery",A=W(y,"title")||"Untitled observation",J=W(y,"subtitle"),K=W(y,"narrative"),V=X(W(y,"facts"),"fact"),R=X(W(y,"concepts"),"concept"),z=X(W(y,"files_read"),"file"),N=X(W(y,"files_modified"),"file"),E=W(y,"importance"),H=Number.parseInt(E,10),Q=Number.isNaN(H)?3:Math.max(1,Math.min(5,H));return{type:$,title:A,subtitle:J,facts:V,narrative:K,concepts:R,filesRead:z,filesModified:N,importance:Q}}function xu(u){let y=W(u,"session_summary");if(!y)return null;let B=W(y,"summary")||"No summary available",$=X(W(y,"key_decisions"),"decision"),A=X(W(y,"files_modified"),"file"),J=X(W(y,"concepts"),"concept"),K=W(y,"request")||void 0,V=W(y,"investigated")||void 0,R=W(y,"learned")||void 0,z=W(y,"completed")||void 0,N=W(y,"next_steps")||void 0;return{summary:B,keyDecisions:$,filesModified:A,concepts:J,request:K,investigated:V,learned:R,completed:z,nextSteps:N}}var jy=new Set(["new_fact","update","duplicate"]);function wu(u){let y=W(u,"evaluation");if(!y)return null;let B=W(y,"outcome").toLowerCase().trim();if(!jy.has(B))return null;let $=B,A=W(y,"reason");if(!A)return null;let J=W(y,"supersedes"),K={outcome:$,reason:A};if($==="update"&&J)K.supersedesId=J;if($==="update"&&!K.supersedesId)return null;return K}var qy=new Set(["technology","library","pattern","concept","file","person","project","other"]),hy=new Set(["uses","depends_on","implements","extends","related_to","replaces","configures"]);function Iu(u){let y=W(u,"extraction");if(!y)return null;let B=W(y,"entities"),$=W(y,"relations"),A=X(B,"entity"),J=[];for(let R of A){let z=W(R,"name");if(!z)continue;let N=W(R,"type").toLowerCase(),E=qy.has(N)?N:"other";J.push({name:z,entityType:E})}let K=X($,"relation"),V=[];for(let R of K){let z=W(R,"source"),N=W(R,"target"),E=W(R,"relationship").toLowerCase();if(!z||!N||!E)continue;if(!hy.has(E))continue;V.push({sourceName:z,targetName:N,relationship:E})}return{entities:J,relations:V}}function P(u){return Math.ceil(u.length/4)}function nu(u,y,B,$){let A=B?`<session_context>
|
|
22
|
+
${B}
|
|
23
23
|
</session_context>
|
|
24
24
|
|
|
25
|
-
`:"",
|
|
25
|
+
`:"",J=$?$.observationTypes.join("|"):"decision|bugfix|feature|refactor|discovery|change",V=($?$.conceptVocabulary:["how-it-works","why-it-exists","what-changed","problem-solution","gotcha","pattern","trade-off"]).map((R)=>{let N={"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"}[R];return N?`- ${R}: ${N}`:`- ${R}`}).join(`
|
|
26
26
|
`);return`<task>
|
|
27
27
|
Analyze the following tool output and extract a structured observation.
|
|
28
28
|
</task>
|
|
29
29
|
|
|
30
|
-
<tool_name>${
|
|
30
|
+
<tool_name>${u}</tool_name>
|
|
31
31
|
|
|
32
32
|
<tool_output>
|
|
33
|
-
${
|
|
33
|
+
${y}
|
|
34
34
|
</tool_output>
|
|
35
35
|
|
|
36
|
-
${
|
|
36
|
+
${A}<instructions>
|
|
37
37
|
Extract a structured observation from the tool output. Determine the most appropriate type and provide a concise but informative summary.
|
|
38
38
|
|
|
39
39
|
When extracting concepts, prefer established vocabulary where appropriate:
|
|
40
|
-
${
|
|
40
|
+
${V}
|
|
41
41
|
You may also use any domain-specific concepts relevant to the observation.
|
|
42
42
|
|
|
43
43
|
Respond with EXACTLY this XML format:
|
|
44
44
|
<observation>
|
|
45
|
-
<type>${
|
|
45
|
+
<type>${J}</type>
|
|
46
46
|
<title>Brief descriptive title (max 80 chars)</title>
|
|
47
47
|
<subtitle>One-line elaboration</subtitle>
|
|
48
48
|
<importance>1-5 (1=trivial/routine, 2=low, 3=normal, 4=significant, 5=critical decision or discovery)</importance>
|
|
@@ -62,18 +62,18 @@ Respond with EXACTLY this XML format:
|
|
|
62
62
|
<file>path/to/file/modified</file>
|
|
63
63
|
</files_modified>
|
|
64
64
|
</observation>
|
|
65
|
-
</instructions>`}function
|
|
66
|
-
<title>${
|
|
67
|
-
<narrative>${
|
|
65
|
+
</instructions>`}function gu(u,y){let B=u.map(($,A)=>` <obs index="${A+1}" type="${$.type}">
|
|
66
|
+
<title>${$.title}</title>
|
|
67
|
+
<narrative>${$.narrative}</narrative>
|
|
68
68
|
</obs>`).join(`
|
|
69
69
|
`);return`<task>
|
|
70
70
|
Summarize the following coding session based on its observations.
|
|
71
71
|
</task>
|
|
72
72
|
|
|
73
|
-
<session_id>${
|
|
73
|
+
<session_id>${y}</session_id>
|
|
74
74
|
|
|
75
75
|
<observations>
|
|
76
|
-
${
|
|
76
|
+
${B}
|
|
77
77
|
</observations>
|
|
78
78
|
|
|
79
79
|
<instructions>
|
|
@@ -97,21 +97,21 @@ Respond with EXACTLY this XML format:
|
|
|
97
97
|
<concept>key-concept</concept>
|
|
98
98
|
</concepts>
|
|
99
99
|
</session_summary>
|
|
100
|
-
</instructions>`}function
|
|
101
|
-
<title>${
|
|
102
|
-
<narrative>${
|
|
103
|
-
<concepts>${
|
|
104
|
-
<type>${
|
|
100
|
+
</instructions>`}function cu(u,y){let B=y.map(($)=>` <candidate id="${$.id}">
|
|
101
|
+
<title>${$.title}</title>
|
|
102
|
+
<narrative>${$.narrative}</narrative>
|
|
103
|
+
<concepts>${$.concepts.join(", ")}</concepts>
|
|
104
|
+
<type>${$.type}</type>
|
|
105
105
|
</candidate>`).join(`
|
|
106
106
|
`);return`<conflict_evaluation>
|
|
107
107
|
<new_observation>
|
|
108
|
-
<title>${
|
|
109
|
-
<narrative>${
|
|
110
|
-
<concepts>${
|
|
111
|
-
<type>${
|
|
108
|
+
<title>${u.title}</title>
|
|
109
|
+
<narrative>${u.narrative}</narrative>
|
|
110
|
+
<concepts>${u.concepts.join(", ")}</concepts>
|
|
111
|
+
<type>${u.type}</type>
|
|
112
112
|
</new_observation>
|
|
113
113
|
<existing_candidates>
|
|
114
|
-
${
|
|
114
|
+
${B}
|
|
115
115
|
</existing_candidates>
|
|
116
116
|
<instructions>
|
|
117
117
|
Evaluate whether the new observation represents:
|
|
@@ -126,22 +126,22 @@ Respond with EXACTLY this XML format:
|
|
|
126
126
|
<reason>Brief explanation</reason>
|
|
127
127
|
</evaluation>
|
|
128
128
|
</instructions>
|
|
129
|
-
</conflict_evaluation>`}function
|
|
129
|
+
</conflict_evaluation>`}function vu(u,y){let B=[...u.filesRead,...u.filesModified],$=y?y.entityTypes.join(", "):"technology, library, pattern, concept, file, person, project, other",A=y?y.relationshipTypes.join(", "):"uses, depends_on, implements, extends, related_to, replaces, configures";return`<entity_extraction>
|
|
130
130
|
<observation>
|
|
131
|
-
<title>${
|
|
132
|
-
<type>${
|
|
133
|
-
<narrative>${
|
|
134
|
-
<facts>${
|
|
131
|
+
<title>${u.title}</title>
|
|
132
|
+
<type>${u.type}</type>
|
|
133
|
+
<narrative>${u.narrative}</narrative>
|
|
134
|
+
<facts>${u.facts.join(`
|
|
135
135
|
`)}</facts>
|
|
136
|
-
<files>${
|
|
136
|
+
<files>${B.join(`
|
|
137
137
|
`)}</files>
|
|
138
|
-
<concepts>${
|
|
138
|
+
<concepts>${u.concepts.join(", ")}</concepts>
|
|
139
139
|
</observation>
|
|
140
140
|
<instructions>
|
|
141
141
|
Extract entities and relationships from this observation.
|
|
142
142
|
|
|
143
|
-
Entity types: ${
|
|
144
|
-
Relationship types: ${
|
|
143
|
+
Entity types: ${$}
|
|
144
|
+
Relationship types: ${A}
|
|
145
145
|
|
|
146
146
|
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.
|
|
147
147
|
Respond with EXACTLY this XML format:
|
|
@@ -155,102 +155,102 @@ Respond with EXACTLY this XML format:
|
|
|
155
155
|
</relations>
|
|
156
156
|
</extraction>
|
|
157
157
|
</instructions>
|
|
158
|
-
</entity_extraction>`}class a{specificationVersion;provider;modelId;supportedUrls;providers;constructor(
|
|
158
|
+
</entity_extraction>`}class a{shouldFailover(u){let{error:y,attemptIndex:B,totalProviders:$}=u;if(x(y))return!1;if(B>=$-1)return!1;return m(y)}onFailover(u){let y=u.error?.status??"unknown";if(!u.nextProvider)return;console.error(`[open-mem] Provider ${u.provider} failed (${y}), falling over to ${u.nextProvider}`)}}class uu{specificationVersion;provider;modelId;supportedUrls;providers;policy;constructor(u,y=new a){if(u.length===0)throw Error("At least one provider required");let B=u[0].model;this.specificationVersion=B.specificationVersion,this.provider=B.provider,this.modelId=B.modelId,this.supportedUrls=B.supportedUrls,this.providers=u,this.policy=y}async doGenerate(u){let y;for(let B=0;B<this.providers.length;B++){let $=this.providers[B];try{return this.policy.onAttempt?.({error:null,provider:$.name,nextProvider:this.providers[B+1]?.name,attemptIndex:B,totalProviders:this.providers.length}),await $.model.doGenerate(u)}catch(A){if(y=A,x(A))throw A;let J=this.providers[B+1]?.name,K={error:A,provider:$.name,nextProvider:J,attemptIndex:B,totalProviders:this.providers.length};if(this.policy.shouldFailover(K)){this.policy.onFailover(K);continue}throw this.policy.onFinalFailure?.(K),A}}throw y}async doStream(u){let y;for(let B=0;B<this.providers.length;B++){let $=this.providers[B];try{return this.policy.onAttempt?.({error:null,provider:$.name,nextProvider:this.providers[B+1]?.name,attemptIndex:B,totalProviders:this.providers.length}),await $.model.doStream(u)}catch(A){if(y=A,x(A))throw A;let J=this.providers[B+1]?.name,K={error:A,provider:$.name,nextProvider:J,attemptIndex:B,totalProviders:this.providers.length};if(this.policy.shouldFailover(K)){this.policy.onFailover(K);continue}throw this.policy.onFinalFailure?.(K),A}}throw y}}var xy={"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 wy(u){if(u.includes("."))return u;return xy[u]||`us.anthropic.${u}-v1:0`}function lu(u){switch(u.provider){case"anthropic":{let{createAnthropic:y}=D("@ai-sdk/anthropic");return y({apiKey:u.apiKey})(u.model)}case"bedrock":{let{createAmazonBedrock:y}=D("@ai-sdk/amazon-bedrock");return y()(wy(u.model))}case"openai":{let{createOpenAI:y}=D("@ai-sdk/openai");return y({apiKey:u.apiKey})(u.model)}case"google":{let{createGoogleGenerativeAI:y}=D("@ai-sdk/google");return y({apiKey:u.apiKey})(u.model)}case"openrouter":{let{createOpenRouter:y}=D("@openrouter/ai-sdk-provider");return y({apiKey:u.apiKey})(u.model)}default:throw Error(`Unknown provider: ${u.provider}. Supported: anthropic, bedrock, openai, google, openrouter`)}}function bu(u){try{switch(u.provider){case"google":{let{createGoogleGenerativeAI:y}=D("@ai-sdk/google");return y({apiKey:u.apiKey}).embedding("text-embedding-004")}case"openai":{let{createOpenAI:y}=D("@ai-sdk/openai");return y({apiKey:u.apiKey}).embedding("text-embedding-3-small")}case"bedrock":{let{createAmazonBedrock:y}=D("@ai-sdk/amazon-bedrock");return y().embedding("amazon.titan-embed-text-v2:0")}case"anthropic":return null;case"openrouter":return null;default:return null}}catch{return null}}var Iy={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 ny(u){switch(u){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 _(u){if(!u.fallbackProviders||u.fallbackProviders.length===0)return[];return u.fallbackProviders.map((y)=>({provider:y,model:Iy[y]??"gemini-2.5-flash-lite",apiKey:ny(y)}))}function C(u,y=[],B){let $=lu(u);if(y.length===0)return $;let A=[{name:u.provider,model:$},...y.map((J)=>({name:J.provider,model:lu(J)}))];return new uu(A,B)}var gy={"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},ru=0;async function F(u,y){if(!y)return;let B=gy[u]||5,$=Math.ceil(60000/B)+100,J=Date.now()-ru;if(J<$){let K=$-J;await new Promise((V)=>setTimeout(V,K))}ru=Date.now()}class w{model;config;_generate=cy;constructor(u){this.config=u,this.model=null;let y=u.provider!=="bedrock";if(u.compressionEnabled&&(!y||u.apiKey))try{this.model=C({provider:u.provider,model:u.model,apiKey:u.apiKey},_(u))}catch{}}static MAX_INPUT_LENGTH=50000;async compress(u,y,B){if(!this.config.compressionEnabled||!this.model)return null;if(y.length<this.config.minOutputLength)return null;let $=P(y),A=y.length>w.MAX_INPUT_LENGTH?`${y.substring(0,w.MAX_INPUT_LENGTH)}
|
|
159
159
|
|
|
160
|
-
[... truncated ...]`:J,N=I0(B,$,K),W=2;for(let Z=0;Z<=W;Z++)try{if(this.config.provider==="google")await O(this.config.model,this.config.rateLimitingEnabled);let{text:Q}=await this._generate({model:this.model,maxOutputTokens:this.config.maxTokensPerCompression,prompt:N}),E=j0(Q);if(E)E.discoveryTokens=z;return E}catch(Q){if(M(Q)&&Z<W){let E=2**Z*1000;await P(E);continue}return null}return null}async compressBatch(B){let J=new Map;for(let K=0;K<B.length;K++){let z=B[K],$=await this.compress(z.toolName,z.toolOutput,z.sessionContext);if(J.set(z.callId,$),K<B.length-1)await P(200)}return J}createFallbackObservation(B,J){let K=wB(J),z=xB[B]??"discovery";return{type:z,title:`${B} execution`,subtitle:J.substring(0,100).replace(/\n/g," "),facts:[],narrative:`Tool ${B} was executed. Output length: ${J.length} chars.`,concepts:[],filesRead:z==="discovery"?K:[],filesModified:z==="change"?K:[],discoveryTokens:q(J),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 xB={Read:"discovery",Write:"change",Edit:"change",Bash:"change",Glob:"discovery",Grep:"discovery"},IB=/(?:^|\s)((?:\.\/|\/|src\/|tests\/|lib\/)\S+\.\w+)/gm;function wB(B){let J=[];for(let K of B.matchAll(IB))J.push(K[1]);return[...new Set(J)]}import{generateText as gB}from"ai";class o{model;config;_generate=gB;constructor(B){if(this.config=B,this.model=null,B.provider==="bedrock"||B.apiKey)try{this.model=y({provider:B.provider,model:B.model,apiKey:B.apiKey},C(B))}catch{}}async evaluate(B,J){if(!this.model||J.length===0)return null;let K=g0(B,J),z=2;for(let $=0;$<=z;$++)try{if(this.config.provider==="google")await O(this.config.model,this.config.rateLimitingEnabled);let{text:N}=await this._generate({model:this.model,maxOutputTokens:512,prompt:K});return h0(N)}catch(N){if(M(N)&&$<z){let W=2**$*1000;await P(W);continue}return null}return null}}import{generateText as pB}from"ai";class e{model;config;_generate=pB;constructor(B){if(this.config=B,this.model=null,B.provider==="bedrock"||B.apiKey)try{this.model=y({provider:B.provider,model:B.model,apiKey:B.apiKey},C(B))}catch{}}async extract(B){if(!this.model)return null;let J=p0(B),K=2;for(let z=0;z<=K;z++)try{if(this.config.provider==="google")await O(this.config.model,this.config.rateLimitingEnabled);let{text:$}=await this._generate({model:this.model,maxOutputTokens:1024,prompt:J});return x0($)}catch($){if(M($)&&z<K){let N=2**z*1000;await P(N);continue}return null}return null}}import{generateText as vB}from"ai";class B0{model;config;_generate=vB;constructor(B){this.config=B,this.model=null;let J=B.provider!=="bedrock";if(B.compressionEnabled&&(!J||B.apiKey))try{this.model=y({provider:B.provider,model:B.model,apiKey:B.apiKey},C(B))}catch{}}async summarize(B,J){if(J.length===0)return null;if(!this.config.compressionEnabled||!this.model)return this.createFallbackSummary(J);let K=w0(J.map((z)=>({type:z.type,title:z.title,narrative:z.narrative})),B);try{if(this.config.provider==="google")await O(this.config.model,this.config.rateLimitingEnabled);let{text:z}=await this._generate({model:this.model,maxOutputTokens:this.config.maxTokensPerCompression,prompt:K}),$=T0(z);if(!$)return this.createFallbackSummary(J);return $}catch{return this.createFallbackSummary(J)}}createFallbackSummary(B){let J=new Set,K=new Set,z=[];for(let Z of B){for(let Q of Z.filesModified)J.add(Q);for(let Q of Z.concepts)K.add(Q);if(Z.type==="decision")z.push(Z.title)}let $=new Map;for(let Z of B)$.set(Z.type,($.get(Z.type)??0)+1);let N=Array.from($.entries()).map(([Z,Q])=>`${Q} ${Z}${Q>1?"s":""}`).join(", "),W=Array.from(K).slice(0,5).join(", ");return{summary:`Session with ${B.length} observations: ${N}. Files modified: ${J.size}. Key concepts: ${W}.`,keyDecisions:z.slice(0,5),filesModified:Array.from(J),concepts:Array.from(K)}}shouldSummarize(B){return B>=2}}import{existsSync as dB,readFileSync as rB}from"fs";import{existsSync as bB,readdirSync as lB,readFileSync as cB}from"fs";import{join as c0}from"path";var J0=c0(import.meta.dir,"."),T=null;function nB(){if(T)return T;if(T=new Map,!bB(J0))return T;for(let B of lB(J0)){if(!B.endsWith(".json"))continue;try{let J=cB(c0(J0,B),"utf-8"),K=JSON.parse(J);if(K.id&&K.observationTypes&&K.conceptVocabulary)T.set(K.id,K)}catch{}}return T}function n0(){return[...nB().keys()].sort()}var sB={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 iB(){let B={};if(process.env.OPEN_MEM_DB_PATH)B.dbPath=process.env.OPEN_MEM_DB_PATH;if(process.env.OPEN_MEM_PROVIDER)B.provider=process.env.OPEN_MEM_PROVIDER;if(process.env.OPEN_MEM_MODEL)B.model=process.env.OPEN_MEM_MODEL;if(process.env.OPEN_MEM_MAX_CONTEXT_TOKENS)B.maxContextTokens=Number.parseInt(process.env.OPEN_MEM_MAX_CONTEXT_TOKENS,10);if(process.env.OPEN_MEM_COMPRESSION==="false")B.compressionEnabled=!1;if(process.env.OPEN_MEM_CONTEXT_INJECTION==="false")B.contextInjectionEnabled=!1;if(process.env.OPEN_MEM_IGNORED_TOOLS)B.ignoredTools=process.env.OPEN_MEM_IGNORED_TOOLS.split(",").map((J)=>J.trim());if(process.env.OPEN_MEM_BATCH_SIZE)B.batchSize=Number.parseInt(process.env.OPEN_MEM_BATCH_SIZE,10);if(process.env.OPEN_MEM_RETENTION_DAYS)B.retentionDays=Number.parseInt(process.env.OPEN_MEM_RETENTION_DAYS,10);if(process.env.OPEN_MEM_LOG_LEVEL)B.logLevel=process.env.OPEN_MEM_LOG_LEVEL;if(process.env.OPEN_MEM_CONTEXT_SHOW_TOKEN_COSTS==="false")B.contextShowTokenCosts=!1;if(process.env.OPEN_MEM_CONTEXT_TYPES)B.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)B.contextFullObservationCount=Number.parseInt(process.env.OPEN_MEM_CONTEXT_FULL_COUNT,10);if(process.env.OPEN_MEM_MAX_OBSERVATIONS)B.maxObservations=Number.parseInt(process.env.OPEN_MEM_MAX_OBSERVATIONS,10);if(process.env.OPEN_MEM_CONTEXT_SHOW_LAST_SUMMARY==="false")B.contextShowLastSummary=!1;if(process.env.OPEN_MEM_RATE_LIMITING==="false")B.rateLimitingEnabled=!1;if(process.env.OPEN_MEM_FOLDER_CONTEXT==="false")B.folderContextEnabled=!1;if(process.env.OPEN_MEM_FOLDER_CONTEXT_MAX_DEPTH)B.folderContextMaxDepth=Number.parseInt(process.env.OPEN_MEM_FOLDER_CONTEXT_MAX_DEPTH,10);if(process.env.OPEN_MEM_FOLDER_CONTEXT_MODE==="single")B.folderContextMode="single";if(process.env.OPEN_MEM_FOLDER_CONTEXT_MODE==="dispersed")B.folderContextMode="dispersed";if(process.env.OPEN_MEM_FOLDER_CONTEXT_FILENAME)B.folderContextFilename=process.env.OPEN_MEM_FOLDER_CONTEXT_FILENAME;if(process.env.OPEN_MEM_DAEMON==="true")B.daemonEnabled=!0;if(process.env.OPEN_MEM_DASHBOARD==="true")B.dashboardEnabled=!0;if(process.env.OPEN_MEM_DASHBOARD_PORT)B.dashboardPort=Number.parseInt(process.env.OPEN_MEM_DASHBOARD_PORT,10);if(process.env.OPEN_MEM_PLATFORM_OPENCODE==="false")B.platformOpenCodeEnabled=!1;if(process.env.OPEN_MEM_PLATFORM_CLAUDE_CODE==="true")B.platformClaudeCodeEnabled=!0;if(process.env.OPEN_MEM_PLATFORM_CURSOR==="true")B.platformCursorEnabled=!0;if(process.env.OPEN_MEM_MCP_COMPAT_MODE)B.mcpCompatibilityMode=process.env.OPEN_MEM_MCP_COMPAT_MODE;if(process.env.OPEN_MEM_MCP_PROTOCOL_VERSION)B.mcpProtocolVersion=process.env.OPEN_MEM_MCP_PROTOCOL_VERSION;if(process.env.OPEN_MEM_MCP_SUPPORTED_PROTOCOLS)B.mcpSupportedProtocolVersions=process.env.OPEN_MEM_MCP_SUPPORTED_PROTOCOLS.split(",").map((J)=>J.trim()).filter(Boolean);if(process.env.OPEN_MEM_EMBEDDING_DIMENSION)B.embeddingDimension=Number.parseInt(process.env.OPEN_MEM_EMBEDDING_DIMENSION,10);if(process.env.OPEN_MEM_CONFLICT_RESOLUTION==="true")B.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))B.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))B.conflictSimilarityBandHigh=J}if(process.env.OPEN_MEM_USER_MEMORY==="true")B.userMemoryEnabled=!0;if(process.env.OPEN_MEM_USER_MEMORY_DB_PATH)B.userMemoryDbPath=process.env.OPEN_MEM_USER_MEMORY_DB_PATH;if(process.env.OPEN_MEM_USER_MEMORY_MAX_TOKENS)B.userMemoryMaxContextTokens=Number.parseInt(process.env.OPEN_MEM_USER_MEMORY_MAX_TOKENS,10);if(process.env.OPEN_MEM_RERANKING==="true")B.rerankingEnabled=!0;if(process.env.OPEN_MEM_RERANKING_MAX_CANDIDATES)B.rerankingMaxCandidates=Number.parseInt(process.env.OPEN_MEM_RERANKING_MAX_CANDIDATES,10);if(process.env.OPEN_MEM_ENTITY_EXTRACTION==="true")B.entityExtractionEnabled=!0;if(process.env.OPEN_MEM_FALLBACK_PROVIDERS)B.fallbackProviders=process.env.OPEN_MEM_FALLBACK_PROVIDERS.split(",").map((J)=>J.trim()).filter(Boolean);if(process.env.OPEN_MEM_MODE)B.mode=process.env.OPEN_MEM_MODE;return B}function tB(B){let J=`${B}/.open-mem/config.json`;if(!dB(J))return{};try{let K=rB(J,"utf-8"),z=JSON.parse(K);if(!z||typeof z!=="object"||Array.isArray(z))return{};return z}catch{return{}}}function aB(B){switch(B){case"google":return 768;case"openai":return 1536;case"bedrock":return 1024;case"anthropic":return 0;case"openrouter":return 0;default:return 768}}function d0(B,J){let K=tB(B),z=iB(),$={...sB,...K,...z,...J};if(!$.dbPath.startsWith("/"))$.dbPath=`${B}/${$.dbPath}`;if(!process.env.OPEN_MEM_PROVIDER&&!J?.provider){if(process.env.GOOGLE_GENERATIVE_AI_API_KEY||process.env.GEMINI_API_KEY)$.provider="google";else if(process.env.ANTHROPIC_API_KEY)$.provider="anthropic";else if(process.env.AWS_BEARER_TOKEN_BEDROCK||process.env.AWS_ACCESS_KEY_ID||process.env.AWS_PROFILE)$.provider="bedrock";else if(process.env.OPENROUTER_API_KEY)$.provider="openrouter"}if(!$.apiKey)switch($.provider){case"google":$.apiKey=process.env.GOOGLE_GENERATIVE_AI_API_KEY||process.env.GEMINI_API_KEY;break;case"anthropic":$.apiKey=process.env.ANTHROPIC_API_KEY;break;case"openai":$.apiKey=process.env.OPENAI_API_KEY;break;case"openrouter":$.apiKey=process.env.OPENROUTER_API_KEY;break;case"bedrock":break}if($.provider==="openrouter"&&$.model==="gemini-2.5-flash-lite")$.model="google/gemini-2.5-flash-lite";if($.embeddingDimension===void 0)$.embeddingDimension=aB($.provider);if($.mode&&!n0().includes($.mode))$.mode="code";return $}import{Database as r0}from"bun:sqlite";import{existsSync as K0,mkdirSync as oB,unlinkSync as s0}from"fs";import*as i0 from"sqlite-vec";class l{db;dbPath;_hasVectorExtension=!1;static enableExtensionSupport(){let B=["/opt/homebrew/opt/sqlite/lib/libsqlite3.dylib","/usr/local/opt/sqlite/lib/libsqlite3.dylib"];for(let J of B)try{if(K0(J))return r0.setCustomSQLite(J),!0}catch{return!1}return!1}constructor(B){this.dbPath=B,this.db=this.open(B),this.configure()}open(B){let J=B.lastIndexOf("/");if(J>0){let K=B.substring(0,J);oB(K,{recursive:!0})}return new r0(B,{create:!0})}configure(){try{this.applyPragmas(),this.loadExtensions()}catch(B){console.warn("[open-mem] Database configure failed, attempting recovery by removing WAL/SHM files:",B.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(K){throw console.warn("[open-mem] All recovery attempts failed, filesystem may be broken:",K.message),B}}}}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{i0.load(this.db),this._hasVectorExtension=!0}catch{this._hasVectorExtension=!1}}get hasVectorExtension(){return this._hasVectorExtension}deleteSidecarFiles(){for(let B of["-wal","-shm"]){let J=this.dbPath+B;try{if(K0(J))s0(J)}catch{}}}deleteDatabaseFiles(){this.deleteSidecarFiles();try{if(K0(this.dbPath))s0(this.dbPath)}catch{}}ensureMigrationTable(){this.db.exec(`
|
|
160
|
+
[... truncated ...]`:y,J=nu(u,A,B),K=2;for(let V=0;V<=K;V++)try{if(this.config.provider==="google")await F(this.config.model,this.config.rateLimitingEnabled);let{text:R}=await this._generate({model:this.model,maxOutputTokens:this.config.maxTokensPerCompression,prompt:J}),z=hu(R);if(z)z.discoveryTokens=$;return z}catch(R){if(m(R)&&V<K){let z=2**V*1000;await O(z);continue}return null}return null}async compressBatch(u){let y=new Map;for(let B=0;B<u.length;B++){let $=u[B],A=await this.compress($.toolName,$.toolOutput,$.sessionContext);if(y.set($.callId,A),B<u.length-1)await O(200)}return y}createFallbackObservation(u,y){let B=by(y),$=vy[u]??"discovery";return{type:$,title:`${u} execution`,subtitle:y.substring(0,100).replace(/\n/g," "),facts:[],narrative:`Tool ${u} was executed. Output length: ${y.length} chars.`,concepts:[],filesRead:$==="discovery"?B:[],filesModified:$==="change"?B:[],discoveryTokens:P(y),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 vy={Read:"discovery",Write:"change",Edit:"change",Bash:"change",Glob:"discovery",Grep:"discovery"},ly=/(?:^|\s)((?:\.\/|\/|src\/|tests\/|lib\/)\S+\.\w+)/gm;function by(u){let y=[];for(let B of u.matchAll(ly))y.push(B[1]);return[...new Set(y)]}import{generateText as ry}from"ai";class yu{model;config;_generate=ry;constructor(u){if(this.config=u,this.model=null,u.provider==="bedrock"||u.apiKey)try{this.model=C({provider:u.provider,model:u.model,apiKey:u.apiKey},_(u))}catch{}}async evaluate(u,y){if(!this.model||y.length===0)return null;let B=cu(u,y),$=2;for(let A=0;A<=$;A++)try{if(this.config.provider==="google")await F(this.config.model,this.config.rateLimitingEnabled);let{text:J}=await this._generate({model:this.model,maxOutputTokens:512,prompt:B});return wu(J)}catch(J){if(m(J)&&A<$){let K=2**A*1000;await O(K);continue}return null}return null}}import{generateText as dy}from"ai";class Bu{model;config;_generate=dy;constructor(u){if(this.config=u,this.model=null,u.provider==="bedrock"||u.apiKey)try{this.model=C({provider:u.provider,model:u.model,apiKey:u.apiKey},_(u))}catch{}}async extract(u){if(!this.model)return null;let y=vu(u),B=2;for(let $=0;$<=B;$++)try{if(this.config.provider==="google")await F(this.config.model,this.config.rateLimitingEnabled);let{text:A}=await this._generate({model:this.model,maxOutputTokens:1024,prompt:y});return Iu(A)}catch(A){if(m(A)&&$<B){let J=2**$*1000;await O(J);continue}return null}return null}}import{generateText as iy}from"ai";class $u{model;config;_generate=iy;constructor(u){this.config=u,this.model=null;let y=u.provider!=="bedrock";if(u.compressionEnabled&&(!y||u.apiKey))try{this.model=C({provider:u.provider,model:u.model,apiKey:u.apiKey},_(u))}catch{}}async summarize(u,y){if(y.length===0)return null;if(!this.config.compressionEnabled||!this.model)return this.createFallbackSummary(y);let B=gu(y.map(($)=>({type:$.type,title:$.title,narrative:$.narrative})),u);try{if(this.config.provider==="google")await F(this.config.model,this.config.rateLimitingEnabled);let{text:$}=await this._generate({model:this.model,maxOutputTokens:this.config.maxTokensPerCompression,prompt:B}),A=xu($);if(!A)return this.createFallbackSummary(y);return A}catch{return this.createFallbackSummary(y)}}createFallbackSummary(u){let y=new Set,B=new Set,$=[];for(let V of u){for(let R of V.filesModified)y.add(R);for(let R of V.concepts)B.add(R);if(V.type==="decision")$.push(V.title)}let A=new Map;for(let V of u)A.set(V.type,(A.get(V.type)??0)+1);let J=Array.from(A.entries()).map(([V,R])=>`${R} ${V}${R>1?"s":""}`).join(", "),K=Array.from(B).slice(0,5).join(", ");return{summary:`Session with ${u.length} observations: ${J}. Files modified: ${y.size}. Key concepts: ${K}.`,keyDecisions:$.slice(0,5),filesModified:Array.from(y),concepts:Array.from(B)}}shouldSummarize(u){return u>=2}}import{existsSync as J0,readFileSync as K0}from"fs";import{join as y0}from"path";import{existsSync as sy,readdirSync as ty,readFileSync as oy}from"fs";import{join as ey}from"path";var q={id:"code",name:"Code",description:"Default coding workflow mode",observationTypes:["decision","bugfix","feature","refactor","discovery","change"],conceptVocabulary:["how-it-works","why-it-exists","what-changed","problem-solution","gotcha","pattern","trade-off"],entityTypes:["technology","library","pattern","concept","file","person","project","other"],relationshipTypes:["uses","depends_on","implements","extends","related_to","replaces","configures"]};function T(u){return{...u,observationTypes:[...u.observationTypes],conceptVocabulary:[...u.conceptVocabulary],entityTypes:[...u.entityTypes],relationshipTypes:[...u.relationshipTypes],promptOverrides:u.promptOverrides?{...u.promptOverrides}:void 0}}function ay(u){if(!u||typeof u!=="object")return!1;let y=u,B=(A)=>Array.isArray(A)&&A.every((J)=>typeof J==="string"),$=(A)=>typeof A==="object"&&A!==null&&!Array.isArray(A)&&Object.values(A).every((J)=>typeof J==="string");return typeof y.id==="string"&&(y.extends===void 0||typeof y.extends==="string")&&(y.locale===void 0||typeof y.locale==="string")&&(y.name===void 0||typeof y.name==="string")&&(y.description===void 0||typeof y.description==="string")&&(y.observationTypes===void 0||B(y.observationTypes))&&(y.conceptVocabulary===void 0||B(y.conceptVocabulary))&&(y.entityTypes===void 0||B(y.entityTypes))&&(y.relationshipTypes===void 0||B(y.relationshipTypes))&&(y.promptOverrides===void 0||$(y.promptOverrides))}function u0(u){return typeof u.name==="string"&&typeof u.description==="string"&&Array.isArray(u.observationTypes)&&Array.isArray(u.conceptVocabulary)&&Array.isArray(u.entityTypes)&&Array.isArray(u.relationshipTypes)}function du(u,y){return{...u,...y,id:y.id,name:y.name??u.name,description:y.description??u.description,observationTypes:y.observationTypes??u.observationTypes,conceptVocabulary:y.conceptVocabulary??u.conceptVocabulary,entityTypes:y.entityTypes??u.entityTypes,relationshipTypes:y.relationshipTypes??u.relationshipTypes,promptOverrides:{...u.promptOverrides??{},...y.promptOverrides??{}}}}class Au{modesDir;constructor(u){this.modesDir=u}loadAllRaw(){let u=new Map;if(!sy(this.modesDir))return u;for(let y of ty(this.modesDir)){if(!y.endsWith(".json"))continue;let B=ey(this.modesDir,y);try{let $=oy(B,"utf-8"),A=JSON.parse($);if(!ay(A))continue;if(u.has(A.id))console.warn(`[open-mem] Duplicate mode id "${A.id}" in ${B}; overriding previous definition.`);u.set(A.id,A)}catch{}}return u}resolveById(u,y){let B=new Set,$=!1,A=(K)=>{if(B.has(K))return $=!0,T(q);B.add(K);let V=y.get(K);if(!V)return T(q);if(!V.extends){if(!u0(V))return T(q);return du(T(q),V)}let R=A(V.extends);if($)return T(q);return du(R,V)},J=A(u);return $?T(q):T(J)}}var B0=y0(import.meta.dir,"."),$0=new Au(B0),b=null;function A0(){if(b)return b;return b=$0.loadAllRaw(),b}function iu(){return[...A0().keys()].sort()}var z0={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,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 R0(){let u={};if(process.env.OPEN_MEM_DB_PATH)u.dbPath=process.env.OPEN_MEM_DB_PATH;if(process.env.OPEN_MEM_PROVIDER)u.provider=process.env.OPEN_MEM_PROVIDER;if(process.env.OPEN_MEM_MODEL)u.model=process.env.OPEN_MEM_MODEL;if(process.env.OPEN_MEM_MAX_CONTEXT_TOKENS)u.maxContextTokens=Number.parseInt(process.env.OPEN_MEM_MAX_CONTEXT_TOKENS,10);if(process.env.OPEN_MEM_COMPRESSION==="false")u.compressionEnabled=!1;if(process.env.OPEN_MEM_CONTEXT_INJECTION==="false")u.contextInjectionEnabled=!1;if(process.env.OPEN_MEM_IGNORED_TOOLS)u.ignoredTools=process.env.OPEN_MEM_IGNORED_TOOLS.split(",").map((y)=>y.trim());if(process.env.OPEN_MEM_BATCH_SIZE)u.batchSize=Number.parseInt(process.env.OPEN_MEM_BATCH_SIZE,10);if(process.env.OPEN_MEM_RETENTION_DAYS)u.retentionDays=Number.parseInt(process.env.OPEN_MEM_RETENTION_DAYS,10);if(process.env.OPEN_MEM_LOG_LEVEL)u.logLevel=process.env.OPEN_MEM_LOG_LEVEL;if(process.env.OPEN_MEM_CONTEXT_SHOW_TOKEN_COSTS==="false")u.contextShowTokenCosts=!1;if(process.env.OPEN_MEM_CONTEXT_TYPES)u.contextObservationTypes=process.env.OPEN_MEM_CONTEXT_TYPES==="all"?"all":process.env.OPEN_MEM_CONTEXT_TYPES.split(",").map((y)=>y.trim());if(process.env.OPEN_MEM_CONTEXT_FULL_COUNT)u.contextFullObservationCount=Number.parseInt(process.env.OPEN_MEM_CONTEXT_FULL_COUNT,10);if(process.env.OPEN_MEM_MAX_OBSERVATIONS)u.maxObservations=Number.parseInt(process.env.OPEN_MEM_MAX_OBSERVATIONS,10);if(process.env.OPEN_MEM_CONTEXT_SHOW_LAST_SUMMARY==="false")u.contextShowLastSummary=!1;if(process.env.OPEN_MEM_RATE_LIMITING==="false")u.rateLimitingEnabled=!1;if(process.env.OPEN_MEM_FOLDER_CONTEXT==="false")u.folderContextEnabled=!1;if(process.env.OPEN_MEM_FOLDER_CONTEXT_MAX_DEPTH)u.folderContextMaxDepth=Number.parseInt(process.env.OPEN_MEM_FOLDER_CONTEXT_MAX_DEPTH,10);if(process.env.OPEN_MEM_FOLDER_CONTEXT_MODE==="single")u.folderContextMode="single";if(process.env.OPEN_MEM_FOLDER_CONTEXT_MODE==="dispersed")u.folderContextMode="dispersed";if(process.env.OPEN_MEM_FOLDER_CONTEXT_FILENAME)u.folderContextFilename=process.env.OPEN_MEM_FOLDER_CONTEXT_FILENAME;if(process.env.OPEN_MEM_DAEMON==="true")u.daemonEnabled=!0;if(process.env.OPEN_MEM_DASHBOARD==="true")u.dashboardEnabled=!0;if(process.env.OPEN_MEM_DASHBOARD_PORT)u.dashboardPort=Number.parseInt(process.env.OPEN_MEM_DASHBOARD_PORT,10);if(process.env.OPEN_MEM_PLATFORM_OPENCODE==="false")u.platformOpenCodeEnabled=!1;if(process.env.OPEN_MEM_PLATFORM_CLAUDE_CODE==="true")u.platformClaudeCodeEnabled=!0;if(process.env.OPEN_MEM_PLATFORM_CURSOR==="true")u.platformCursorEnabled=!0;if(process.env.OPEN_MEM_MCP_PROTOCOL_VERSION)u.mcpProtocolVersion=process.env.OPEN_MEM_MCP_PROTOCOL_VERSION;if(process.env.OPEN_MEM_MCP_SUPPORTED_PROTOCOLS)u.mcpSupportedProtocolVersions=process.env.OPEN_MEM_MCP_SUPPORTED_PROTOCOLS.split(",").map((y)=>y.trim()).filter(Boolean);if(process.env.OPEN_MEM_EMBEDDING_DIMENSION)u.embeddingDimension=Number.parseInt(process.env.OPEN_MEM_EMBEDDING_DIMENSION,10);if(process.env.OPEN_MEM_CONFLICT_RESOLUTION==="true")u.conflictResolutionEnabled=!0;if(process.env.OPEN_MEM_CONFLICT_BAND_LOW){let y=Number.parseFloat(process.env.OPEN_MEM_CONFLICT_BAND_LOW);if(!Number.isNaN(y))u.conflictSimilarityBandLow=y}if(process.env.OPEN_MEM_CONFLICT_BAND_HIGH){let y=Number.parseFloat(process.env.OPEN_MEM_CONFLICT_BAND_HIGH);if(!Number.isNaN(y))u.conflictSimilarityBandHigh=y}if(process.env.OPEN_MEM_USER_MEMORY==="true")u.userMemoryEnabled=!0;if(process.env.OPEN_MEM_USER_MEMORY_DB_PATH)u.userMemoryDbPath=process.env.OPEN_MEM_USER_MEMORY_DB_PATH;if(process.env.OPEN_MEM_USER_MEMORY_MAX_TOKENS)u.userMemoryMaxContextTokens=Number.parseInt(process.env.OPEN_MEM_USER_MEMORY_MAX_TOKENS,10);if(process.env.OPEN_MEM_RERANKING==="true")u.rerankingEnabled=!0;if(process.env.OPEN_MEM_RERANKING_MAX_CANDIDATES)u.rerankingMaxCandidates=Number.parseInt(process.env.OPEN_MEM_RERANKING_MAX_CANDIDATES,10);if(process.env.OPEN_MEM_ENTITY_EXTRACTION==="true")u.entityExtractionEnabled=!0;if(process.env.OPEN_MEM_FALLBACK_PROVIDERS)u.fallbackProviders=process.env.OPEN_MEM_FALLBACK_PROVIDERS.split(",").map((y)=>y.trim()).filter(Boolean);if(process.env.OPEN_MEM_MODE)u.mode=process.env.OPEN_MEM_MODE;return u}function V0(u){let y=`${u}/.open-mem/config.json`;if(!J0(y))return{};try{let B=K0(y,"utf-8"),$=JSON.parse(B);if(!$||typeof $!=="object"||Array.isArray($))return{};return $}catch{return{}}}function N0(u){switch(u){case"google":return 768;case"openai":return 1536;case"bedrock":return 1024;case"anthropic":return 0;case"openrouter":return 0;default:return 768}}function su(u,y){let B=V0(u),$=R0(),A={...z0,...B,...$,...y};if(!A.dbPath.startsWith("/"))A.dbPath=`${u}/${A.dbPath}`;if(!process.env.OPEN_MEM_PROVIDER&&!y?.provider){if(process.env.GOOGLE_GENERATIVE_AI_API_KEY||process.env.GEMINI_API_KEY)A.provider="google";else if(process.env.ANTHROPIC_API_KEY)A.provider="anthropic";else if(process.env.AWS_BEARER_TOKEN_BEDROCK||process.env.AWS_ACCESS_KEY_ID||process.env.AWS_PROFILE)A.provider="bedrock";else if(process.env.OPENROUTER_API_KEY)A.provider="openrouter"}if(!A.apiKey)switch(A.provider){case"google":A.apiKey=process.env.GOOGLE_GENERATIVE_AI_API_KEY||process.env.GEMINI_API_KEY;break;case"anthropic":A.apiKey=process.env.ANTHROPIC_API_KEY;break;case"openai":A.apiKey=process.env.OPENAI_API_KEY;break;case"openrouter":A.apiKey=process.env.OPENROUTER_API_KEY;break;case"bedrock":break}if(A.provider==="openrouter"&&A.model==="gemini-2.5-flash-lite")A.model="google/gemini-2.5-flash-lite";if(A.embeddingDimension===void 0)A.embeddingDimension=N0(A.provider);if(A.mode&&!iu().includes(A.mode))A.mode="code";return A}import{Database as tu}from"bun:sqlite";import{existsSync as Ju,mkdirSync as E0,unlinkSync as ou}from"fs";import*as eu from"sqlite-vec";class r{db;dbPath;_hasVectorExtension=!1;static enableExtensionSupport(){let u=["/opt/homebrew/opt/sqlite/lib/libsqlite3.dylib","/usr/local/opt/sqlite/lib/libsqlite3.dylib"];for(let y of u)try{if(Ju(y))return tu.setCustomSQLite(y),!0}catch{return!1}return!1}constructor(u){this.dbPath=u,this.db=this.open(u),this.configure()}open(u){let y=u.lastIndexOf("/");if(y>0){let B=u.substring(0,y);E0(B,{recursive:!0})}return new tu(u,{create:!0})}configure(){try{this.applyPragmas(),this.loadExtensions()}catch(u){console.warn("[open-mem] Database configure failed, attempting recovery by removing WAL/SHM files:",u.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(y){console.warn("[open-mem] WAL/SHM cleanup insufficient, recreating database from scratch:",y.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(B){throw console.warn("[open-mem] All recovery attempts failed, filesystem may be broken:",B.message),u}}}}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{eu.load(this.db),this._hasVectorExtension=!0}catch{this._hasVectorExtension=!1}}get hasVectorExtension(){return this._hasVectorExtension}deleteSidecarFiles(){for(let u of["-wal","-shm"]){let y=this.dbPath+u;try{if(Ju(y))ou(y)}catch{}}}deleteDatabaseFiles(){this.deleteSidecarFiles();try{if(Ju(this.dbPath))ou(this.dbPath)}catch{}}ensureMigrationTable(){this.db.exec(`
|
|
161
161
|
CREATE TABLE IF NOT EXISTS _migrations (
|
|
162
162
|
version INTEGER PRIMARY KEY,
|
|
163
163
|
name TEXT NOT NULL,
|
|
164
164
|
applied_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
165
165
|
)
|
|
166
|
-
`)}migrate(
|
|
166
|
+
`)}migrate(u){this.ensureMigrationTable();let y=this.db.query("SELECT version FROM _migrations ORDER BY version").all(),B=new Set(y.map((A)=>A.version)),$=u.filter((A)=>!B.has(A.version)).sort((A,J)=>A.version-J.version);for(let A of $)this.db.transaction(()=>{this.db.exec(A.up),this.db.query("INSERT INTO _migrations (version, name) VALUES ($version, $name)").run({$version:A.version,$name:A.name})})()}run(u,y){let B=this.db.query(u);if(y)B.run(...y);else B.run()}get(u,y){let B=this.db.query(u);return y?B.get(...y):B.get()}all(u,y){let B=this.db.query(u);return y?B.all(...y):B.all()}exec(u){this.db.exec(u)}transaction(u){return this.db.transaction(u)()}close(){this.db.close()}get isOpen(){try{return this.db.query("SELECT 1").get(),!0}catch{return!1}}get raw(){return this.db}}function au(u){return new r(u)}import{randomUUID as uy}from"crypto";class Ku{db;constructor(u){this.db=u}upsertEntity(u,y){let B=uy(),$=new Date().toISOString();this.db.run(`INSERT INTO entities (id, name, entity_type, first_seen_at, last_seen_at, mention_count)
|
|
167
167
|
VALUES (?, ?, ?, ?, ?, 1)
|
|
168
168
|
ON CONFLICT(name, entity_type) DO UPDATE SET
|
|
169
169
|
mention_count = mention_count + 1,
|
|
170
|
-
last_seen_at = ?`,[
|
|
170
|
+
last_seen_at = ?`,[B,u,y,$,$,$]);let A=this.db.get("SELECT * FROM entities WHERE name = ? AND entity_type = ?",[u,y]);if(!A)throw Error(`Failed to upsert entity: ${u} (${y})`);return this.mapEntityRow(A)}createRelation(u,y,B,$){let A=uy(),J=new Date().toISOString();try{this.db.run(`INSERT OR IGNORE INTO entity_relations
|
|
171
171
|
(id, source_entity_id, target_entity_id, relationship, observation_id, created_at)
|
|
172
|
-
VALUES (?, ?, ?, ?, ?, ?)`,[
|
|
173
|
-
WHERE source_entity_id = ? AND target_entity_id = ? AND relationship = ?`,[
|
|
172
|
+
VALUES (?, ?, ?, ?, ?, ?)`,[A,u,y,B,$,J])}catch{return null}let K=this.db.get(`SELECT * FROM entity_relations
|
|
173
|
+
WHERE source_entity_id = ? AND target_entity_id = ? AND relationship = ?`,[u,y,B]);return K?this.mapRelationRow(K):null}linkObservation(u,y){this.db.run("INSERT OR IGNORE INTO entity_observations (entity_id, observation_id) VALUES (?, ?)",[u,y])}findByName(u){try{return this.db.all(`SELECT e.*
|
|
174
174
|
FROM entities e
|
|
175
175
|
JOIN entities_fts fts ON e._rowid = fts.rowid
|
|
176
176
|
WHERE entities_fts MATCH ?
|
|
177
|
-
ORDER BY rank`,[
|
|
178
|
-
WHERE source_entity_id = ? OR target_entity_id = ?`,[
|
|
179
|
-
`)}function
|
|
177
|
+
ORDER BY rank`,[u]).map((B)=>this.mapEntityRow(B))}catch{return[]}}getRelationsFor(u){return this.db.all(`SELECT * FROM entity_relations
|
|
178
|
+
WHERE source_entity_id = ? OR target_entity_id = ?`,[u,u]).map((B)=>this.mapRelationRow(B))}traverseRelations(u,y=1){let B=Math.min(y,2),$=100,A=new Set,J=[{id:u,currentDepth:0}];A.add(u);while(J.length>0){if(A.size>=100)break;let K=J.shift();if(!K)continue;if(K.currentDepth>=B)continue;let V=this.getRelationsFor(K.id);for(let R of V){let z=R.sourceEntityId===K.id?R.targetEntityId:R.sourceEntityId;if(!A.has(z))A.add(z),J.push({id:z,currentDepth:K.currentDepth+1})}}return A}getObservationsForEntity(u){return this.db.all("SELECT observation_id FROM entity_observations WHERE entity_id = ?",[u]).map((B)=>B.observation_id)}getById(u){let y=this.db.get("SELECT * FROM entities WHERE id = ?",[u]);return y?this.mapEntityRow(y):null}mapEntityRow(u){return{id:u.id,name:u.name,entityType:u.entity_type,firstSeenAt:u.first_seen_at,lastSeenAt:u.last_seen_at,mentionCount:u.mention_count}}mapRelationRow(u){return{id:u.id,sourceEntityId:u.source_entity_id,targetEntityId:u.target_entity_id,relationship:u.relationship,observationId:u.observation_id,createdAt:u.created_at}}}import{randomUUID as H0}from"crypto";import{embed as W0}from"ai";async function zu(u,y){try{let{embedding:B}=await W0({model:u,value:y});return B}catch{return null}}function yy(u,y){if(u.length!==y.length||u.length===0)return 0;let B=0,$=0,A=0;for(let K=0;K<u.length;K++)B+=u[K]*y[K],$+=u[K]*u[K],A+=y[K]*y[K];let J=Math.sqrt($)*Math.sqrt(A);if(J===0)return 0;return B/J}function Ru(u){let y=[u.title,u.narrative];if(u.concepts.length>0)y.push(u.concepts.join(", "));return y.join(`
|
|
179
|
+
`)}function Q0(u){return u.replace(/[%_\\]/g,"\\$&")}class Vu{db;constructor(u){this.db=u}create(u){let y=H0(),B=new Date().toISOString(),$=u.discoveryTokens??0,A=u.importance??3,J=u.scope??"project";return this.db.run(`INSERT INTO observations
|
|
180
180
|
(id, session_id, scope, type, title, subtitle, facts, narrative,
|
|
181
181
|
concepts, files_read, files_modified, raw_tool_output,
|
|
182
182
|
tool_name, created_at, token_count, discovery_tokens, importance, revision_of, deleted_at)
|
|
183
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,[
|
|
183
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,[y,u.sessionId,J,u.type,u.title,u.subtitle,JSON.stringify(u.facts),u.narrative,JSON.stringify(u.concepts),JSON.stringify(u.filesRead),JSON.stringify(u.filesModified),u.rawToolOutput,u.toolName,B,u.tokenCount,$,A,null,null]),{...u,id:y,scope:J,createdAt:B,discoveryTokens:$,importance:A,revisionOf:null,deletedAt:null,supersededBy:null,supersededAt:null}}importObservation(u){this.db.run(`INSERT INTO observations
|
|
184
184
|
(id, session_id, scope, type, title, subtitle, facts, narrative,
|
|
185
185
|
concepts, files_read, files_modified, raw_tool_output,
|
|
186
186
|
tool_name, created_at, token_count, discovery_tokens, importance, revision_of, deleted_at)
|
|
187
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,[
|
|
187
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,[u.id,u.sessionId,u.scope??"project",u.type,u.title,u.subtitle,JSON.stringify(u.facts),u.narrative,JSON.stringify(u.concepts),JSON.stringify(u.filesRead),JSON.stringify(u.filesModified),u.rawToolOutput,u.toolName,u.createdAt,u.tokenCount,u.discoveryTokens??0,u.importance??3,u.revisionOf??null,u.deletedAt??null])}getById(u){let y=this.db.get("SELECT * FROM observations WHERE id = ? AND superseded_by IS NULL AND deleted_at IS NULL",[u]);return y?this.mapRow(y):null}getByIdIncludingArchived(u){let y=this.db.get("SELECT * FROM observations WHERE id = ?",[u]);return y?this.mapRow(y):null}getBySession(u){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",[u]).map((y)=>this.mapRow(y))}getCount(u){if(u)return this.db.get("SELECT COUNT(*) as count FROM observations WHERE session_id = ?",[u])?.count??0;return this.db.get("SELECT COUNT(*) as count FROM observations")?.count??0}getIndex(u,y=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
|
|
188
188
|
FROM observations o
|
|
189
189
|
JOIN sessions s ON o.session_id = s.id
|
|
190
190
|
WHERE s.project_path = ? AND o.superseded_by IS NULL AND o.deleted_at IS NULL
|
|
191
191
|
ORDER BY o.created_at DESC
|
|
192
|
-
LIMIT ?`,[
|
|
192
|
+
LIMIT ?`,[u,y]).map((B)=>({id:B.id,sessionId:B.session_id,type:B.type,title:B.title,tokenCount:B.token_count,discoveryTokens:B.discovery_tokens??0,createdAt:B.created_at,importance:B.importance??3}))}getAroundTimestamp(u,y,B,$){let A=y>0?this.db.all(`SELECT o.*
|
|
193
193
|
FROM observations o
|
|
194
194
|
JOIN sessions s ON o.session_id = s.id
|
|
195
195
|
WHERE s.project_path = ? AND o.created_at < ?
|
|
196
196
|
AND o.superseded_by IS NULL AND o.deleted_at IS NULL
|
|
197
197
|
ORDER BY o.created_at DESC
|
|
198
|
-
LIMIT ?`,[
|
|
198
|
+
LIMIT ?`,[$,u,y]).reverse():[],J=B>0?this.db.all(`SELECT o.*
|
|
199
199
|
FROM observations o
|
|
200
200
|
JOIN sessions s ON o.session_id = s.id
|
|
201
201
|
WHERE s.project_path = ? AND o.created_at > ?
|
|
202
202
|
AND o.superseded_by IS NULL AND o.deleted_at IS NULL
|
|
203
203
|
ORDER BY o.created_at ASC
|
|
204
|
-
LIMIT ?`,[
|
|
204
|
+
LIMIT ?`,[$,u,B]):[];return[...A,...J].map((K)=>this.mapRow(K))}listByProject(u,y={}){let{limit:B=50,offset:$=0,type:A,state:J,sessionId:K}=y,V=`SELECT o.*
|
|
205
205
|
FROM observations o
|
|
206
206
|
JOIN sessions s ON o.session_id = s.id
|
|
207
|
-
WHERE s.project_path = ?`,
|
|
207
|
+
WHERE s.project_path = ?`,R=[u];if(K)V+=" AND o.session_id = ?",R.push(K);if(A)V+=" AND o.type = ?",R.push(A);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 ?",R.push(B,$),this.db.all(V,R).map((z)=>this.mapRow(z))}search(u){let y=!!u.projectPath,B=`
|
|
208
208
|
SELECT o.*, rank
|
|
209
209
|
FROM observations o
|
|
210
210
|
JOIN observations_fts fts ON o._rowid = fts.rowid
|
|
211
|
-
${
|
|
211
|
+
${y?"JOIN sessions s ON o.session_id = s.id":""}
|
|
212
212
|
WHERE observations_fts MATCH ? AND o.superseded_by IS NULL AND o.deleted_at IS NULL
|
|
213
|
-
|
|
214
|
-
OR EXISTS (SELECT 1 FROM json_each(o.files_modified) WHERE LOWER(value) LIKE LOWER(?) ESCAPE '\\'))`);
|
|
213
|
+
`,$=[u.query];if(y&&u.projectPath)B+=" AND s.project_path = ?",$.push(u.projectPath);if(u.sessionId)B+=" AND o.session_id = ?",$.push(u.sessionId);if(u.type)B+=" AND o.type = ?",$.push(u.type);if(u.importanceMin!==void 0)B+=" AND o.importance >= ?",$.push(u.importanceMin);if(u.importanceMax!==void 0)B+=" AND o.importance <= ?",$.push(u.importanceMax);if(u.createdAfter)B+=" AND o.created_at >= ?",$.push(u.createdAfter);if(u.createdBefore)B+=" AND o.created_at <= ?",$.push(u.createdBefore);if(u.concepts&&u.concepts.length>0){let A=u.concepts.map(()=>"EXISTS (SELECT 1 FROM json_each(o.concepts) WHERE LOWER(value) = LOWER(?))");B+=` AND (${A.join(" OR ")})`;for(let J of u.concepts)$.push(J)}if(u.files&&u.files.length>0){let A=u.files.map(()=>`(EXISTS (SELECT 1 FROM json_each(o.files_read) WHERE LOWER(value) LIKE LOWER(?) ESCAPE '\\')
|
|
214
|
+
OR EXISTS (SELECT 1 FROM json_each(o.files_modified) WHERE LOWER(value) LIKE LOWER(?) ESCAPE '\\'))`);B+=` AND (${A.join(" OR ")})`;for(let J of u.files){let K=`%${Q0(J)}%`;$.push(K,K)}}return B+=" ORDER BY rank LIMIT ? OFFSET ?",$.push(u.limit??10),$.push(u.offset??0),this.db.all(B,$).map((A)=>({observation:this.mapRow(A),rank:A.rank,snippet:A.title}))}searchByConcept(u,y=10,B){let $=!!B,A=`SELECT o.*
|
|
215
215
|
FROM observations o
|
|
216
216
|
JOIN observations_fts fts ON o._rowid = fts.rowid
|
|
217
|
-
${
|
|
217
|
+
${$?"JOIN sessions s ON o.session_id = s.id":""}
|
|
218
218
|
WHERE observations_fts MATCH ?
|
|
219
219
|
AND o.superseded_by IS NULL AND o.deleted_at IS NULL
|
|
220
|
-
${
|
|
220
|
+
${$?"AND s.project_path = ?":""}
|
|
221
221
|
ORDER BY rank
|
|
222
|
-
LIMIT ?`,
|
|
222
|
+
LIMIT ?`,K=[`concepts:"${u.replace(/"/g,'""')}"`];if($&&B)K.push(B);return K.push(y),this.db.all(A,K).map((V)=>this.mapRow(V))}searchByFile(u,y=10,B){let $=!!B,A=`SELECT o.*
|
|
223
223
|
FROM observations o
|
|
224
224
|
JOIN observations_fts fts ON o._rowid = fts.rowid
|
|
225
|
-
${
|
|
225
|
+
${$?"JOIN sessions s ON o.session_id = s.id":""}
|
|
226
226
|
WHERE observations_fts MATCH ?
|
|
227
227
|
AND o.superseded_by IS NULL AND o.deleted_at IS NULL
|
|
228
|
-
${
|
|
228
|
+
${$?"AND s.project_path = ?":""}
|
|
229
229
|
ORDER BY rank
|
|
230
|
-
LIMIT ?`,
|
|
230
|
+
LIMIT ?`,J=[`files_read:"${u.replace(/"/g,'""')}" OR files_modified:"${u.replace(/"/g,'""')}"`];if($&&B)J.push(B);return J.push(y),this.db.all(A,J).map((K)=>this.mapRow(K))}setEmbedding(u,y){this.db.run("UPDATE observations SET embedding = ? WHERE id = ?",[JSON.stringify(y),u])}getWithEmbeddings(u,y){return this.db.all(`SELECT o.id, o.embedding, o.title
|
|
231
231
|
FROM observations o
|
|
232
232
|
JOIN sessions s ON o.session_id = s.id
|
|
233
233
|
WHERE s.project_path = ? AND o.embedding IS NOT NULL AND o.superseded_by IS NULL AND o.deleted_at IS NULL
|
|
234
234
|
ORDER BY o.created_at DESC
|
|
235
|
-
LIMIT ?`,[
|
|
235
|
+
LIMIT ?`,[u,y]).map((B)=>{try{return{id:B.id,embedding:JSON.parse(B.embedding),title:B.title}}catch{return null}}).filter((B)=>B!==null)}findSimilar(u,y,B,$){let A=this.db.all(`SELECT id, embedding FROM observations
|
|
236
236
|
WHERE embedding IS NOT NULL AND type = ? AND superseded_by IS NULL AND deleted_at IS NULL
|
|
237
237
|
ORDER BY created_at DESC
|
|
238
|
-
LIMIT 200`,[
|
|
238
|
+
LIMIT 200`,[y]),J=[];for(let K of A)try{let V=JSON.parse(K.embedding);if(!Array.isArray(V)||V.length!==u.length)continue;let R=yy(u,V);if(R>=B)J.push({id:K.id,similarity:R})}catch{}return J.sort((K,V)=>V.similarity-K.similarity).slice(0,$)}insertVecEmbedding(u,y){let B=new Float32Array(y);this.db.run("BEGIN");try{this.db.run("DELETE FROM observation_embeddings WHERE observation_id = ?",[u]),this.db.run("INSERT INTO observation_embeddings (observation_id, embedding) VALUES (?, ?)",[u,B]),this.db.run("COMMIT")}catch($){throw this.db.run("ROLLBACK"),$}}migrateExistingEmbeddings(u){let y=this.db.all("SELECT id, embedding FROM observations WHERE embedding IS NOT NULL"),B=0,$=0;for(let A of y)try{let J=JSON.parse(A.embedding);if(!Array.isArray(J)||J.length!==u){$++;continue}this.insertVecEmbedding(A.id,J),B++}catch{$++}return{migrated:B,skipped:$}}getVecEmbeddingMatches(u,y){try{let B=new Float32Array(u);return this.db.all(`SELECT observation_id, distance
|
|
239
239
|
FROM observation_embeddings
|
|
240
|
-
WHERE embedding MATCH ? AND k = ?`,[
|
|
240
|
+
WHERE embedding MATCH ? AND k = ?`,[B,y]).map(($)=>({observationId:$.observation_id,distance:$.distance}))}catch{return[]}}searchVecSubset(u,y,B){if(y.length===0)return[];try{let $=new Float32Array(u),A=Math.max(B*5,y.length),J=this.db.all(`SELECT observation_id, distance
|
|
241
241
|
FROM observation_embeddings
|
|
242
|
-
WHERE embedding MATCH ? AND k = ?`,[
|
|
242
|
+
WHERE embedding MATCH ? AND k = ?`,[$,A]),K=new Set(y);return J.filter((V)=>K.has(V.observation_id)).slice(0,B).map((V)=>({observationId:V.observation_id,distance:V.distance}))}catch{return[]}}update(u,y){let B=this.getById(u);if(!B)return null;if(Object.keys(y).length===0)return B;let $=this.create({sessionId:B.sessionId,scope:B.scope??"project",type:y.type??B.type,title:y.title??B.title,subtitle:y.subtitle??B.subtitle,facts:y.facts??B.facts,narrative:y.narrative??B.narrative,concepts:y.concepts??B.concepts,filesRead:y.filesRead??B.filesRead,filesModified:y.filesModified??B.filesModified,rawToolOutput:B.rawToolOutput,toolName:"mem-revise",tokenCount:B.tokenCount,discoveryTokens:B.discoveryTokens,importance:y.importance??B.importance});return this.db.run("UPDATE observations SET revision_of = ? WHERE id = ?",[u,$.id]),this.supersede(u,$.id),this.getById($.id)}supersede(u,y){let B=new Date().toISOString();this.db.run("UPDATE observations SET superseded_by = ?, superseded_at = ? WHERE id = ?",[y,B,u])}delete(u){if(this.db.all("SELECT id FROM observations WHERE id = ?",[u]).length===0)return!1;let B=new Date().toISOString();return this.db.run("UPDATE observations SET deleted_at = ? WHERE id = ?",[B,u]),this.deleteEmbeddingsForObservations([u]),!0}getLineage(u){let y=this.getByIdIncludingArchived(u);if(!y)return[];let B=new Set([y.id]),$=[y];while($[0].revisionOf){let A=this.getByIdIncludingArchived($[0].revisionOf);if(!A||B.has(A.id))break;$.unshift(A),B.add(A.id)}while($[$.length-1].supersededBy){let A=$[$.length-1].supersededBy;if(!A)break;let J=this.getByIdIncludingArchived(A);if(!J||B.has(J.id))break;$.push(J),B.add(J.id)}return $}deleteOlderThan(u){return this.db.all(`DELETE FROM observations
|
|
243
243
|
WHERE (created_at < datetime('now', '-' || ? || ' days') OR deleted_at IS NOT NULL)
|
|
244
244
|
AND session_id NOT IN (SELECT id FROM sessions WHERE status != 'completed')
|
|
245
|
-
RETURNING id`,[
|
|
245
|
+
RETURNING id`,[u]).length}deleteEmbeddingsForObservations(u){if(u.length===0)return;let y=u.map(()=>"?").join(",");try{this.db.run(`DELETE FROM observation_embeddings WHERE observation_id IN (${y})`,u)}catch{}this.db.run(`UPDATE observations SET embedding = NULL WHERE id IN (${y})`,u)}mapRow(u){return{id:u.id,sessionId:u.session_id,scope:u.scope??"project",type:u.type,title:u.title,subtitle:u.subtitle,facts:JSON.parse(u.facts),narrative:u.narrative,concepts:JSON.parse(u.concepts),filesRead:JSON.parse(u.files_read),filesModified:JSON.parse(u.files_modified),rawToolOutput:u.raw_tool_output,toolName:u.tool_name,createdAt:u.created_at,tokenCount:u.token_count,discoveryTokens:u.discovery_tokens??0,importance:u.importance??3,revisionOf:u.revision_of??null,deletedAt:u.deleted_at??null,supersededBy:u.superseded_by??null,supersededAt:u.superseded_at??null}}}import{randomUUID as Z0}from"crypto";class Nu{db;constructor(u){this.db=u}create(u){let y=Z0(),B=new Date().toISOString();return this.db.run(`INSERT INTO pending_messages
|
|
246
246
|
(id, session_id, tool_name, tool_output, call_id, created_at)
|
|
247
|
-
VALUES (?, ?, ?, ?, ?, ?)`,[
|
|
247
|
+
VALUES (?, ?, ?, ?, ?, ?)`,[y,u.sessionId,u.toolName,u.toolOutput,u.callId,B]),{...u,id:y,createdAt:B,status:"pending",retryCount:0,error:null}}getPending(u=10){return this.db.all("SELECT * FROM pending_messages WHERE status = 'pending' ORDER BY created_at ASC LIMIT ?",[u]).map((y)=>this.mapRow(y))}getByStatus(u){return this.db.all("SELECT * FROM pending_messages WHERE status = ? ORDER BY created_at ASC",[u]).map((y)=>this.mapRow(y))}markProcessing(u){this.db.run("UPDATE pending_messages SET status = 'processing' WHERE id = ?",[u])}markCompleted(u){this.db.run("UPDATE pending_messages SET status = 'completed' WHERE id = ?",[u])}markFailed(u,y){this.db.run("UPDATE pending_messages SET status = 'failed', error = ?, retry_count = retry_count + 1 WHERE id = ?",[y,u])}resetStale(u=5){return this.db.all(`UPDATE pending_messages SET status = 'pending'
|
|
248
248
|
WHERE status = 'processing'
|
|
249
249
|
AND created_at < datetime('now', ? || ' minutes')
|
|
250
|
-
RETURNING id`,[`-${
|
|
250
|
+
RETURNING id`,[`-${u}`]).length}deleteCompletedOlderThan(u){return this.db.all(`DELETE FROM pending_messages
|
|
251
251
|
WHERE status = 'completed'
|
|
252
252
|
AND created_at < datetime('now', '-' || ? || ' days')
|
|
253
|
-
RETURNING id`,[
|
|
253
|
+
RETURNING id`,[u]).length}mapRow(u){return{id:u.id,sessionId:u.session_id,toolName:u.tool_name,toolOutput:u.tool_output,callId:u.call_id,createdAt:u.created_at,status:u.status,retryCount:u.retry_count,error:u.error??null}}}var S0=[{version:1,name:"create-schema",up:`
|
|
254
254
|
-- Sessions table
|
|
255
255
|
CREATE TABLE IF NOT EXISTS sessions (
|
|
256
256
|
_rowid INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
@@ -544,22 +544,22 @@ Respond with EXACTLY this XML format:
|
|
|
544
544
|
INSERT INTO entities_fts(rowid, name, entity_type)
|
|
545
545
|
VALUES (new._rowid, new.name, new.entity_type);
|
|
546
546
|
END;
|
|
547
|
-
`}];function
|
|
547
|
+
`}];function By(u,y){if(u.migrate(S0),y?.hasVectorExtension&&y?.embeddingDimension&&y.embeddingDimension>0)U0(u,y.embeddingDimension)}function U0(u,y){if(u.get("SELECT name FROM sqlite_master WHERE type='table' AND name='observation_embeddings'")){let $=u.get("SELECT value FROM _embedding_meta WHERE key = 'dimension'");if($&&Number($.value)!==y){console.warn(`[open-mem] vec0 table exists with dimension ${$.value}, but config specifies ${y}. Drop observation_embeddings to re-create with new dimension.`);return}}else u.exec(`CREATE VIRTUAL TABLE observation_embeddings USING vec0(
|
|
548
548
|
observation_id TEXT PRIMARY KEY,
|
|
549
|
-
embedding float[${
|
|
550
|
-
)`);
|
|
551
|
-
VALUES (?, ?, ?, 'active')`,[
|
|
549
|
+
embedding float[${y}] distance_metric=cosine
|
|
550
|
+
)`);u.run("INSERT OR REPLACE INTO _embedding_meta (key, value) VALUES (?, ?)",["dimension",String(y)])}class Eu{db;constructor(u){this.db=u}create(u,y){let B=new Date().toISOString();return this.db.run(`INSERT INTO sessions (id, project_path, started_at, status)
|
|
551
|
+
VALUES (?, ?, ?, 'active')`,[u,y,B]),this.getById(u)}getOrCreate(u,y){let B=this.getById(u);if(B)return B;return this.create(u,y)}getById(u){let y=this.db.get("SELECT * FROM sessions WHERE id = ?",[u]);return y?this.mapRow(y):null}getRecent(u,y=10){return this.db.all("SELECT * FROM sessions WHERE project_path = ? ORDER BY started_at DESC LIMIT ?",[u,y]).map((B)=>this.mapRow(B))}getAll(u){return this.db.all("SELECT * FROM sessions WHERE project_path = ? ORDER BY started_at DESC",[u]).map((y)=>this.mapRow(y))}getActive(){return this.db.all("SELECT * FROM sessions WHERE status = 'active' ORDER BY started_at DESC").map((u)=>this.mapRow(u))}updateStatus(u,y){this.db.run("UPDATE sessions SET status = ? WHERE id = ?",[y,u])}markCompleted(u){this.db.run("UPDATE sessions SET status = 'completed', ended_at = datetime('now') WHERE id = ?",[u])}incrementObservationCount(u){this.db.run("UPDATE sessions SET observation_count = observation_count + 1 WHERE id = ?",[u])}setSummary(u,y){this.db.run("UPDATE sessions SET summary_id = ? WHERE id = ?",[y,u])}mapRow(u){return{id:u.id,projectPath:u.project_path,startedAt:u.started_at,endedAt:u.ended_at??null,status:u.status,observationCount:u.observation_count,summaryId:u.summary_id??null}}}import{randomUUID as k0}from"crypto";class Wu{db;constructor(u){this.db=u}create(u){let y=k0(),B=new Date().toISOString();return this.db.run(`INSERT INTO session_summaries
|
|
552
552
|
(id, session_id, summary, key_decisions, files_modified,
|
|
553
553
|
concepts, created_at, token_count,
|
|
554
554
|
request, investigated, learned, completed, next_steps)
|
|
555
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,[
|
|
555
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,[y,u.sessionId,u.summary,JSON.stringify(u.keyDecisions),JSON.stringify(u.filesModified),JSON.stringify(u.concepts),B,u.tokenCount,u.request??"",u.investigated??"",u.learned??"",u.completed??"",u.nextSteps??""]),{...u,id:y,createdAt:B}}importSummary(u){this.db.run(`INSERT INTO session_summaries
|
|
556
556
|
(id, session_id, summary, key_decisions, files_modified,
|
|
557
557
|
concepts, created_at, token_count,
|
|
558
558
|
request, investigated, learned, completed, next_steps)
|
|
559
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,[
|
|
559
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,[u.id,u.sessionId,u.summary,JSON.stringify(u.keyDecisions),JSON.stringify(u.filesModified),JSON.stringify(u.concepts),u.createdAt,u.tokenCount,u.request??"",u.investigated??"",u.learned??"",u.completed??"",u.nextSteps??""])}getBySessionId(u){let y=this.db.get("SELECT * FROM session_summaries WHERE session_id = ?",[u]);return y?this.mapRow(y):null}getRecent(u=10){return this.db.all("SELECT * FROM session_summaries ORDER BY created_at DESC LIMIT ?",[u]).map((y)=>this.mapRow(y))}search(u,y=10){return this.db.all(`SELECT ss.*
|
|
560
560
|
FROM session_summaries ss
|
|
561
561
|
JOIN summaries_fts fts ON ss._rowid = fts.rowid
|
|
562
562
|
WHERE summaries_fts MATCH ?
|
|
563
563
|
ORDER BY rank
|
|
564
|
-
LIMIT ?`,[
|
|
565
|
-
`)}function
|
|
564
|
+
LIMIT ?`,[u,y]).map((B)=>this.mapRow(B))}mapRow(u){return{id:u.id,sessionId:u.session_id,summary:u.summary,keyDecisions:JSON.parse(u.key_decisions),filesModified:JSON.parse(u.files_modified),concepts:JSON.parse(u.concepts),createdAt:u.created_at,tokenCount:u.token_count,request:u.request||void 0,investigated:u.investigated||void 0,learned:u.learned||void 0,completed:u.completed||void 0,nextSteps:u.next_steps||void 0}}}class Hu{config;compressor;summarizer;pendingRepo;observationRepo;sessionRepo;summaryRepo;embeddingModel;conflictEvaluator;entityExtractor;entityRepo;observer;processing=!1;timer=null;mode="in-process";onEnqueue=null;constructor(u,y,B,$,A,J,K,V=null,R=null,z=null,N=null,E=null){this.config=u;this.compressor=y;this.summarizer=B;this.pendingRepo=$;this.observationRepo=A;this.sessionRepo=J;this.summaryRepo=K;this.embeddingModel=V;this.conflictEvaluator=R;this.entityExtractor=z;this.entityRepo=N;this.observer=E}setMode(u){if(this.mode=u,u==="enqueue-only")this.stop()}getMode(){return this.mode}setOnEnqueue(u){this.onEnqueue=u}enqueue(u,y,B,$){if(this.pendingRepo.create({sessionId:u,toolName:y,toolOutput:B,callId:$}),this.observer?.onEnqueue?.({sessionId:u,toolName:y,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 u=0,y=0,B=Date.now();try{this.pendingRepo.resetStale(5);let $=this.pendingRepo.getPending(this.config.batchSize);if(this.observer?.onBatchStart?.({pending:$.length,mode:this.mode,startedAt:new Date(B).toISOString()}),$.length===0)return 0;for(let A of $)try{this.pendingRepo.markProcessing(A.id);let K=await this.compressor.compress(A.toolName,A.toolOutput)??this.compressor.createFallbackObservation(A.toolName,A.toolOutput),V=!1,R=null;if(this.embeddingModel)try{let N=Ru({title:K.title,narrative:K.narrative,concepts:K.concepts}),E=await zu(this.embeddingModel,N);if(E){let H=this.config.conflictResolutionEnabled&&this.conflictEvaluator,Q=this.config.conflictSimilarityBandLow??0.7,U=this.config.conflictSimilarityBandHigh??0.92;if(H){let k=this.observationRepo.findSimilar(E,K.type,Q,5),M=k.find((f)=>f.similarity>U);if(M)console.log(`[open-mem] Dedup: skipping duplicate of ${M.id} (similarity: ${M.similarity.toFixed(3)})`),V=!0;else{let f=k.filter((Z)=>Z.similarity>=Q&&Z.similarity<=U);if(f.length>0)try{let Z=f.map((S)=>{let Y=this.observationRepo.getById(S.id);return Y?{id:Y.id,title:Y.title,narrative:Y.narrative,concepts:Y.concepts,type:Y.type}:null}).filter((S)=>S!==null);if(Z.length>0&&this.conflictEvaluator){let S=await this.conflictEvaluator.evaluate({title:K.title,narrative:K.narrative,concepts:K.concepts,type:K.type},Z);if(S&&S.outcome==="duplicate")console.log(`[open-mem] Conflict eval: duplicate (${S.reason})`),V=!0;else if(S&&S.outcome==="update"&&S.supersedesId)console.log(`[open-mem] Conflict eval: update supersedes ${S.supersedesId} (${S.reason})`),R=S.supersedesId}}catch{}}}else{let k=this.observationRepo.findSimilar(E,K.type,0.92,1);if(k.length>0)console.log(`[open-mem] Dedup: skipping duplicate of ${k[0].id} (similarity: ${k[0].similarity.toFixed(3)})`),V=!0}}}catch{}if(V){this.pendingRepo.markCompleted(A.id);continue}let z=this.observationRepo.create({sessionId:A.sessionId,type:K.type,title:K.title,subtitle:K.subtitle,facts:K.facts,narrative:K.narrative,concepts:K.concepts,filesRead:K.filesRead,filesModified:K.filesModified,rawToolOutput:A.toolOutput,toolName:A.toolName,tokenCount:P(`${K.title} ${K.narrative} ${K.facts.join(" ")}`),discoveryTokens:K.discoveryTokens??P(A.toolOutput),importance:K.importance??3});if(this.embeddingModel)try{let N=Ru({title:z.title,narrative:z.narrative,concepts:z.concepts}),E=await zu(this.embeddingModel,N);if(E)this.observationRepo.setEmbedding(z.id,E)}catch{}if(R)try{this.observationRepo.supersede(R,z.id),console.log(`[open-mem] Superseded observation ${R} with ${z.id}`)}catch(N){console.error(`[open-mem] Failed to supersede ${R}:`,N)}if(this.config.entityExtractionEnabled&&this.entityExtractor&&this.entityRepo)try{let N=await this.entityExtractor.extract({title:z.title,narrative:z.narrative,concepts:z.concepts,facts:z.facts,filesRead:z.filesRead,filesModified:z.filesModified,type:z.type});if(N){let E=new Map;for(let H of N.entities){let Q=this.entityRepo.upsertEntity(H.name,H.entityType);E.set(H.name,Q.id),this.entityRepo.linkObservation(Q.id,z.id)}for(let H of N.relations){let Q=E.get(H.sourceName),U=E.get(H.targetName);if(Q&&U)this.entityRepo.createRelation(Q,U,H.relationship,z.id)}}}catch{}this.sessionRepo.incrementObservationCount(A.sessionId),this.pendingRepo.markCompleted(A.id),u++}catch(J){this.pendingRepo.markFailed(A.id,String(J)),y++,this.observer?.onItemFailed?.({pendingId:A.id,error:String(J),failedAt:new Date().toISOString()})}return u}finally{this.observer?.onBatchEnd?.({processed:u,failed:y,durationMs:Date.now()-B,finishedAt:new Date().toISOString()}),this.processing=!1}}async summarizeSession(u){let y=this.observationRepo.getBySession(u);if(!this.summarizer.shouldSummarize(y.length))return;if(this.summaryRepo.getBySessionId(u))return;let $=await this.summarizer.summarize(u,y);if(!$)return;let A=this.summaryRepo.create({sessionId:u,summary:$.summary,keyDecisions:$.keyDecisions,filesModified:$.filesModified,concepts:$.concepts,tokenCount:P($.summary)});this.sessionRepo.setSummary(u,A.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 $y}from"child_process";import{dirname as M0,resolve as Ay}from"path";function f0(u){try{let y=$y("git",["rev-parse","--git-common-dir"],{cwd:u,encoding:"utf-8",timeout:5000});if(y.status!==0||!y.stdout)return null;let B=y.stdout.trim();if(B===".git")return null;let $=$y("git",["rev-parse","--git-dir"],{cwd:u,encoding:"utf-8",timeout:5000});if($.status!==0||!$.stdout)return null;let A=$.stdout.trim(),J=Ay(u,B),K=Ay(u,A);if(J===K)return null;let V=M0(J);if(V===J||V==="/")return null;return V}catch{return null}}function Jy(u){return f0(u)??u}function Qu(u){process.stdout.write(`${JSON.stringify(u)}
|
|
565
|
+
`)}function Y0(){let{values:u}=X0({options:{project:{type:"string",short:"p"},"http-port":{type:"string"}},strict:!1}),y=typeof u.project==="string"?u.project:process.cwd(),B=u["http-port"],$=typeof B==="string"&&Number.parseInt(B,10)>0?Number.parseInt(B,10):void 0;return{projectDir:y,httpPort:$}}function D0(u,y){if(u==="claude-code"&&!y.platformClaudeCodeEnabled)throw Error("Claude Code adapter is disabled. Set OPEN_MEM_PLATFORM_CLAUDE_CODE=true.");if(u==="cursor"&&!y.platformCursorEnabled)throw Error("Cursor adapter is disabled. Set OPEN_MEM_PLATFORM_CURSOR=true.")}function m0(u,y){let B=Jy(y),$=su(B);D0(u,$),r.enableExtensionSupport();let A=au($.dbPath);By(A,{hasVectorExtension:A.hasVectorExtension,embeddingDimension:$.embeddingDimension});let J=new Eu(A),K=new Vu(A),V=new Wu(A),R=new Nu(A),z=new w($),N=new $u($),E=$.provider!=="bedrock",H=$.compressionEnabled&&(!E||$.apiKey)?bu({provider:$.provider,model:$.model,apiKey:$.apiKey}):null,Q=$.conflictResolutionEnabled&&(!E||$.apiKey)?new yu({provider:$.provider,apiKey:$.apiKey,model:$.model,rateLimitingEnabled:$.rateLimitingEnabled}):null,U=$.entityExtractionEnabled&&(!E||$.apiKey)?new Bu({provider:$.provider,apiKey:$.apiKey,model:$.model,rateLimitingEnabled:$.rateLimitingEnabled}):null,k=new Ku(A),M=new Hu($,z,N,R,K,J,V,H,Q,U,k),f=u==="claude-code"?Mu():Lu(),Z=new e({adapter:f,queue:M,sessions:J,observations:K,pendingMessages:R,projectPath:B,config:$});return{db:A,queue:M,runtime:Z,platform:u,projectPath:B}}function Ky(u,y){let B=u.queue.getStats();return{id:y,ok:!0,code:"OK",status:{platform:u.platform,projectPath:u.projectPath,queue:{mode:u.queue.getMode(),running:u.queue.isRunning,processing:B.processing,pending:B.pending}}}}function zy(u){if(!u||typeof u!=="object"||Array.isArray(u))return{command:"event",payload:u};let y=u,B=typeof y.command==="string"&&(y.command==="event"||y.command==="flush"||y.command==="health"||y.command==="shutdown")?y.command:void 0,$=typeof y.id==="string"||typeof y.id==="number"?y.id:void 0;if(!B)return{command:"event",payload:u,id:$};return{id:$,command:B,payload:"payload"in y?y.payload:void 0}}async function Ry(u){let y=Y0(),B=m0(u,y.projectDir);B.queue.start();let $=!1,A=async()=>{if($)return;$=!0;try{await B.queue.processBatch()}catch{}B.queue.stop(),B.db.close(),process.exit(0)},J=async(R)=>{let z=R.command??"event";if(z==="health")return Ky(B,R.id);if(z==="flush"){let E=await B.queue.processBatch();return{id:R.id,ok:!0,code:"OK",processed:E}}if(z==="shutdown")return{id:R.id,ok:!0,code:"OK",message:"shutting down"};if(!await B.runtime.ingestRaw(R.payload))return{id:R.id,ok:!1,code:"UNSUPPORTED_EVENT",message:"Payload did not match adapter event schema"};return{id:R.id,ok:!0,code:"OK",ingested:!0}};if(y.httpPort)Zu("127.0.0.1","Platform worker HTTP server"),Bun.serve({port:y.httpPort,hostname:"127.0.0.1",idleTimeout:0,fetch:async(z)=>{if(z.method==="GET"&&new URL(z.url).pathname==="/v1/health")return Response.json(Ky(B));if(z.method==="POST"&&new URL(z.url).pathname==="/v1/events"){let N;try{N=await z.json()}catch{return Response.json({ok:!1,code:"INVALID_JSON",message:"Invalid JSON payload"},{status:400})}let E=zy(N);try{let H=await J(E);if((E.command??"event")==="shutdown")setTimeout(()=>{A()},0);return Response.json(H,{status:H.ok?200:422})}catch(H){return Response.json({ok:!1,code:"INGESTION_FAILED",message:String(H)},{status:500})}}return Response.json({ok:!1,code:"NOT_FOUND"},{status:404})}});process.on("SIGINT",()=>{A()}),process.on("SIGTERM",()=>{A()});let K=Promise.resolve(),V=L0({input:process.stdin,terminal:!1});V.on("line",(R)=>{let z=R.trim();if(!z)return;K=K.then(async()=>{let N;try{N=JSON.parse(z)}catch{Qu({ok:!1,code:"INVALID_JSON",message:"Invalid JSON payload"});return}try{let E=zy(N),H=await J(E);if(Qu(H),(E.command??"event")==="shutdown")await A()}catch(E){Qu({ok:!1,code:"INGESTION_FAILED",message:String(E)})}})}),V.on("close",()=>{K.finally(()=>A())})}Ry("claude-code");
|