From af011f2ddbbf0f5e415f545e7ff452bead58ac8d Mon Sep 17 00:00:00 2001 From: Alex Newman Date: Sat, 25 Apr 2026 17:11:20 -0700 Subject: [PATCH] chore: bump version to 12.4.4 (#2137) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PATCH release for the /clear queue-drain fix (PR #2136): removes the SessionEnd → session-complete shim across all five integration surfaces so pending observations are no longer abandoned when users type /clear, logout, or exit. Co-authored-by: Claude Opus 4.7 (1M context) --- .claude-plugin/marketplace.json | 2 +- .claude-plugin/plugin.json | 2 +- .codex-plugin/plugin.json | 2 +- package.json | 2 +- plugin/.claude-plugin/plugin.json | 2 +- plugin/package.json | 2 +- plugin/scripts/mcp-server.cjs | 2 +- plugin/scripts/worker-service.cjs | 4 ++-- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 05424ffa..2c1da7c8 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -10,7 +10,7 @@ "plugins": [ { "name": "claude-mem", - "version": "12.4.3", + "version": "12.4.4", "source": "./plugin", "description": "Persistent memory system for Claude Code - context compression across sessions" } diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index e8481cd7..7c9ad61a 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "claude-mem", - "version": "12.4.3", + "version": "12.4.4", "description": "Memory compression system for Claude Code - persist context across sessions", "author": { "name": "Alex Newman" diff --git a/.codex-plugin/plugin.json b/.codex-plugin/plugin.json index 65f379fe..8fea1900 100644 --- a/.codex-plugin/plugin.json +++ b/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "claude-mem", - "version": "12.4.3", + "version": "12.4.4", "description": "Memory compression system for Claude Code - persist context across sessions", "author": { "name": "Alex Newman", diff --git a/package.json b/package.json index b154eb09..0ed7229b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "claude-mem", - "version": "12.4.3", + "version": "12.4.4", "description": "Memory compression system for Claude Code - persist context across sessions", "keywords": [ "claude", diff --git a/plugin/.claude-plugin/plugin.json b/plugin/.claude-plugin/plugin.json index 4a04041a..0b595e31 100644 --- a/plugin/.claude-plugin/plugin.json +++ b/plugin/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "claude-mem", - "version": "12.4.3", + "version": "12.4.4", "description": "Persistent memory system for Claude Code - seamlessly preserve context across sessions", "author": { "name": "Alex Newman" diff --git a/plugin/package.json b/plugin/package.json index 42fd3d27..c05f5bab 100644 --- a/plugin/package.json +++ b/plugin/package.json @@ -1,6 +1,6 @@ { "name": "claude-mem-plugin", - "version": "12.4.3", + "version": "12.4.4", "private": true, "description": "Runtime dependencies for claude-mem bundled hooks", "type": "module", diff --git a/plugin/scripts/mcp-server.cjs b/plugin/scripts/mcp-server.cjs index 239f92c3..96842c73 100755 --- a/plugin/scripts/mcp-server.cjs +++ b/plugin/scripts/mcp-server.cjs @@ -187,7 +187,7 @@ ${f}`}let s=i.lineStart;for(let u=i.lineStart-1;u>=0;u--){let l=a[u].trim();if(l ${c}`}var $b=new Set([".js",".jsx",".ts",".tsx",".mjs",".cjs",".py",".pyw",".go",".rs",".rb",".java",".cs",".cpp",".cc",".cxx",".c",".h",".hpp",".hh",".swift",".kt",".kts",".php",".vue",".svelte",".ex",".exs",".lua",".scala",".sc",".sh",".bash",".zsh",".hs",".zig",".css",".scss",".toml",".yml",".yaml",".sql",".md",".mdx"]),uD=new Set(["node_modules",".git","dist","build",".next","__pycache__",".venv","venv","env",".env","target","vendor",".cache",".turbo","coverage",".nyc_output",".claude",".smart-file-read"]),lD=512*1024;async function*bb(t,e,r=20,n){if(r<=0)return;let o;try{o=await(0,Zn.readdir)(t,{withFileTypes:!0})}catch(i){_.debug("WORKER",`walkDir: failed to read directory ${t}`,void 0,i instanceof Error?i:void 0);return}for(let i of o){if(i.name.startsWith(".")&&i.name!=="."||uD.has(i.name))continue;let a=(0,Ai.join)(t,i.name);if(i.isDirectory())yield*bb(a,e,r-1,n);else if(i.isFile()){let s=i.name.slice(i.name.lastIndexOf("."));($b.has(s)||n&&n.has(s))&&(yield a)}}}async function dD(t){try{let e=await(0,Zn.stat)(t);if(e.size>lD||e.size===0)return null;let r=await(0,Zn.readFile)(t,"utf-8");return r.slice(0,1e3).includes("\0")?null:r}catch(e){return _.debug("WORKER",`safeReadFile: failed to read ${t}`,void 0,e instanceof Error?e:void 0),null}}async function Sb(t,e,r={}){let n=r.maxResults||20,o=e.toLowerCase(),i=o.split(/[\s_\-./]+/).filter(x=>x.length>0),a=r.projectRoot||t,s=Ni(a),c=new Set;for(let x of Object.values(s.grammars))for(let S of x.extensions)$b.has(S)||c.add(S);let u=[];for await(let x of bb(t,t,20,c.size>0?c:void 0)){if(r.filePattern&&!(0,Ai.relative)(t,x).toLowerCase().includes(r.filePattern.toLowerCase()))continue;let S=await dD(x);S&&u.push({absolutePath:x,relativePath:(0,Ai.relative)(t,x),content:S})}let l=vb(u,a),d=[],p=[],f=0;for(let[x,S]of l){f+=pD(S);let z=nc(x.toLowerCase(),i)>0,Ve=[],We=(qn,qr)=>{for(let ye of qn){let rr=0,mt="",Vn=nc(ye.name.toLowerCase(),i);Vn>0&&(rr+=Vn*3,mt="name match"),ye.signature.toLowerCase().includes(o)&&(rr+=2,mt=mt?`${mt} + signature`:"signature match"),ye.jsdoc&&ye.jsdoc.toLowerCase().includes(o)&&(rr+=1,mt=mt?`${mt} + jsdoc`:"jsdoc match"),rr>0&&(z=!0,Ve.push({filePath:x,symbolName:qr?`${qr}.${ye.name}`:ye.name,kind:ye.kind,signature:ye.signature,jsdoc:ye.jsdoc,lineStart:ye.lineStart,lineEnd:ye.lineEnd,matchReason:mt})),ye.children&&We(ye.children,ye.name)}};We(S.symbols),z&&(d.push(S),p.push(...Ve))}p.sort((x,S)=>{let j=nc(x.symbolName.toLowerCase(),i);return nc(S.symbolName.toLowerCase(),i)-j});let h=p.slice(0,n),g=new Set(h.map(x=>x.filePath)),$=d.filter(x=>g.has(x.filePath)).slice(0,n),k=$.reduce((x,S)=>x+S.foldedTokenEstimate,0);return{foldedFiles:$,matchingSymbols:h,totalFilesScanned:u.length,totalSymbolsFound:f,tokenEstimate:k}}function nc(t,e){let r=0;for(let n of e)if(t===n)r+=10;else if(t.includes(n))r+=5;else{let o=0,i=0;for(let a of n){let s=t.indexOf(a,o);s!==-1&&(i++,o=s+1)}i===n.length&&(r+=1)}return r}function pD(t){let e=t.symbols.length;for(let r of t.symbols)r.children&&(e+=r.children.length);return e}function xb(t,e){let r=[];if(r.push(`\u{1F50D} Smart Search: "${e}"`),r.push(` Scanned ${t.totalFilesScanned} files, found ${t.totalSymbolsFound} symbols`),r.push(` ${t.matchingSymbols.length} matches across ${t.foldedFiles.length} files (~${t.tokenEstimate} tokens for folded view)`),r.push(""),t.matchingSymbols.length===0)return r.push(" No matching symbols found."),r.join(` `);r.push("\u2500\u2500 Matching Symbols \u2500\u2500"),r.push("");for(let n of t.matchingSymbols){if(r.push(` ${n.kind} ${n.symbolName} (${n.filePath}:${n.lineStart+1})`),r.push(` ${n.signature}`),n.jsdoc){let o=n.jsdoc.split(` `).find(i=>i.replace(/^[\s*/]+/,"").trim().length>0);o&&r.push(` \u{1F4AC} ${o.replace(/^[\s*/]+/,"").trim()}`)}r.push("")}r.push("\u2500\u2500 Folded File Views \u2500\u2500"),r.push("");for(let n of t.foldedFiles)r.push(Ln(n)),r.push("");return r.push("\u2500\u2500 Actions \u2500\u2500"),r.push(" To see full implementation: use smart_unfold with file path and symbol name"),r.join(` -`)}var ym=require("node:fs/promises"),Eb=require("node:fs"),Fr=require("node:path"),Ib=require("node:url"),xD={},fD="12.4.3";console.log=(...t)=>{_.error("CONSOLE","Intercepted console output (MCP protocol protection)",void 0,{args:t})};var Pb=!1,Tb=(()=>{if(typeof __dirname<"u")return __dirname;try{return(0,Fr.dirname)((0,Ib.fileURLToPath)(xD.url))}catch{return Pb=!0,process.cwd()}})(),$m=(0,Fr.resolve)(Tb,"worker-service.cjs");function mD(){Pb&&((0,Eb.existsSync)($m)||_.error("SYSTEM","mcp-server: dirname resolution failed (both __dirname and import.meta.url are unavailable). Fell back to process.cwd() and the resolved WORKER_SCRIPT_PATH does not exist. This is the actual problem \u2014 the worker bundle is fine, but mcp-server cannot locate it. Worker auto-start will fail until the dirname-resolution path is fixed.",{workerScriptPath:$m,mcpServerDir:Tb}))}var kb={search:"/api/search",timeline:"/api/timeline"};async function _m(t,e){_.debug("SYSTEM","\u2192 Worker API",void 0,{endpoint:t,params:e});let r=new URLSearchParams;for(let[o,i]of Object.entries(e))i!=null&&r.append(o,String(i));let n=`${t}?${r}`;try{let o=await ec(n);if(!o.ok){let a=await o.text();throw new Error(`Worker API error (${o.status}): ${a}`)}let i=await o.json();return _.debug("SYSTEM","\u2190 Worker API success",void 0,{endpoint:t}),i}catch(o){return _.error("SYSTEM","\u2190 Worker API error",{endpoint:t},o instanceof Error?o:new Error(String(o))),{content:[{type:"text",text:`Error calling Worker API: ${o instanceof Error?o.message:String(o)}`}],isError:!0}}}async function hD(t,e){let r=await ec(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!r.ok){let o=await r.text();throw new Error(`Worker API error (${r.status}): ${o}`)}let n=await r.json();return _.debug("HTTP","Worker API success (POST)",void 0,{endpoint:t}),{content:[{type:"text",text:JSON.stringify(n,null,2)}]}}async function Fn(t,e){_.debug("HTTP","Worker API request (POST)",void 0,{endpoint:t});try{return await hD(t,e)}catch(r){return _.error("HTTP","Worker API error (POST)",{endpoint:t},r instanceof Error?r:new Error(String(r))),{content:[{type:"text",text:`Error calling Worker API: ${r instanceof Error?r.message:String(r)}`}],isError:!0}}}async function gD(){try{return(await ec("/api/health")).ok}catch(t){return _.debug("SYSTEM","Worker health check failed",{},t instanceof Error?t:new Error(String(t))),!1}}async function vD(){if(await gD())return!0;_.warn("SYSTEM","Worker not available, attempting auto-start for MCP client"),mD();try{let t=am(),e=await ib(t,$m);return e||_.error("SYSTEM","Worker auto-start returned false \u2014 MCP tools that require the worker (search, timeline, get_observations) will fail until the worker is running. Check earlier log lines for the specific failure reason (Bun not found, missing worker bundle, port conflict, etc.)."),e}catch(t){return _.error("SYSTEM","Worker auto-start threw \u2014 MCP tools that require the worker (search, timeline, get_observations) will fail until the worker is running.",void 0,t instanceof Error?t:new Error(String(t))),!1}}var zb=[{name:"__IMPORTANT",description:`3-LAYER WORKFLOW (ALWAYS FOLLOW): +`)}var ym=require("node:fs/promises"),Eb=require("node:fs"),Fr=require("node:path"),Ib=require("node:url"),xD={},fD="12.4.4";console.log=(...t)=>{_.error("CONSOLE","Intercepted console output (MCP protocol protection)",void 0,{args:t})};var Pb=!1,Tb=(()=>{if(typeof __dirname<"u")return __dirname;try{return(0,Fr.dirname)((0,Ib.fileURLToPath)(xD.url))}catch{return Pb=!0,process.cwd()}})(),$m=(0,Fr.resolve)(Tb,"worker-service.cjs");function mD(){Pb&&((0,Eb.existsSync)($m)||_.error("SYSTEM","mcp-server: dirname resolution failed (both __dirname and import.meta.url are unavailable). Fell back to process.cwd() and the resolved WORKER_SCRIPT_PATH does not exist. This is the actual problem \u2014 the worker bundle is fine, but mcp-server cannot locate it. Worker auto-start will fail until the dirname-resolution path is fixed.",{workerScriptPath:$m,mcpServerDir:Tb}))}var kb={search:"/api/search",timeline:"/api/timeline"};async function _m(t,e){_.debug("SYSTEM","\u2192 Worker API",void 0,{endpoint:t,params:e});let r=new URLSearchParams;for(let[o,i]of Object.entries(e))i!=null&&r.append(o,String(i));let n=`${t}?${r}`;try{let o=await ec(n);if(!o.ok){let a=await o.text();throw new Error(`Worker API error (${o.status}): ${a}`)}let i=await o.json();return _.debug("SYSTEM","\u2190 Worker API success",void 0,{endpoint:t}),i}catch(o){return _.error("SYSTEM","\u2190 Worker API error",{endpoint:t},o instanceof Error?o:new Error(String(o))),{content:[{type:"text",text:`Error calling Worker API: ${o instanceof Error?o.message:String(o)}`}],isError:!0}}}async function hD(t,e){let r=await ec(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!r.ok){let o=await r.text();throw new Error(`Worker API error (${r.status}): ${o}`)}let n=await r.json();return _.debug("HTTP","Worker API success (POST)",void 0,{endpoint:t}),{content:[{type:"text",text:JSON.stringify(n,null,2)}]}}async function Fn(t,e){_.debug("HTTP","Worker API request (POST)",void 0,{endpoint:t});try{return await hD(t,e)}catch(r){return _.error("HTTP","Worker API error (POST)",{endpoint:t},r instanceof Error?r:new Error(String(r))),{content:[{type:"text",text:`Error calling Worker API: ${r instanceof Error?r.message:String(r)}`}],isError:!0}}}async function gD(){try{return(await ec("/api/health")).ok}catch(t){return _.debug("SYSTEM","Worker health check failed",{},t instanceof Error?t:new Error(String(t))),!1}}async function vD(){if(await gD())return!0;_.warn("SYSTEM","Worker not available, attempting auto-start for MCP client"),mD();try{let t=am(),e=await ib(t,$m);return e||_.error("SYSTEM","Worker auto-start returned false \u2014 MCP tools that require the worker (search, timeline, get_observations) will fail until the worker is running. Check earlier log lines for the specific failure reason (Bun not found, missing worker bundle, port conflict, etc.)."),e}catch(t){return _.error("SYSTEM","Worker auto-start threw \u2014 MCP tools that require the worker (search, timeline, get_observations) will fail until the worker is running.",void 0,t instanceof Error?t:new Error(String(t))),!1}}var zb=[{name:"__IMPORTANT",description:`3-LAYER WORKFLOW (ALWAYS FOLLOW): 1. search(query) \u2192 Get index with IDs (~50-100 tokens/result) 2. timeline(anchor=ID) \u2192 Get context around interesting results 3. get_observations([IDs]) \u2192 Fetch full details ONLY for filtered IDs diff --git a/plugin/scripts/worker-service.cjs b/plugin/scripts/worker-service.cjs index 21aed0d4..700df4b8 100755 --- a/plugin/scripts/worker-service.cjs +++ b/plugin/scripts/worker-service.cjs @@ -1047,7 +1047,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs. SELECT cwd FROM pending_messages WHERE cwd IS NOT NULL AND cwd != '' GROUP BY cwd - `).all();for(let{cwd:u}of c){let l=Zq(u);l&&n.add(l)}}finally{s?.close()}if(n.size===0)return g.debug("SYSTEM","Worktree adoption found no known parent repos"),i;for(let o of n)try{let a=await yC({repoPath:o,dataDirectory:e,dryRun:t.dryRun});i.push(a)}catch(a){g.warn("SYSTEM","Worktree adoption failed for parent repo (continuing)",{repoPath:o,error:a instanceof Error?a.message:String(a)})}return i}var WB=Oe(j0(),1),HB=Oe(require("http"),1),UA=Oe(require("fs"),1),xh=Oe(require("path"),1);var MA=["search","context","summarize","import","export"],CB=["workflow","search_params","examples","all"];oe();var $A=Oe(j0(),1),DB=Oe($B(),1),jB=Oe(require("path"),1);Tt();oe();function DA(t){let e=[];e.push($A.default.json({limit:"5mb"})),e.push((0,DB.default)({origin:(n,s)=>{!n||n.startsWith("http://localhost:")||n.startsWith("http://127.0.0.1:")?s(null,!0):s(new Error("CORS not allowed"))},methods:["GET","HEAD","POST","PUT","PATCH","DELETE"],allowedHeaders:["Content-Type","X-Requested-With"],credentials:!1})),e.push((n,s,o)=>{let c=[".html",".js",".css",".svg",".png",".jpg",".jpeg",".webp",".woff",".woff2",".ttf",".eot"].some(f=>n.path.endsWith(f)),u=n.path==="/api/logs";if(n.path.startsWith("/health")||n.path==="/"||c||u)return o();let l=Date.now(),d=`${n.method}-${Date.now()}`,p=t(n.method,n.path,n.body);g.debug("HTTP",`\u2192 ${n.method} ${n.path}`,{requestId:d},p);let m=s.send.bind(s);s.send=function(f){let h=Date.now()-l;return g.debug("HTTP",`\u2190 ${s.statusCode} ${n.path}`,{requestId:d,duration:`${h}ms`}),m(f)},o()});let r=Qn(),i=jB.default.join(r,"plugin","ui");return e.push($A.default.static(i)),e}function Sh(t,e,r){let i=t.ip||t.connection.remoteAddress||"";if(!(i==="127.0.0.1"||i==="::1"||i==="::ffff:127.0.0.1"||i==="localhost")){g.warn("SECURITY","Admin endpoint access denied - not localhost",{endpoint:t.path,clientIp:i,method:t.method}),e.status(403).json({error:"Forbidden",message:"Admin endpoints are only accessible from localhost"});return}r()}function jA(t,e,r){if(!r||Object.keys(r).length===0||e.includes("/init"))return"";if(e.includes("/observations")){let i=r.tool_name||"?",n=r.tool_input;return`tool=${g.formatTool(i,n)}`}return e.includes("/summarize")?"requesting summary":""}wh();Ua();Qs();$a();var BB=xh.default.resolve(__dirname,"../skills/mem-search"),Mwe=xh.default.join(BB,"operations"),zA=xh.default.join(BB,"SKILL.md"),FB=(()=>{try{let t=UA.readFileSync(zA,"utf-8");return g.info("SYSTEM","Cached SKILL.md at boot",{path:zA,bytes:Buffer.byteLength(t,"utf-8")}),t}catch(t){return g.debug("SYSTEM","SKILL.md not present at boot, /api/instructions will 404 for topic queries",{path:zA,message:t instanceof Error?t.message:String(t)}),null}})(),$we=(()=>{let t=new Map;for(let e of MA){let r=xh.default.join(Mwe,`${e}.md`);try{t.set(e,UA.readFileSync(r,"utf-8"))}catch(i){g.debug("SYSTEM","Operation instruction file not present at boot",{path:r,message:i instanceof Error?i.message:String(i)})}}return t.size>0&&g.info("SYSTEM","Cached operation instruction files at boot",{count:t.size,operations:Array.from(t.keys())}),t})(),qB="12.4.3",z0=class{app;server=null;options;startTime=Date.now();constructor(e){this.options=e,this.app=(0,WB.default)(),this.setupMiddleware(),this.setupCoreRoutes()}getHttpServer(){return this.server}async listen(e,r){return new Promise((i,n)=>{let s=HB.default.createServer(this.app);this.server=s;let o=c=>{s.off("listening",a),n(c)},a=()=>{s.off("error",o),g.info("SYSTEM","HTTP server started",{host:r,port:e,pid:process.pid}),i()};s.once("error",o),s.once("listening",a),s.listen(e,r)})}async close(){this.server&&(this.server.closeAllConnections(),process.platform==="win32"&&await new Promise(e=>setTimeout(e,500)),await new Promise((e,r)=>{this.server.close(i=>i?r(i):e())}),process.platform==="win32"&&await new Promise(e=>setTimeout(e,500)),this.server=null,g.info("SYSTEM","HTTP server closed"))}registerRoutes(e){e.setupRoutes(this.app)}finalizeRoutes(){this.app.use(LB),this.app.use(UB)}setupMiddleware(){DA(jA).forEach(r=>this.app.use(r))}setupCoreRoutes(){this.app.get("/api/health",(e,r)=>{r.status(200).json({status:"ok",version:qB,workerPath:this.options.workerPath,uptime:Date.now()-this.startTime,managed:process.env.CLAUDE_MEM_MANAGED==="true",hasIpc:typeof process.send=="function",platform:process.platform,pid:process.pid,initialized:this.options.getInitializationComplete(),mcpReady:this.options.getMcpReady(),ai:this.options.getAiStatus()})}),this.app.get("/api/readiness",(e,r)=>{this.options.getInitializationComplete()?r.status(200).json({status:"ready",mcpReady:this.options.getMcpReady()}):r.status(503).json({status:"initializing",message:"Worker is still initializing, please retry"})}),this.app.get("/api/version",(e,r)=>{r.status(200).json({version:qB})}),this.app.get("/api/instructions",(e,r)=>{let i=e.query.topic||"all",n=e.query.operation;if(i&&!CB.includes(i))return r.status(400).json({error:"Invalid topic"});if(n&&!MA.includes(n))return r.status(400).json({error:"Invalid operation"});if(n){let o=$we.get(n);return o===void 0?(g.debug("HTTP","Instruction file not cached at boot",{operation:n}),r.status(404).json({error:"Instruction not found"})):r.json({content:[{type:"text",text:o}]})}if(FB===null)return g.debug("HTTP","SKILL.md not cached at boot",{topic:i}),r.status(404).json({error:"Instruction not found"});let s=this.extractInstructionSection(FB,i);r.json({content:[{type:"text",text:s}]})}),this.app.post("/api/admin/restart",Sh,async(e,r)=>{r.json({status:"restarting"}),process.platform==="win32"&&process.env.CLAUDE_MEM_MANAGED==="true"&&process.send?(g.info("SYSTEM","Sending restart request to wrapper"),process.send({type:"restart"})):setTimeout(async()=>{try{await this.options.onRestart()}finally{process.exit(0)}},100)}),this.app.post("/api/admin/shutdown",Sh,async(e,r)=>{r.json({status:"shutting_down"}),process.platform==="win32"&&process.env.CLAUDE_MEM_MANAGED==="true"&&process.send?(g.info("SYSTEM","Sending shutdown request to wrapper"),process.send({type:"shutdown"})):setTimeout(async()=>{try{await this.options.onShutdown()}finally{process.exit(0)}},100)}),this.app.get("/api/admin/doctor",Sh,(e,r)=>{let o=Xr().getRegistry().getAll().map(f=>({id:f.id,pid:f.pid,type:f.type,status:mi(f.pid)?"alive":"dead",startedAt:f.startedAt})),a=o.filter(f=>f.status==="dead").map(f=>f.pid),c=!Object.keys(process.env).some(f=>UR.has(f)||zR.some(h=>f.startsWith(h))),u=Date.now()-this.startTime,l=Math.floor(u/1e3),d=Math.floor(l/3600),p=Math.floor(l%3600/60),m=d>0?`${d}h ${p}m`:`${p}m`;r.json({supervisor:{running:!0,pid:process.pid,uptime:m},processes:o,health:{deadProcessPids:a,envClean:c}})})}extractInstructionSection(e,r){let i={workflow:this.extractBetween(e,"## The Workflow","## Search Parameters"),search_params:this.extractBetween(e,"## Search Parameters","## Examples"),examples:this.extractBetween(e,"## Examples","## Why This Workflow"),all:e};return i[r]||i.all}extractBetween(e,r,i){let n=e.indexOf(r),s=e.indexOf(i);return n===-1?e:s===-1?e.substring(n):e.substring(n,s).trim()}};var qt=Oe(require("path"),1),kh=require("os"),or=require("fs"),VB=require("child_process"),KB=require("util");oe();hn();Tt();var Xi=require("fs"),Eh=require("path");oe();function ZB(t){try{return(0,Xi.existsSync)(t)?JSON.parse((0,Xi.readFileSync)(t,"utf-8")):{}}catch(e){return g.error("CONFIG","Failed to read Cursor registry, using empty registry",{file:t,error:e instanceof Error?e.message:String(e)}),{}}}function GB(t,e){let r=(0,Eh.join)(t,"..");(0,Xi.mkdirSync)(r,{recursive:!0}),(0,Xi.writeFileSync)(t,JSON.stringify(e,null,2))}function LA(t,e){let r=(0,Eh.join)(t,".cursor","rules"),i=(0,Eh.join)(r,"claude-mem-context.mdc"),n=`${i}.tmp`;(0,Xi.mkdirSync)(r,{recursive:!0});let s=`--- + `).all();for(let{cwd:u}of c){let l=Zq(u);l&&n.add(l)}}finally{s?.close()}if(n.size===0)return g.debug("SYSTEM","Worktree adoption found no known parent repos"),i;for(let o of n)try{let a=await yC({repoPath:o,dataDirectory:e,dryRun:t.dryRun});i.push(a)}catch(a){g.warn("SYSTEM","Worktree adoption failed for parent repo (continuing)",{repoPath:o,error:a instanceof Error?a.message:String(a)})}return i}var WB=Oe(j0(),1),HB=Oe(require("http"),1),UA=Oe(require("fs"),1),xh=Oe(require("path"),1);var MA=["search","context","summarize","import","export"],CB=["workflow","search_params","examples","all"];oe();var $A=Oe(j0(),1),DB=Oe($B(),1),jB=Oe(require("path"),1);Tt();oe();function DA(t){let e=[];e.push($A.default.json({limit:"5mb"})),e.push((0,DB.default)({origin:(n,s)=>{!n||n.startsWith("http://localhost:")||n.startsWith("http://127.0.0.1:")?s(null,!0):s(new Error("CORS not allowed"))},methods:["GET","HEAD","POST","PUT","PATCH","DELETE"],allowedHeaders:["Content-Type","X-Requested-With"],credentials:!1})),e.push((n,s,o)=>{let c=[".html",".js",".css",".svg",".png",".jpg",".jpeg",".webp",".woff",".woff2",".ttf",".eot"].some(f=>n.path.endsWith(f)),u=n.path==="/api/logs";if(n.path.startsWith("/health")||n.path==="/"||c||u)return o();let l=Date.now(),d=`${n.method}-${Date.now()}`,p=t(n.method,n.path,n.body);g.debug("HTTP",`\u2192 ${n.method} ${n.path}`,{requestId:d},p);let m=s.send.bind(s);s.send=function(f){let h=Date.now()-l;return g.debug("HTTP",`\u2190 ${s.statusCode} ${n.path}`,{requestId:d,duration:`${h}ms`}),m(f)},o()});let r=Qn(),i=jB.default.join(r,"plugin","ui");return e.push($A.default.static(i)),e}function Sh(t,e,r){let i=t.ip||t.connection.remoteAddress||"";if(!(i==="127.0.0.1"||i==="::1"||i==="::ffff:127.0.0.1"||i==="localhost")){g.warn("SECURITY","Admin endpoint access denied - not localhost",{endpoint:t.path,clientIp:i,method:t.method}),e.status(403).json({error:"Forbidden",message:"Admin endpoints are only accessible from localhost"});return}r()}function jA(t,e,r){if(!r||Object.keys(r).length===0||e.includes("/init"))return"";if(e.includes("/observations")){let i=r.tool_name||"?",n=r.tool_input;return`tool=${g.formatTool(i,n)}`}return e.includes("/summarize")?"requesting summary":""}wh();Ua();Qs();$a();var BB=xh.default.resolve(__dirname,"../skills/mem-search"),Mwe=xh.default.join(BB,"operations"),zA=xh.default.join(BB,"SKILL.md"),FB=(()=>{try{let t=UA.readFileSync(zA,"utf-8");return g.info("SYSTEM","Cached SKILL.md at boot",{path:zA,bytes:Buffer.byteLength(t,"utf-8")}),t}catch(t){return g.debug("SYSTEM","SKILL.md not present at boot, /api/instructions will 404 for topic queries",{path:zA,message:t instanceof Error?t.message:String(t)}),null}})(),$we=(()=>{let t=new Map;for(let e of MA){let r=xh.default.join(Mwe,`${e}.md`);try{t.set(e,UA.readFileSync(r,"utf-8"))}catch(i){g.debug("SYSTEM","Operation instruction file not present at boot",{path:r,message:i instanceof Error?i.message:String(i)})}}return t.size>0&&g.info("SYSTEM","Cached operation instruction files at boot",{count:t.size,operations:Array.from(t.keys())}),t})(),qB="12.4.4",z0=class{app;server=null;options;startTime=Date.now();constructor(e){this.options=e,this.app=(0,WB.default)(),this.setupMiddleware(),this.setupCoreRoutes()}getHttpServer(){return this.server}async listen(e,r){return new Promise((i,n)=>{let s=HB.default.createServer(this.app);this.server=s;let o=c=>{s.off("listening",a),n(c)},a=()=>{s.off("error",o),g.info("SYSTEM","HTTP server started",{host:r,port:e,pid:process.pid}),i()};s.once("error",o),s.once("listening",a),s.listen(e,r)})}async close(){this.server&&(this.server.closeAllConnections(),process.platform==="win32"&&await new Promise(e=>setTimeout(e,500)),await new Promise((e,r)=>{this.server.close(i=>i?r(i):e())}),process.platform==="win32"&&await new Promise(e=>setTimeout(e,500)),this.server=null,g.info("SYSTEM","HTTP server closed"))}registerRoutes(e){e.setupRoutes(this.app)}finalizeRoutes(){this.app.use(LB),this.app.use(UB)}setupMiddleware(){DA(jA).forEach(r=>this.app.use(r))}setupCoreRoutes(){this.app.get("/api/health",(e,r)=>{r.status(200).json({status:"ok",version:qB,workerPath:this.options.workerPath,uptime:Date.now()-this.startTime,managed:process.env.CLAUDE_MEM_MANAGED==="true",hasIpc:typeof process.send=="function",platform:process.platform,pid:process.pid,initialized:this.options.getInitializationComplete(),mcpReady:this.options.getMcpReady(),ai:this.options.getAiStatus()})}),this.app.get("/api/readiness",(e,r)=>{this.options.getInitializationComplete()?r.status(200).json({status:"ready",mcpReady:this.options.getMcpReady()}):r.status(503).json({status:"initializing",message:"Worker is still initializing, please retry"})}),this.app.get("/api/version",(e,r)=>{r.status(200).json({version:qB})}),this.app.get("/api/instructions",(e,r)=>{let i=e.query.topic||"all",n=e.query.operation;if(i&&!CB.includes(i))return r.status(400).json({error:"Invalid topic"});if(n&&!MA.includes(n))return r.status(400).json({error:"Invalid operation"});if(n){let o=$we.get(n);return o===void 0?(g.debug("HTTP","Instruction file not cached at boot",{operation:n}),r.status(404).json({error:"Instruction not found"})):r.json({content:[{type:"text",text:o}]})}if(FB===null)return g.debug("HTTP","SKILL.md not cached at boot",{topic:i}),r.status(404).json({error:"Instruction not found"});let s=this.extractInstructionSection(FB,i);r.json({content:[{type:"text",text:s}]})}),this.app.post("/api/admin/restart",Sh,async(e,r)=>{r.json({status:"restarting"}),process.platform==="win32"&&process.env.CLAUDE_MEM_MANAGED==="true"&&process.send?(g.info("SYSTEM","Sending restart request to wrapper"),process.send({type:"restart"})):setTimeout(async()=>{try{await this.options.onRestart()}finally{process.exit(0)}},100)}),this.app.post("/api/admin/shutdown",Sh,async(e,r)=>{r.json({status:"shutting_down"}),process.platform==="win32"&&process.env.CLAUDE_MEM_MANAGED==="true"&&process.send?(g.info("SYSTEM","Sending shutdown request to wrapper"),process.send({type:"shutdown"})):setTimeout(async()=>{try{await this.options.onShutdown()}finally{process.exit(0)}},100)}),this.app.get("/api/admin/doctor",Sh,(e,r)=>{let o=Xr().getRegistry().getAll().map(f=>({id:f.id,pid:f.pid,type:f.type,status:mi(f.pid)?"alive":"dead",startedAt:f.startedAt})),a=o.filter(f=>f.status==="dead").map(f=>f.pid),c=!Object.keys(process.env).some(f=>UR.has(f)||zR.some(h=>f.startsWith(h))),u=Date.now()-this.startTime,l=Math.floor(u/1e3),d=Math.floor(l/3600),p=Math.floor(l%3600/60),m=d>0?`${d}h ${p}m`:`${p}m`;r.json({supervisor:{running:!0,pid:process.pid,uptime:m},processes:o,health:{deadProcessPids:a,envClean:c}})})}extractInstructionSection(e,r){let i={workflow:this.extractBetween(e,"## The Workflow","## Search Parameters"),search_params:this.extractBetween(e,"## Search Parameters","## Examples"),examples:this.extractBetween(e,"## Examples","## Why This Workflow"),all:e};return i[r]||i.all}extractBetween(e,r,i){let n=e.indexOf(r),s=e.indexOf(i);return n===-1?e:s===-1?e.substring(n):e.substring(n,s).trim()}};var qt=Oe(require("path"),1),kh=require("os"),or=require("fs"),VB=require("child_process"),KB=require("util");oe();hn();Tt();var Xi=require("fs"),Eh=require("path");oe();function ZB(t){try{return(0,Xi.existsSync)(t)?JSON.parse((0,Xi.readFileSync)(t,"utf-8")):{}}catch(e){return g.error("CONFIG","Failed to read Cursor registry, using empty registry",{file:t,error:e instanceof Error?e.message:String(e)}),{}}}function GB(t,e){let r=(0,Eh.join)(t,"..");(0,Xi.mkdirSync)(r,{recursive:!0}),(0,Xi.writeFileSync)(t,JSON.stringify(e,null,2))}function LA(t,e){let r=(0,Eh.join)(t,".cursor","rules"),i=(0,Eh.join)(r,"claude-mem-context.mdc"),n=`${i}.tmp`;(0,Xi.mkdirSync)(r,{recursive:!0});let s=`--- alwaysApply: true description: "Claude-mem context from past sessions (auto-updated)" --- @@ -1709,7 +1709,7 @@ ${s.formatTableHeader()}`,m=d.map((f,h)=>s.formatObservationIndex(f,h));i.json({ `);xr(zi);let n=this.findClaudeExecutable(),s=pi(Zf()),o=Ng({prompt:i,options:{model:this.getModelId(),cwd:zi,disallowedTools:Qee,pathToClaudeCodeExecutable:n,env:s,mcpServers:{}}}),a;try{for await(let c of o)c.session_id&&(a=c.session_id),c.type==="result"&&g.info("WORKER",`Knowledge agent primed for corpus "${e.name}"`)}catch(c){if(a)c instanceof Error?g.debug("WORKER",`SDK process exited after priming corpus "${e.name}" \u2014 session captured, continuing`,{},c):g.debug("WORKER",`SDK process exited after priming corpus "${e.name}" \u2014 session captured, continuing (non-Error thrown)`,{thrownValue:String(c)});else throw c}if(!a)throw new Error(`Failed to capture session_id while priming corpus "${e.name}"`);return e.session_id=a,this.corpusStore.write(e),a}async query(e,r){if(!e.session_id)throw new Error(`Corpus "${e.name}" has no session \u2014 call prime first`);try{let i=await this.executeQuery(e,r);return i.session_id!==e.session_id&&(e.session_id=i.session_id,this.corpusStore.write(e)),i}catch(i){if(!this.isSessionResumeError(i))throw i instanceof Error?g.error("WORKER",`Query failed for corpus "${e.name}"`,{},i):g.error("WORKER",`Query failed for corpus "${e.name}" (non-Error thrown)`,{thrownValue:String(i)}),i;g.info("WORKER",`Session expired for corpus "${e.name}", auto-repriming...`),await this.prime(e);let n=this.corpusStore.read(e.name);if(!n||!n.session_id)throw new Error(`Auto-reprime failed for corpus "${e.name}"`);let s=await this.executeQuery(n,r);return s.session_id!==n.session_id&&(n.session_id=s.session_id,this.corpusStore.write(n)),s}}async reprime(e){return e.session_id=null,this.prime(e)}isSessionResumeError(e){let r=e instanceof Error?e.message:String(e);return/session|resume|expired|invalid.*session|not found/i.test(r)}async executeQuery(e,r){xr(zi);let i=this.findClaudeExecutable(),n=pi(Zf()),s=Ng({prompt:r,options:{model:this.getModelId(),resume:e.session_id,cwd:zi,disallowedTools:Qee,pathToClaudeCodeExecutable:i,env:n,mcpServers:{}}}),o="",a=e.session_id;try{for await(let c of s)c.session_id&&(a=c.session_id),c.type==="assistant"&&(o=c.message.content.filter(l=>l.type==="text").map(l=>l.text).join(""))}catch(c){if(o)c instanceof Error?g.debug("WORKER","SDK process exited after query \u2014 answer captured, continuing",{},c):g.debug("WORKER","SDK process exited after query \u2014 answer captured, continuing (non-Error thrown)",{thrownValue:String(c)});else throw c}return{answer:o,session_id:a}}getModelId(){return ke.loadFromFile(kt).CLAUDE_MEM_MODEL}findClaudeExecutable(){let e=ke.loadFromFile(kt);if(e.CLAUDE_CODE_PATH){let{existsSync:r}=require("fs");if(!r(e.CLAUDE_CODE_PATH))throw new Error(`CLAUDE_CODE_PATH is set to "${e.CLAUDE_CODE_PATH}" but the file does not exist.`);return e.CLAUDE_CODE_PATH}if(process.platform==="win32")try{return(0,tj.execSync)("where claude.cmd",{encoding:"utf8",windowsHide:!0,stdio:["ignore","pipe","ignore"]}),"claude.cmd"}catch{}try{let r=(0,tj.execSync)(process.platform==="win32"?"where claude":"which claude",{encoding:"utf8",windowsHide:!0,stdio:["ignore","pipe","ignore"]}).trim().split(` `)[0].trim();if(r)return r}catch(r){r instanceof Error?g.debug("WORKER","Claude executable auto-detection failed",{},r):g.debug("WORKER","Claude executable auto-detection failed (non-Error thrown)",{thrownValue:String(r)})}throw new Error(`Claude executable not found. Please either: 1. Add "claude" to your system PATH, or -2. Set CLAUDE_CODE_PATH in ~/.claude-mem/settings.json`)}};Qs();var tje={},JDe="12.4.3";function Rte(t,e){return{continue:!0,suppressOutput:!0,status:t,...e&&{message:e}}}var JE=class t{server;startTime=Date.now();mcpClient;mcpReady=!1;initializationCompleteFlag=!1;isShuttingDown=!1;dbManager;sessionManager;sseBroadcaster;sdkAgent;geminiAgent;openRouterAgent;paginationHelper;settingsManager;sessionEventBroadcaster;completionHandler;corpusStore;searchRoutes=null;chromaMcpManager=null;transcriptWatcher=null;initializationComplete;resolveInitialization;lastAiInteraction=null;constructor(){this.initializationComplete=new Promise(e=>{this.resolveInitialization=e}),this.dbManager=new q0,this.sessionManager=new Z0(this.dbManager),this.sseBroadcaster=new G0,this.sdkAgent=new qx(this.dbManager,this.sessionManager),this.geminiAgent=new Wx(this.dbManager,this.sessionManager),this.openRouterAgent=new Zx(this.dbManager,this.sessionManager),this.paginationHelper=new Gx(this.dbManager),this.settingsManager=new Vx(this.dbManager),this.sessionEventBroadcaster=new Qx(this.sseBroadcaster,this),this.completionHandler=new eE(this.sessionManager,this.sessionEventBroadcaster,this.dbManager),this.corpusStore=new ZE,vZ({sessionManager:this.sessionManager,dbManager:this.dbManager,eventBroadcaster:this.sessionEventBroadcaster}),this.sessionManager.setOnSessionDeleted(()=>{this.broadcastProcessingStatus()}),this.mcpClient=new Kl({name:"worker-search-proxy",version:JDe},{capabilities:{}}),this.server=new z0({getInitializationComplete:()=>this.initializationCompleteFlag,getMcpReady:()=>this.mcpReady,onShutdown:()=>this.shutdown(),onRestart:()=>this.shutdown(),workerPath:__filename,getAiStatus:()=>{let e="claude";return yp()&&Tu()?e="openrouter":vp()&&ku()&&(e="gemini"),{provider:e,authMethod:vS(),lastInteraction:this.lastAiInteraction?{timestamp:this.lastAiInteraction.timestamp,success:this.lastAiInteraction.success,...this.lastAiInteraction.error&&{error:this.lastAiInteraction.error}}:null}}}),this.registerRoutes(),this.registerSignalHandlers()}registerSignalHandlers(){tq(async()=>{this.isShuttingDown=!0,await this.shutdown()})}registerRoutes(){this.server.registerRoutes(new BE),this.server.app.get("/api/context/inject",async(r,i,n)=>{if(!this.initializationCompleteFlag||!this.searchRoutes){g.warn("SYSTEM","Context requested before initialization complete, returning empty"),i.status(200).json({content:[{type:"text",text:""}]});return}n()}),this.server.app.use("/api",async(r,i,n)=>{if(r.path==="/chroma/status"||r.path==="/health"||r.path==="/readiness"||r.path==="/version"){n();return}if(this.initializationCompleteFlag){n();return}let s=12e4,o=new Promise((a,c)=>setTimeout(()=>c(new Error("Database initialization timeout")),s));try{await Promise.race([this.initializationComplete,o]),n()}catch(a){a instanceof Error?g.error("WORKER",`Request to ${r.method} ${r.path} rejected \u2014 DB not initialized`,{},a):g.error("WORKER",`Request to ${r.method} ${r.path} rejected \u2014 DB not initialized with non-Error`,{},new Error(String(a))),i.status(503).json({error:"Service initializing",message:"Database is still initializing, please retry"});return}}),this.server.registerRoutes(new RE(this.sseBroadcaster,this.dbManager,this.sessionManager));let e=new PE(this.sessionManager,this.dbManager,this.sdkAgent,this.geminiAgent,this.openRouterAgent,this.sessionEventBroadcaster,this,this.completionHandler);this.server.registerRoutes(e),yZ((r,i)=>e.ensureGeneratorRunning(r,i)),this.server.registerRoutes(new AE(this.paginationHelper,this.dbManager,this.sessionManager,this.sseBroadcaster,this,this.startTime)),this.server.registerRoutes(new LE(this.settingsManager)),this.server.registerRoutes(new qE),this.server.registerRoutes(new WE(this.dbManager,"claude-mem"))}async start(){let e=On(),r=VR();await eq(),await this.server.listen(e,r),Iq({pid:process.pid,port:e,startedAt:new Date().toISOString()}),Xr().registerProcess("worker",{pid:process.pid,type:"worker",startedAt:new Date().toISOString()}),g.info("SYSTEM","Worker started",{host:r,port:e,pid:process.pid}),this.initializeBackground().catch(i=>{g.error("SYSTEM","Background initialization failed",{},i)})}async initializeBackground(){try{g.info("WORKER","Background initialization starting..."),await Oq();let{ModeManager:e}=await Promise.resolve().then(()=>(Pn(),aZ)),{SettingsDefaultsManager:r}=await Promise.resolve().then(()=>(sr(),OF)),{USER_SETTINGS_PATH:i}=await Promise.resolve().then(()=>(Tt(),$F)),n=r.loadFromFile(i),s=n.CLAUDE_MEM_MODE;e.getInstance().loadMode(s),g.info("SYSTEM",`Mode loaded: ${s}`),(n.CLAUDE_MEM_MODE==="local"||!n.CLAUDE_MEM_MODE)&&(g.info("WORKER","Checking for one-time Chroma migration..."),Rq()),g.info("WORKER","Checking for one-time CWD remap..."),Cq(),g.info("WORKER","Adopting merged worktrees (background)..."),Gq({}).then(h=>{if(h)for(let v of h)(v.adoptedObservations>0||v.adoptedSummaries>0||v.chromaUpdates>0)&&g.info("SYSTEM","Merged worktrees adopted in background",v),v.errors.length>0&&g.warn("SYSTEM","Worktree adoption had per-branch errors",{repoPath:v.repoPath,errors:v.errors})}).catch(h=>{g.error("WORKER","Worktree adoption failed (background)",{},h instanceof Error?h:new Error(String(h)))}),n.CLAUDE_MEM_CHROMA_ENABLED!=="false"?(this.chromaMcpManager=Fi.getInstance(),g.info("SYSTEM","ChromaMcpManager initialized (lazy - connects on first use)")):g.info("SYSTEM","Chroma disabled via CLAUDE_MEM_CHROMA_ENABLED=false, skipping ChromaMcpManager"),g.info("WORKER","Initializing database manager..."),await this.dbManager.initialize();try{g.info("WORKER","Running startup GC for pending messages...");let{PendingMessageStore:h}=await Promise.resolve().then(()=>(W0(),GA)),y=new h(this.dbManager.getSessionStore().db,3).clearFailedOlderThan(10080*60*1e3);y>0&&g.info("QUEUE","Startup GC cleared old failed pending_messages rows",{cleared:y})}catch(h){g.warn("QUEUE","Startup GC for failed pending_messages rows failed",{},h instanceof Error?h:void 0)}Uq(),g.info("WORKER","Initializing search services...");let a=new Jx,c=new Xx,u=new Yx(this.dbManager.getSessionSearch(),this.dbManager.getSessionStore(),this.dbManager.getChromaSync(),a,c);this.searchRoutes=new jE(u),this.server.registerRoutes(this.searchRoutes),g.info("WORKER","SearchManager initialized and search routes registered");let{SearchOrchestrator:l}=await Promise.resolve().then(()=>(gD(),kX)),d=new l(this.dbManager.getSessionSearch(),this.dbManager.getSessionStore(),this.dbManager.getChromaSync()),p=new VE(this.dbManager.getSessionStore(),d,this.corpusStore),m=new KE(this.corpusStore);this.server.registerRoutes(new HE(this.corpusStore,p,m)),g.info("WORKER","CorpusRoutes registered"),this.initializationCompleteFlag=!0,this.resolveInitialization(),g.info("SYSTEM","Core initialization complete (DB + search ready)"),await this.startTranscriptWatcher(n),this.chromaMcpManager&&Fa.backfillAllProjects(this.dbManager.getSessionStore()).then(()=>{g.info("CHROMA_SYNC","Backfill check complete for all projects")}).catch(h=>{g.error("CHROMA_SYNC","Backfill failed (non-blocking)",{},h)});let f=Ote.default.join(__dirname,"mcp-server.cjs");this.mcpReady=(0,gj.existsSync)(f),this.runMcpSelfCheck(f).catch(h=>{g.debug("WORKER","MCP self-check failed (non-fatal)",{error:h.message})});return}catch(e){g.error("SYSTEM","Background initialization failed",{},e instanceof Error?e:void 0)}}async runMcpSelfCheck(e){try{Xr().assertCanSpawn("mcp server");let r=new Xl({command:process.execPath,args:[e],env:Object.fromEntries(Object.entries(pi(process.env)).filter(([,o])=>o!==void 0))}),i=6e4,n=this.mcpClient.connect(r),s=new Promise((o,a)=>{setTimeout(()=>a(new Error("MCP connection timeout")),6e4)});await Promise.race([n,s]),g.info("WORKER","MCP loopback self-check connected successfully"),await r.close()}catch(r){g.warn("WORKER","MCP loopback self-check failed",{error:r instanceof Error?r.message:String(r)})}}async startTranscriptWatcher(e){if(!(e.CLAUDE_MEM_TRANSCRIPTS_ENABLED!=="false")){g.info("TRANSCRIPT","Transcript watcher disabled via CLAUDE_MEM_TRANSCRIPTS_ENABLED=false");return}let i=e.CLAUDE_MEM_TRANSCRIPTS_CONFIG_PATH||rE,n=ra(i);(0,gj.existsSync)(n)||(IX(i),g.info("TRANSCRIPT","Created default transcript watch config",{configPath:n}));let s=TX(i),o=ra(s.stateFile??nE);try{this.transcriptWatcher=new TE(s,o),await this.transcriptWatcher.start()}catch(a){this.transcriptWatcher?.stop(),this.transcriptWatcher=null,a instanceof Error?g.error("WORKER","Failed to start transcript watcher (continuing without Codex ingestion)",{configPath:n},a):g.error("WORKER","Failed to start transcript watcher with non-Error (continuing without Codex ingestion)",{configPath:n},new Error(String(a)));return}g.info("TRANSCRIPT","Transcript watcher started",{configPath:n,statePath:o,watches:s.watches.length})}getActiveAgent(){return yp()&&Tu()?this.openRouterAgent:vp()&&ku()?this.geminiAgent:this.sdkAgent}startSessionProcessor(e,r){if(!e)return;let i=e.sessionDbId,n=this.getActiveAgent(),s=n.constructor.name;e.abortController.signal.aborted&&(g.debug("SYSTEM","Replacing aborted AbortController before starting generator",{sessionId:e.sessionDbId}),e.abortController=new AbortController);let o=!1,a=!1;g.info("SYSTEM",`Starting generator (${r}) using ${s}`,{sessionId:i}),e.lastGeneratorActivity=Date.now(),e.generatorPromise=n.startSession(e,this).catch(async c=>{let u=c?.message||"";if(["Claude executable not found","CLAUDE_CODE_PATH","ENOENT","spawn","Invalid API key","API_KEY_INVALID","API key expired","API key not valid","PERMISSION_DENIED","Gemini API error: 400","Gemini API error: 401","Gemini API error: 403","FOREIGN KEY constraint failed"].some(p=>u.includes(p))){o=!0,this.lastAiInteraction={timestamp:Date.now(),success:!1,provider:s,error:u},g.error("SDK","Unrecoverable generator error - will NOT restart",{sessionId:e.sessionDbId,project:e.project,errorMessage:u});return}if(this.isSessionTerminatedError(c))return g.warn("SDK","SDK resume failed, falling back to standalone processing",{sessionId:e.sessionDbId,project:e.project,reason:c instanceof Error?c.message:String(c)}),this.runFallbackForTerminatedSession(e,c);throw["aborted by user","No conversation found"].some(p=>u.includes(p))&&e.memorySessionId&&(g.warn("SDK","Detected stale resume failure, clearing memorySessionId for fresh start",{sessionId:e.sessionDbId,memorySessionId:e.memorySessionId,errorMessage:u}),this.dbManager.getSessionStore().updateMemorySessionId(e.sessionDbId,null),e.memorySessionId=null,e.forceInit=!0),g.error("SDK","Session generator failed",{sessionId:e.sessionDbId,project:e.project,provider:s},c),a=!0,this.lastAiInteraction={timestamp:Date.now(),success:!1,provider:s,error:u},c}).finally(async()=>{let c=ja(e.sessionDbId);if(c&&c.process.exitCode===null&&await za(c,5e3),e.generatorPromise=null,!a&&!o&&(this.lastAiInteraction={timestamp:Date.now(),success:!0,provider:s}),o){this.terminateSession(e.sessionDbId,"unrecoverable_error");return}let l=this.sessionManager.getPendingMessageStore().getPendingCount(e.sessionDbId);if(e.idleTimedOut&&(e.idleTimedOut=!1,l===0)){this.terminateSession(e.sessionDbId,"idle_timeout");return}if(l>0){e.restartGuard||(e.restartGuard=new Wa);let d=e.restartGuard.recordRestart();if(e.consecutiveRestarts=(e.consecutiveRestarts||0)+1,!d){g.error("SYSTEM","Restart guard tripped: session is dead, terminating",{sessionId:e.sessionDbId,pendingCount:l,restartsInWindow:e.restartGuard.restartsInWindow,windowMs:e.restartGuard.windowMs,maxRestarts:e.restartGuard.maxRestarts,consecutiveFailures:e.restartGuard.consecutiveFailuresSinceSuccess,maxConsecutiveFailures:e.restartGuard.maxConsecutiveFailures}),e.consecutiveRestarts=0,this.terminateSession(e.sessionDbId,"max_restarts_exceeded");return}g.info("SYSTEM","Pending work remains after generator exit, restarting with fresh AbortController",{sessionId:e.sessionDbId,pendingCount:l,attempt:e.consecutiveRestarts}),e.abortController=new AbortController,this.startSessionProcessor(e,"pending-work-restart"),this.broadcastProcessingStatus()}else e.restartGuard?.recordSuccess(),e.consecutiveRestarts=0,this.completionHandler.finalizeSession(e.sessionDbId),this.sessionManager.removeSessionImmediate(e.sessionDbId)})}static SESSION_TERMINATED_PATTERNS=["process aborted by user","processtransport","not ready for writing","session generator failed","claude code process"];isSessionTerminatedError(e){let i=(e instanceof Error?e.message:String(e)).toLowerCase();return t.SESSION_TERMINATED_PATTERNS.some(n=>i.includes(n))}async runFallbackForTerminatedSession(e,r){if(!e)return;let i=e.sessionDbId;if(!e.memorySessionId){let n=`fallback-${i}-${Date.now()}`;e.memorySessionId=n,this.dbManager.getSessionStore().updateMemorySessionId(i,n)}if(ku())try{await this.geminiAgent.startSession(e,this);return}catch(n){n instanceof Error?(g.warn("WORKER","Fallback Gemini failed, trying OpenRouter",{sessionId:i}),g.error("WORKER","Gemini fallback error detail",{sessionId:i},n)):g.error("WORKER","Gemini fallback failed with non-Error",{sessionId:i},new Error(String(n)))}if(Tu())try{await this.openRouterAgent.startSession(e,this);return}catch(n){n instanceof Error?g.error("WORKER","Fallback OpenRouter failed, will abandon messages",{sessionId:i},n):g.error("WORKER","Fallback OpenRouter failed with non-Error, will abandon messages",{sessionId:i},new Error(String(n)))}this.completionHandler.finalizeSession(i),this.sessionManager.removeSessionImmediate(i)}terminateSession(e,r){g.info("SYSTEM","Session terminated",{sessionId:e,reason:r}),this.completionHandler.finalizeSession(e),this.sessionManager.removeSessionImmediate(e)}async processPendingQueues(e=10){let{PendingMessageStore:r}=await Promise.resolve().then(()=>(W0(),GA)),i=new r(this.dbManager.getSessionStore().db,3),n=this.dbManager.getSessionStore(),s=360*60*1e3,o=Date.now()-s,a=n.db.prepare(` +2. Set CLAUDE_CODE_PATH in ~/.claude-mem/settings.json`)}};Qs();var tje={},JDe="12.4.4";function Rte(t,e){return{continue:!0,suppressOutput:!0,status:t,...e&&{message:e}}}var JE=class t{server;startTime=Date.now();mcpClient;mcpReady=!1;initializationCompleteFlag=!1;isShuttingDown=!1;dbManager;sessionManager;sseBroadcaster;sdkAgent;geminiAgent;openRouterAgent;paginationHelper;settingsManager;sessionEventBroadcaster;completionHandler;corpusStore;searchRoutes=null;chromaMcpManager=null;transcriptWatcher=null;initializationComplete;resolveInitialization;lastAiInteraction=null;constructor(){this.initializationComplete=new Promise(e=>{this.resolveInitialization=e}),this.dbManager=new q0,this.sessionManager=new Z0(this.dbManager),this.sseBroadcaster=new G0,this.sdkAgent=new qx(this.dbManager,this.sessionManager),this.geminiAgent=new Wx(this.dbManager,this.sessionManager),this.openRouterAgent=new Zx(this.dbManager,this.sessionManager),this.paginationHelper=new Gx(this.dbManager),this.settingsManager=new Vx(this.dbManager),this.sessionEventBroadcaster=new Qx(this.sseBroadcaster,this),this.completionHandler=new eE(this.sessionManager,this.sessionEventBroadcaster,this.dbManager),this.corpusStore=new ZE,vZ({sessionManager:this.sessionManager,dbManager:this.dbManager,eventBroadcaster:this.sessionEventBroadcaster}),this.sessionManager.setOnSessionDeleted(()=>{this.broadcastProcessingStatus()}),this.mcpClient=new Kl({name:"worker-search-proxy",version:JDe},{capabilities:{}}),this.server=new z0({getInitializationComplete:()=>this.initializationCompleteFlag,getMcpReady:()=>this.mcpReady,onShutdown:()=>this.shutdown(),onRestart:()=>this.shutdown(),workerPath:__filename,getAiStatus:()=>{let e="claude";return yp()&&Tu()?e="openrouter":vp()&&ku()&&(e="gemini"),{provider:e,authMethod:vS(),lastInteraction:this.lastAiInteraction?{timestamp:this.lastAiInteraction.timestamp,success:this.lastAiInteraction.success,...this.lastAiInteraction.error&&{error:this.lastAiInteraction.error}}:null}}}),this.registerRoutes(),this.registerSignalHandlers()}registerSignalHandlers(){tq(async()=>{this.isShuttingDown=!0,await this.shutdown()})}registerRoutes(){this.server.registerRoutes(new BE),this.server.app.get("/api/context/inject",async(r,i,n)=>{if(!this.initializationCompleteFlag||!this.searchRoutes){g.warn("SYSTEM","Context requested before initialization complete, returning empty"),i.status(200).json({content:[{type:"text",text:""}]});return}n()}),this.server.app.use("/api",async(r,i,n)=>{if(r.path==="/chroma/status"||r.path==="/health"||r.path==="/readiness"||r.path==="/version"){n();return}if(this.initializationCompleteFlag){n();return}let s=12e4,o=new Promise((a,c)=>setTimeout(()=>c(new Error("Database initialization timeout")),s));try{await Promise.race([this.initializationComplete,o]),n()}catch(a){a instanceof Error?g.error("WORKER",`Request to ${r.method} ${r.path} rejected \u2014 DB not initialized`,{},a):g.error("WORKER",`Request to ${r.method} ${r.path} rejected \u2014 DB not initialized with non-Error`,{},new Error(String(a))),i.status(503).json({error:"Service initializing",message:"Database is still initializing, please retry"});return}}),this.server.registerRoutes(new RE(this.sseBroadcaster,this.dbManager,this.sessionManager));let e=new PE(this.sessionManager,this.dbManager,this.sdkAgent,this.geminiAgent,this.openRouterAgent,this.sessionEventBroadcaster,this,this.completionHandler);this.server.registerRoutes(e),yZ((r,i)=>e.ensureGeneratorRunning(r,i)),this.server.registerRoutes(new AE(this.paginationHelper,this.dbManager,this.sessionManager,this.sseBroadcaster,this,this.startTime)),this.server.registerRoutes(new LE(this.settingsManager)),this.server.registerRoutes(new qE),this.server.registerRoutes(new WE(this.dbManager,"claude-mem"))}async start(){let e=On(),r=VR();await eq(),await this.server.listen(e,r),Iq({pid:process.pid,port:e,startedAt:new Date().toISOString()}),Xr().registerProcess("worker",{pid:process.pid,type:"worker",startedAt:new Date().toISOString()}),g.info("SYSTEM","Worker started",{host:r,port:e,pid:process.pid}),this.initializeBackground().catch(i=>{g.error("SYSTEM","Background initialization failed",{},i)})}async initializeBackground(){try{g.info("WORKER","Background initialization starting..."),await Oq();let{ModeManager:e}=await Promise.resolve().then(()=>(Pn(),aZ)),{SettingsDefaultsManager:r}=await Promise.resolve().then(()=>(sr(),OF)),{USER_SETTINGS_PATH:i}=await Promise.resolve().then(()=>(Tt(),$F)),n=r.loadFromFile(i),s=n.CLAUDE_MEM_MODE;e.getInstance().loadMode(s),g.info("SYSTEM",`Mode loaded: ${s}`),(n.CLAUDE_MEM_MODE==="local"||!n.CLAUDE_MEM_MODE)&&(g.info("WORKER","Checking for one-time Chroma migration..."),Rq()),g.info("WORKER","Checking for one-time CWD remap..."),Cq(),g.info("WORKER","Adopting merged worktrees (background)..."),Gq({}).then(h=>{if(h)for(let v of h)(v.adoptedObservations>0||v.adoptedSummaries>0||v.chromaUpdates>0)&&g.info("SYSTEM","Merged worktrees adopted in background",v),v.errors.length>0&&g.warn("SYSTEM","Worktree adoption had per-branch errors",{repoPath:v.repoPath,errors:v.errors})}).catch(h=>{g.error("WORKER","Worktree adoption failed (background)",{},h instanceof Error?h:new Error(String(h)))}),n.CLAUDE_MEM_CHROMA_ENABLED!=="false"?(this.chromaMcpManager=Fi.getInstance(),g.info("SYSTEM","ChromaMcpManager initialized (lazy - connects on first use)")):g.info("SYSTEM","Chroma disabled via CLAUDE_MEM_CHROMA_ENABLED=false, skipping ChromaMcpManager"),g.info("WORKER","Initializing database manager..."),await this.dbManager.initialize();try{g.info("WORKER","Running startup GC for pending messages...");let{PendingMessageStore:h}=await Promise.resolve().then(()=>(W0(),GA)),y=new h(this.dbManager.getSessionStore().db,3).clearFailedOlderThan(10080*60*1e3);y>0&&g.info("QUEUE","Startup GC cleared old failed pending_messages rows",{cleared:y})}catch(h){g.warn("QUEUE","Startup GC for failed pending_messages rows failed",{},h instanceof Error?h:void 0)}Uq(),g.info("WORKER","Initializing search services...");let a=new Jx,c=new Xx,u=new Yx(this.dbManager.getSessionSearch(),this.dbManager.getSessionStore(),this.dbManager.getChromaSync(),a,c);this.searchRoutes=new jE(u),this.server.registerRoutes(this.searchRoutes),g.info("WORKER","SearchManager initialized and search routes registered");let{SearchOrchestrator:l}=await Promise.resolve().then(()=>(gD(),kX)),d=new l(this.dbManager.getSessionSearch(),this.dbManager.getSessionStore(),this.dbManager.getChromaSync()),p=new VE(this.dbManager.getSessionStore(),d,this.corpusStore),m=new KE(this.corpusStore);this.server.registerRoutes(new HE(this.corpusStore,p,m)),g.info("WORKER","CorpusRoutes registered"),this.initializationCompleteFlag=!0,this.resolveInitialization(),g.info("SYSTEM","Core initialization complete (DB + search ready)"),await this.startTranscriptWatcher(n),this.chromaMcpManager&&Fa.backfillAllProjects(this.dbManager.getSessionStore()).then(()=>{g.info("CHROMA_SYNC","Backfill check complete for all projects")}).catch(h=>{g.error("CHROMA_SYNC","Backfill failed (non-blocking)",{},h)});let f=Ote.default.join(__dirname,"mcp-server.cjs");this.mcpReady=(0,gj.existsSync)(f),this.runMcpSelfCheck(f).catch(h=>{g.debug("WORKER","MCP self-check failed (non-fatal)",{error:h.message})});return}catch(e){g.error("SYSTEM","Background initialization failed",{},e instanceof Error?e:void 0)}}async runMcpSelfCheck(e){try{Xr().assertCanSpawn("mcp server");let r=new Xl({command:process.execPath,args:[e],env:Object.fromEntries(Object.entries(pi(process.env)).filter(([,o])=>o!==void 0))}),i=6e4,n=this.mcpClient.connect(r),s=new Promise((o,a)=>{setTimeout(()=>a(new Error("MCP connection timeout")),6e4)});await Promise.race([n,s]),g.info("WORKER","MCP loopback self-check connected successfully"),await r.close()}catch(r){g.warn("WORKER","MCP loopback self-check failed",{error:r instanceof Error?r.message:String(r)})}}async startTranscriptWatcher(e){if(!(e.CLAUDE_MEM_TRANSCRIPTS_ENABLED!=="false")){g.info("TRANSCRIPT","Transcript watcher disabled via CLAUDE_MEM_TRANSCRIPTS_ENABLED=false");return}let i=e.CLAUDE_MEM_TRANSCRIPTS_CONFIG_PATH||rE,n=ra(i);(0,gj.existsSync)(n)||(IX(i),g.info("TRANSCRIPT","Created default transcript watch config",{configPath:n}));let s=TX(i),o=ra(s.stateFile??nE);try{this.transcriptWatcher=new TE(s,o),await this.transcriptWatcher.start()}catch(a){this.transcriptWatcher?.stop(),this.transcriptWatcher=null,a instanceof Error?g.error("WORKER","Failed to start transcript watcher (continuing without Codex ingestion)",{configPath:n},a):g.error("WORKER","Failed to start transcript watcher with non-Error (continuing without Codex ingestion)",{configPath:n},new Error(String(a)));return}g.info("TRANSCRIPT","Transcript watcher started",{configPath:n,statePath:o,watches:s.watches.length})}getActiveAgent(){return yp()&&Tu()?this.openRouterAgent:vp()&&ku()?this.geminiAgent:this.sdkAgent}startSessionProcessor(e,r){if(!e)return;let i=e.sessionDbId,n=this.getActiveAgent(),s=n.constructor.name;e.abortController.signal.aborted&&(g.debug("SYSTEM","Replacing aborted AbortController before starting generator",{sessionId:e.sessionDbId}),e.abortController=new AbortController);let o=!1,a=!1;g.info("SYSTEM",`Starting generator (${r}) using ${s}`,{sessionId:i}),e.lastGeneratorActivity=Date.now(),e.generatorPromise=n.startSession(e,this).catch(async c=>{let u=c?.message||"";if(["Claude executable not found","CLAUDE_CODE_PATH","ENOENT","spawn","Invalid API key","API_KEY_INVALID","API key expired","API key not valid","PERMISSION_DENIED","Gemini API error: 400","Gemini API error: 401","Gemini API error: 403","FOREIGN KEY constraint failed"].some(p=>u.includes(p))){o=!0,this.lastAiInteraction={timestamp:Date.now(),success:!1,provider:s,error:u},g.error("SDK","Unrecoverable generator error - will NOT restart",{sessionId:e.sessionDbId,project:e.project,errorMessage:u});return}if(this.isSessionTerminatedError(c))return g.warn("SDK","SDK resume failed, falling back to standalone processing",{sessionId:e.sessionDbId,project:e.project,reason:c instanceof Error?c.message:String(c)}),this.runFallbackForTerminatedSession(e,c);throw["aborted by user","No conversation found"].some(p=>u.includes(p))&&e.memorySessionId&&(g.warn("SDK","Detected stale resume failure, clearing memorySessionId for fresh start",{sessionId:e.sessionDbId,memorySessionId:e.memorySessionId,errorMessage:u}),this.dbManager.getSessionStore().updateMemorySessionId(e.sessionDbId,null),e.memorySessionId=null,e.forceInit=!0),g.error("SDK","Session generator failed",{sessionId:e.sessionDbId,project:e.project,provider:s},c),a=!0,this.lastAiInteraction={timestamp:Date.now(),success:!1,provider:s,error:u},c}).finally(async()=>{let c=ja(e.sessionDbId);if(c&&c.process.exitCode===null&&await za(c,5e3),e.generatorPromise=null,!a&&!o&&(this.lastAiInteraction={timestamp:Date.now(),success:!0,provider:s}),o){this.terminateSession(e.sessionDbId,"unrecoverable_error");return}let l=this.sessionManager.getPendingMessageStore().getPendingCount(e.sessionDbId);if(e.idleTimedOut&&(e.idleTimedOut=!1,l===0)){this.terminateSession(e.sessionDbId,"idle_timeout");return}if(l>0){e.restartGuard||(e.restartGuard=new Wa);let d=e.restartGuard.recordRestart();if(e.consecutiveRestarts=(e.consecutiveRestarts||0)+1,!d){g.error("SYSTEM","Restart guard tripped: session is dead, terminating",{sessionId:e.sessionDbId,pendingCount:l,restartsInWindow:e.restartGuard.restartsInWindow,windowMs:e.restartGuard.windowMs,maxRestarts:e.restartGuard.maxRestarts,consecutiveFailures:e.restartGuard.consecutiveFailuresSinceSuccess,maxConsecutiveFailures:e.restartGuard.maxConsecutiveFailures}),e.consecutiveRestarts=0,this.terminateSession(e.sessionDbId,"max_restarts_exceeded");return}g.info("SYSTEM","Pending work remains after generator exit, restarting with fresh AbortController",{sessionId:e.sessionDbId,pendingCount:l,attempt:e.consecutiveRestarts}),e.abortController=new AbortController,this.startSessionProcessor(e,"pending-work-restart"),this.broadcastProcessingStatus()}else e.restartGuard?.recordSuccess(),e.consecutiveRestarts=0,this.completionHandler.finalizeSession(e.sessionDbId),this.sessionManager.removeSessionImmediate(e.sessionDbId)})}static SESSION_TERMINATED_PATTERNS=["process aborted by user","processtransport","not ready for writing","session generator failed","claude code process"];isSessionTerminatedError(e){let i=(e instanceof Error?e.message:String(e)).toLowerCase();return t.SESSION_TERMINATED_PATTERNS.some(n=>i.includes(n))}async runFallbackForTerminatedSession(e,r){if(!e)return;let i=e.sessionDbId;if(!e.memorySessionId){let n=`fallback-${i}-${Date.now()}`;e.memorySessionId=n,this.dbManager.getSessionStore().updateMemorySessionId(i,n)}if(ku())try{await this.geminiAgent.startSession(e,this);return}catch(n){n instanceof Error?(g.warn("WORKER","Fallback Gemini failed, trying OpenRouter",{sessionId:i}),g.error("WORKER","Gemini fallback error detail",{sessionId:i},n)):g.error("WORKER","Gemini fallback failed with non-Error",{sessionId:i},new Error(String(n)))}if(Tu())try{await this.openRouterAgent.startSession(e,this);return}catch(n){n instanceof Error?g.error("WORKER","Fallback OpenRouter failed, will abandon messages",{sessionId:i},n):g.error("WORKER","Fallback OpenRouter failed with non-Error, will abandon messages",{sessionId:i},new Error(String(n)))}this.completionHandler.finalizeSession(i),this.sessionManager.removeSessionImmediate(i)}terminateSession(e,r){g.info("SYSTEM","Session terminated",{sessionId:e,reason:r}),this.completionHandler.finalizeSession(e),this.sessionManager.removeSessionImmediate(e)}async processPendingQueues(e=10){let{PendingMessageStore:r}=await Promise.resolve().then(()=>(W0(),GA)),i=new r(this.dbManager.getSessionStore().db,3),n=this.dbManager.getSessionStore(),s=360*60*1e3,o=Date.now()-s,a=n.db.prepare(` SELECT id FROM sdk_sessions WHERE status = 'active' AND started_at_epoch < ? `).all(o);if(a.length>0){let l=a.map(m=>m.id),d=l.map(()=>"?").join(","),p=Date.now();try{n.db.prepare(`