diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 800705de..a3428e67 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -10,7 +10,7 @@ "plugins": [ { "name": "claude-mem", - "version": "12.3.2", + "version": "12.3.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 1ffd1ad1..7fad8328 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "claude-mem", - "version": "12.3.2", + "version": "12.3.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 712d02ef..248a1dcf 100644 --- a/.codex-plugin/plugin.json +++ b/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "claude-mem", - "version": "12.3.2", + "version": "12.3.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 aa234c44..25a40dc6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "claude-mem", - "version": "12.3.2", + "version": "12.3.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 2368ed91..e57e51d8 100644 --- a/plugin/.claude-plugin/plugin.json +++ b/plugin/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "claude-mem", - "version": "12.3.2", + "version": "12.3.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 d2970a35..83b587fb 100644 --- a/plugin/package.json +++ b/plugin/package.json @@ -1,6 +1,6 @@ { "name": "claude-mem-plugin", - "version": "12.3.2", + "version": "12.3.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 6346598d..6b0e85e6 100755 --- a/plugin/scripts/mcp-server.cjs +++ b/plugin/scripts/mcp-server.cjs @@ -194,7 +194,7 @@ ${f}`}let s=i.lineStart;for(let u=i.lineStart-1;u>=0;u--){let l=a[u].trim();if(l ${c}`}var db=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"]),oj=new Set(["node_modules",".git","dist","build",".next","__pycache__",".venv","venv","env",".env","target","vendor",".cache",".turbo","coverage",".nyc_output",".claude",".smart-file-read"]),ij=512*1024;async function*pb(t,e,r=20,n){if(r<=0)return;let o;try{o=await(0,Un.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!=="."||oj.has(i.name))continue;let a=(0,Mi.join)(t,i.name);if(i.isDirectory())yield*pb(a,e,r-1,n);else if(i.isFile()){let s=i.name.slice(i.name.lastIndexOf("."));(db.has(s)||n&&n.has(s))&&(yield a)}}}async function aj(t){try{let e=await(0,Un.stat)(t);if(e.size>ij||e.size===0)return null;let r=await(0,Un.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 fb(t,e,r={}){let n=r.maxResults||20,o=e.toLowerCase(),i=o.split(/[\s_\-./]+/).filter(S=>S.length>0),a=r.projectRoot||t,s=Ni(a),c=new Set;for(let S of Object.values(s.grammars))for(let x of S.extensions)db.has(x)||c.add(x);let u=[];for await(let S of pb(t,t,20,c.size>0?c:void 0)){if(r.filePattern&&!(0,Mi.relative)(t,S).toLowerCase().includes(r.filePattern.toLowerCase()))continue;let x=await aj(S);x&&u.push({absolutePath:S,relativePath:(0,Mi.relative)(t,S),content:x})}let l=cb(u,a),d=[],p=[],f=0;for(let[S,x]of l){f+=sj(x);let T=tc(S.toLowerCase(),i)>0,Ve=[],We=(Ln,qr)=>{for(let ye of Ln){let rr=0,mt="",Fn=tc(ye.name.toLowerCase(),i);Fn>0&&(rr+=Fn*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&&(T=!0,Ve.push({filePath:S,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(x.symbols),T&&(d.push(x),p.push(...Ve))}p.sort((S,x)=>{let N=tc(S.symbolName.toLowerCase(),i);return tc(x.symbolName.toLowerCase(),i)-N});let h=p.slice(0,n),g=new Set(h.map(S=>S.filePath)),$=d.filter(S=>g.has(S.filePath)).slice(0,n),k=$.reduce((S,x)=>S+x.foldedTokenEstimate,0);return{foldedFiles:$,matchingSymbols:h,totalFilesScanned:u.length,totalSymbolsFound:f,tokenEstimate:k}}function tc(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 sj(t){let e=t.symbols.length;for(let r of t.symbols)r.children&&(e+=r.children.length);return e}function mb(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(Cn(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 hm=require("node:fs/promises"),vb=require("node:fs"),Fr=require("node:path"),_b=require("node:url"),_j={},cj="12.3.2";console.log=(...t)=>{_.error("CONSOLE","Intercepted console output (MCP protocol protection)",void 0,{args:t})};var yb=!1,$b=(()=>{if(typeof __dirname<"u")return __dirname;try{return(0,Fr.dirname)((0,_b.fileURLToPath)(_j.url))}catch{return yb=!0,process.cwd()}})(),gm=(0,Fr.resolve)($b,"worker-service.cjs");function uj(){yb&&((0,vb.existsSync)(gm)||_.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:gm,mcpServerDir:$b}))}var hb={search:"/api/search",timeline:"/api/timeline"};async function mm(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 Bs(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 lj(t,e){let r=await Bs(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 Zn(t,e){_.debug("HTTP","Worker API request (POST)",void 0,{endpoint:t});try{return await lj(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 dj(){try{return(await Bs("/api/health")).ok}catch(t){return _.debug("SYSTEM","Worker health check failed",{},t instanceof Error?t:new Error(String(t))),!1}}async function pj(){if(await dj())return!0;_.warn("SYSTEM","Worker not available, attempting auto-start for MCP client"),uj();try{let t=Yf(),e=await Y$(t,gm);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 bb=[{name:"__IMPORTANT",description:`3-LAYER WORKFLOW (ALWAYS FOLLOW): +`)}var hm=require("node:fs/promises"),vb=require("node:fs"),Fr=require("node:path"),_b=require("node:url"),_j={},cj="12.3.4";console.log=(...t)=>{_.error("CONSOLE","Intercepted console output (MCP protocol protection)",void 0,{args:t})};var yb=!1,$b=(()=>{if(typeof __dirname<"u")return __dirname;try{return(0,Fr.dirname)((0,_b.fileURLToPath)(_j.url))}catch{return yb=!0,process.cwd()}})(),gm=(0,Fr.resolve)($b,"worker-service.cjs");function uj(){yb&&((0,vb.existsSync)(gm)||_.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:gm,mcpServerDir:$b}))}var hb={search:"/api/search",timeline:"/api/timeline"};async function mm(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 Bs(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 lj(t,e){let r=await Bs(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 Zn(t,e){_.debug("HTTP","Worker API request (POST)",void 0,{endpoint:t});try{return await lj(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 dj(){try{return(await Bs("/api/health")).ok}catch(t){return _.debug("SYSTEM","Worker health check failed",{},t instanceof Error?t:new Error(String(t))),!1}}async function pj(){if(await dj())return!0;_.warn("SYSTEM","Worker not available, attempting auto-start for MCP client"),uj();try{let t=Yf(),e=await Y$(t,gm);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 bb=[{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 1e1c51cd..917b81af 100755 --- a/plugin/scripts/worker-service.cjs +++ b/plugin/scripts/worker-service.cjs @@ -1082,7 +1082,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=BD(u);l&&i.add(l)}}finally{s?.close()}if(i.size===0)return h.debug("SYSTEM","Worktree adoption found no known parent repos"),n;for(let o of i)try{let a=await xk({repoPath:o,dataDirectory:e,dryRun:t.dryRun});n.push(a)}catch(a){h.warn("SYSTEM","Worktree adoption failed for parent repo (continuing)",{repoPath:o,error:a instanceof Error?a.message:String(a)})}return n}var s6=Ie(Fv(),1),I$=Ie(require("fs"),1),_u=Ie(require("path"),1);var WF=["search","context","summarize","import","export"],GF=["workflow","search_params","examples","all"];Y();var k$=Ie(Fv(),1),QF=Ie(XF(),1),e6=Ie(require("path"),1);$t();Y();function T$(t){let e=[];e.push(k$.default.json({limit:"50mb"})),e.push((0,QF.default)({origin:(i,s)=>{!i||i.startsWith("http://localhost:")||i.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","Authorization","X-Requested-With"],credentials:!1})),e.push((i,s,o)=>{let c=[".html",".js",".css",".svg",".png",".jpg",".jpeg",".webp",".woff",".woff2",".ttf",".eot"].some(m=>i.path.endsWith(m)),u=i.path==="/api/logs";if(i.path.startsWith("/health")||i.path==="/"||c||u)return o();let l=Date.now(),d=`${i.method}-${Date.now()}`,p=t(i.method,i.path,i.body);h.debug("HTTP",`\u2192 ${i.method} ${i.path}`,{requestId:d},p);let f=s.send.bind(s);s.send=function(m){let g=Date.now()-l;return h.debug("HTTP",`\u2190 ${s.statusCode} ${i.path}`,{requestId:d,duration:`${g}ms`}),f(m)},o()});let r=_n(),n=e6.default.join(r,"plugin","ui");return e.push(k$.default.static(n)),e}function Zp(t,e,r){let n=t.ip||t.connection.remoteAddress||"";if(!(n==="127.0.0.1"||n==="::1"||n==="::ffff:127.0.0.1"||n==="localhost")){h.warn("SECURITY","Admin endpoint access denied - not localhost",{endpoint:t.path,clientIp:n,method:t.method}),e.status(403).json({error:"Forbidden",message:"Admin endpoints are only accessible from localhost"});return}r()}function $$(t,e,r){if(!r||Object.keys(r).length===0||e.includes("/init"))return"";if(e.includes("/observations")){let n=r.tool_name||"?",i=r.tool_input;return`tool=${h.formatTool(n,i)}`}return e.includes("/summarize")?"requesting summary":""}Y();var En=class extends Error{constructor(r,n=500,i,s){super(r);this.statusCode=n;this.code=i;this.details=s;this.name="AppError"}};function t6(t,e,r,n){let i={error:t,message:e};return r&&(i.code=r),n&&(i.details=n),i}var r6=(t,e,r,n)=>{let i=t instanceof En?t.statusCode:500;h.error("HTTP",`Error handling ${e.method} ${e.path}`,{statusCode:i,error:t.message,code:t instanceof En?t.code:void 0},t);let s=t6(t.name||"Error",t.message,t instanceof En?t.code:void 0,t instanceof En?t.details:void 0);r.status(i).json(s)};function n6(t,e){e.status(404).json(t6("NotFound",`Cannot ${t.method} ${t.path}`))}var i6="12.3.2",qv=class{app;server=null;options;startTime=Date.now();constructor(e){this.options=e,this.app=(0,s6.default)(),this.setupMiddleware(),this.setupCoreRoutes()}getHttpServer(){return this.server}async listen(e,r){return new Promise((n,i)=>{this.server=this.app.listen(e,r,()=>{h.info("SYSTEM","HTTP server started",{host:r,port:e,pid:process.pid}),n()}),this.server.on("error",i)})}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(n=>n?r(n):e())}),process.platform==="win32"&&await new Promise(e=>setTimeout(e,500)),this.server=null,h.info("SYSTEM","HTTP server closed"))}registerRoutes(e){e.setupRoutes(this.app)}finalizeRoutes(){this.app.use(n6),this.app.use(r6)}setupMiddleware(){T$($$).forEach(r=>this.app.use(r))}setupCoreRoutes(){this.app.get("/api/health",(e,r)=>{r.status(200).json({status:"ok",version:i6,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:i6})}),this.app.get("/api/instructions",async(e,r)=>{let n=e.query.topic||"all",i=e.query.operation;if(n&&!GF.includes(n))return r.status(400).json({error:"Invalid topic"});if(i&&!WF.includes(i))return r.status(400).json({error:"Invalid operation"});if(i){let s=_u.default.resolve(__dirname,"../skills/mem-search/operations");if(!_u.default.resolve(s,`${i}.md`).startsWith(s+_u.default.sep))return r.status(400).json({error:"Invalid request"})}try{let s=await this.loadInstructionContent(i,n);r.json({content:[{type:"text",text:s}]})}catch(s){s instanceof Error?h.debug("HTTP","Instruction file not found",{topic:n,operation:i,message:s.message}):h.debug("HTTP","Instruction file not found",{topic:n,operation:i,error:String(s)}),r.status(404).json({error:"Instruction not found"})}}),this.app.post("/api/admin/restart",Zp,async(e,r)=>{r.json({status:"restarting"}),process.platform==="win32"&&process.env.CLAUDE_MEM_MANAGED==="true"&&process.send?(h.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",Zp,async(e,r)=>{r.json({status:"shutting_down"}),process.platform==="win32"&&process.env.CLAUDE_MEM_MANAGED==="true"&&process.send?(h.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",Zp,(e,r)=>{let o=bt().getRegistry().getAll().map(m=>({id:m.id,pid:m.pid,type:m.type,status:Mn(m.pid)?"alive":"dead",startedAt:m.startedAt})),a=o.filter(m=>m.status==="dead").map(m=>m.pid),c=!Object.keys(process.env).some(m=>ek.has(m)||Q0.some(g=>m.startsWith(g))),u=Date.now()-this.startTime,l=Math.floor(u/1e3),d=Math.floor(l/3600),p=Math.floor(l%3600/60),f=d>0?`${d}h ${p}m`:`${p}m`;r.json({supervisor:{running:!0,pid:process.pid,uptime:f},processes:o,health:{deadProcessPids:a,envClean:c}})})}async loadInstructionContent(e,r){if(e){let s=_u.default.resolve(__dirname,"../skills/mem-search/operations",`${e}.md`);return I$.promises.readFile(s,"utf-8")}let n=_u.default.join(__dirname,"../skills/mem-search/SKILL.md"),i=await I$.promises.readFile(n,"utf-8");return this.extractInstructionSection(i,r)}extractInstructionSection(e,r){let n={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 n[r]||n.all}extractBetween(e,r,n){let i=e.indexOf(r),s=e.indexOf(n);return i===-1?e:s===-1?e.substring(i):e.substring(i,s).trim()}};var Pt=Ie(require("path"),1),Wp=require("os"),Jt=require("fs"),c6=require("child_process"),u6=require("util");Y();Or();$t();var ii=require("fs"),Bp=require("path");Y();function o6(t){try{return(0,ii.existsSync)(t)?JSON.parse((0,ii.readFileSync)(t,"utf-8")):{}}catch(e){return h.error("CONFIG","Failed to read Cursor registry, using empty registry",{file:t,error:e instanceof Error?e.message:String(e)}),{}}}function a6(t,e){let r=(0,Bp.join)(t,"..");(0,ii.mkdirSync)(r,{recursive:!0}),(0,ii.writeFileSync)(t,JSON.stringify(e,null,2))}function R$(t,e){let r=(0,Bp.join)(t,".cursor","rules"),n=(0,Bp.join)(r,"claude-mem-context.mdc"),i=`${n}.tmp`;(0,ii.mkdirSync)(r,{recursive:!0});let s=`--- + `).all();for(let{cwd:u}of c){let l=BD(u);l&&i.add(l)}}finally{s?.close()}if(i.size===0)return h.debug("SYSTEM","Worktree adoption found no known parent repos"),n;for(let o of i)try{let a=await xk({repoPath:o,dataDirectory:e,dryRun:t.dryRun});n.push(a)}catch(a){h.warn("SYSTEM","Worktree adoption failed for parent repo (continuing)",{repoPath:o,error:a instanceof Error?a.message:String(a)})}return n}var s6=Ie(Fv(),1),I$=Ie(require("fs"),1),_u=Ie(require("path"),1);var WF=["search","context","summarize","import","export"],GF=["workflow","search_params","examples","all"];Y();var k$=Ie(Fv(),1),QF=Ie(XF(),1),e6=Ie(require("path"),1);$t();Y();function T$(t){let e=[];e.push(k$.default.json({limit:"50mb"})),e.push((0,QF.default)({origin:(i,s)=>{!i||i.startsWith("http://localhost:")||i.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","Authorization","X-Requested-With"],credentials:!1})),e.push((i,s,o)=>{let c=[".html",".js",".css",".svg",".png",".jpg",".jpeg",".webp",".woff",".woff2",".ttf",".eot"].some(m=>i.path.endsWith(m)),u=i.path==="/api/logs";if(i.path.startsWith("/health")||i.path==="/"||c||u)return o();let l=Date.now(),d=`${i.method}-${Date.now()}`,p=t(i.method,i.path,i.body);h.debug("HTTP",`\u2192 ${i.method} ${i.path}`,{requestId:d},p);let f=s.send.bind(s);s.send=function(m){let g=Date.now()-l;return h.debug("HTTP",`\u2190 ${s.statusCode} ${i.path}`,{requestId:d,duration:`${g}ms`}),f(m)},o()});let r=_n(),n=e6.default.join(r,"plugin","ui");return e.push(k$.default.static(n)),e}function Zp(t,e,r){let n=t.ip||t.connection.remoteAddress||"";if(!(n==="127.0.0.1"||n==="::1"||n==="::ffff:127.0.0.1"||n==="localhost")){h.warn("SECURITY","Admin endpoint access denied - not localhost",{endpoint:t.path,clientIp:n,method:t.method}),e.status(403).json({error:"Forbidden",message:"Admin endpoints are only accessible from localhost"});return}r()}function $$(t,e,r){if(!r||Object.keys(r).length===0||e.includes("/init"))return"";if(e.includes("/observations")){let n=r.tool_name||"?",i=r.tool_input;return`tool=${h.formatTool(n,i)}`}return e.includes("/summarize")?"requesting summary":""}Y();var En=class extends Error{constructor(r,n=500,i,s){super(r);this.statusCode=n;this.code=i;this.details=s;this.name="AppError"}};function t6(t,e,r,n){let i={error:t,message:e};return r&&(i.code=r),n&&(i.details=n),i}var r6=(t,e,r,n)=>{let i=t instanceof En?t.statusCode:500;h.error("HTTP",`Error handling ${e.method} ${e.path}`,{statusCode:i,error:t.message,code:t instanceof En?t.code:void 0},t);let s=t6(t.name||"Error",t.message,t instanceof En?t.code:void 0,t instanceof En?t.details:void 0);r.status(i).json(s)};function n6(t,e){e.status(404).json(t6("NotFound",`Cannot ${t.method} ${t.path}`))}var i6="12.3.4",qv=class{app;server=null;options;startTime=Date.now();constructor(e){this.options=e,this.app=(0,s6.default)(),this.setupMiddleware(),this.setupCoreRoutes()}getHttpServer(){return this.server}async listen(e,r){return new Promise((n,i)=>{this.server=this.app.listen(e,r,()=>{h.info("SYSTEM","HTTP server started",{host:r,port:e,pid:process.pid}),n()}),this.server.on("error",i)})}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(n=>n?r(n):e())}),process.platform==="win32"&&await new Promise(e=>setTimeout(e,500)),this.server=null,h.info("SYSTEM","HTTP server closed"))}registerRoutes(e){e.setupRoutes(this.app)}finalizeRoutes(){this.app.use(n6),this.app.use(r6)}setupMiddleware(){T$($$).forEach(r=>this.app.use(r))}setupCoreRoutes(){this.app.get("/api/health",(e,r)=>{r.status(200).json({status:"ok",version:i6,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:i6})}),this.app.get("/api/instructions",async(e,r)=>{let n=e.query.topic||"all",i=e.query.operation;if(n&&!GF.includes(n))return r.status(400).json({error:"Invalid topic"});if(i&&!WF.includes(i))return r.status(400).json({error:"Invalid operation"});if(i){let s=_u.default.resolve(__dirname,"../skills/mem-search/operations");if(!_u.default.resolve(s,`${i}.md`).startsWith(s+_u.default.sep))return r.status(400).json({error:"Invalid request"})}try{let s=await this.loadInstructionContent(i,n);r.json({content:[{type:"text",text:s}]})}catch(s){s instanceof Error?h.debug("HTTP","Instruction file not found",{topic:n,operation:i,message:s.message}):h.debug("HTTP","Instruction file not found",{topic:n,operation:i,error:String(s)}),r.status(404).json({error:"Instruction not found"})}}),this.app.post("/api/admin/restart",Zp,async(e,r)=>{r.json({status:"restarting"}),process.platform==="win32"&&process.env.CLAUDE_MEM_MANAGED==="true"&&process.send?(h.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",Zp,async(e,r)=>{r.json({status:"shutting_down"}),process.platform==="win32"&&process.env.CLAUDE_MEM_MANAGED==="true"&&process.send?(h.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",Zp,(e,r)=>{let o=bt().getRegistry().getAll().map(m=>({id:m.id,pid:m.pid,type:m.type,status:Mn(m.pid)?"alive":"dead",startedAt:m.startedAt})),a=o.filter(m=>m.status==="dead").map(m=>m.pid),c=!Object.keys(process.env).some(m=>ek.has(m)||Q0.some(g=>m.startsWith(g))),u=Date.now()-this.startTime,l=Math.floor(u/1e3),d=Math.floor(l/3600),p=Math.floor(l%3600/60),f=d>0?`${d}h ${p}m`:`${p}m`;r.json({supervisor:{running:!0,pid:process.pid,uptime:f},processes:o,health:{deadProcessPids:a,envClean:c}})})}async loadInstructionContent(e,r){if(e){let s=_u.default.resolve(__dirname,"../skills/mem-search/operations",`${e}.md`);return I$.promises.readFile(s,"utf-8")}let n=_u.default.join(__dirname,"../skills/mem-search/SKILL.md"),i=await I$.promises.readFile(n,"utf-8");return this.extractInstructionSection(i,r)}extractInstructionSection(e,r){let n={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 n[r]||n.all}extractBetween(e,r,n){let i=e.indexOf(r),s=e.indexOf(n);return i===-1?e:s===-1?e.substring(i):e.substring(i,s).trim()}};var Pt=Ie(require("path"),1),Wp=require("os"),Jt=require("fs"),c6=require("child_process"),u6=require("util");Y();Or();$t();var ii=require("fs"),Bp=require("path");Y();function o6(t){try{return(0,ii.existsSync)(t)?JSON.parse((0,ii.readFileSync)(t,"utf-8")):{}}catch(e){return h.error("CONFIG","Failed to read Cursor registry, using empty registry",{file:t,error:e instanceof Error?e.message:String(e)}),{}}}function a6(t,e){let r=(0,Bp.join)(t,"..");(0,ii.mkdirSync)(r,{recursive:!0}),(0,ii.writeFileSync)(t,JSON.stringify(e,null,2))}function R$(t,e){let r=(0,Bp.join)(t,".cursor","rules"),n=(0,Bp.join)(r,"claude-mem-context.mdc"),i=`${n}.tmp`;(0,ii.mkdirSync)(r,{recursive:!0});let s=`--- alwaysApply: true description: "Claude-mem context from past sessions (auto-updated)" --- @@ -1707,7 +1707,7 @@ ${e}`,o=z$(i,s),a=`${t}.tmp`;try{(0,Ui.writeFileSync)(a,o),(0,Ui.renameSync)(a,t `);ir(Xi);let i=this.findClaudeExecutable(),s=Nn(sp()),o=Tf({prompt:n,options:{model:this.getModelId(),cwd:Xi,disallowedTools:I5,pathToClaudeCodeExecutable:i,env:s}}),a;try{for await(let c of o)c.session_id&&(a=c.session_id),c.type==="result"&&h.info("WORKER",`Knowledge agent primed for corpus "${e.name}"`)}catch(c){if(a)c instanceof Error?h.debug("WORKER",`SDK process exited after priming corpus "${e.name}" \u2014 session captured, continuing`,{},c):h.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 n=await this.executeQuery(e,r);return n.session_id!==e.session_id&&(e.session_id=n.session_id,this.corpusStore.write(e)),n}catch(n){if(!this.isSessionResumeError(n))throw n instanceof Error?h.error("WORKER",`Query failed for corpus "${e.name}"`,{},n):h.error("WORKER",`Query failed for corpus "${e.name}" (non-Error thrown)`,{thrownValue:String(n)}),n;h.info("WORKER",`Session expired for corpus "${e.name}", auto-repriming...`),await this.prime(e);let i=this.corpusStore.read(e.name);if(!i||!i.session_id)throw new Error(`Auto-reprime failed for corpus "${e.name}"`);let s=await this.executeQuery(i,r);return s.session_id!==i.session_id&&(i.session_id=s.session_id,this.corpusStore.write(i)),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){ir(Xi);let n=this.findClaudeExecutable(),i=Nn(sp()),s=Tf({prompt:r,options:{model:this.getModelId(),resume:e.session_id,cwd:Xi,disallowedTools:I5,pathToClaudeCodeExecutable:n,env:i}}),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?h.debug("WORKER","SDK process exited after query \u2014 answer captured, continuing",{},c):h.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 ge.loadFromFile(pt).CLAUDE_MEM_MODEL}findClaudeExecutable(){let e=ge.loadFromFile(pt);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,TR.execSync)("where claude.cmd",{encoding:"utf8",windowsHide:!0,stdio:["ignore","pipe","ignore"]}),"claude.cmd"}catch{}try{let r=(0,TR.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?h.debug("WORKER","Claude executable auto-detection failed",{},r):h.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`)}};var $we={},wwe="12.3.2";function i3(t,e){return{continue:!0,suppressOutput:!0,status:t,...e&&{message:e}}}var z_=class t{server;startTime=Date.now();mcpClient;mcpReady=!1;initializationCompleteFlag=!1;isShuttingDown=!1;dbManager;sessionManager;sseBroadcaster;sdkAgent;geminiAgent;openRouterAgent;paginationHelper;settingsManager;sessionEventBroadcaster;corpusStore;searchRoutes=null;chromaMcpManager=null;transcriptWatcher=null;initializationComplete;resolveInitialization;stopOrphanReaper=null;staleSessionReaperInterval=null;lastAiInteraction=null;constructor(){this.initializationComplete=new Promise(e=>{this.resolveInitialization=e}),this.dbManager=new Wv,this.sessionManager=new Jv(this.dbManager),this.sseBroadcaster=new Yv,this.sdkAgent=new $y(this.dbManager,this.sessionManager),this.geminiAgent=new Iy(this.dbManager,this.sessionManager),this.openRouterAgent=new Cy(this.dbManager,this.sessionManager),this.paginationHelper=new Py(this.dbManager),this.settingsManager=new Ay(this.dbManager),this.sessionEventBroadcaster=new jy(this.sseBroadcaster,this),this.corpusStore=new A_,this.sessionManager.setOnSessionDeleted(()=>{this.broadcastProcessingStatus()}),this.mcpClient=new zc({name:"worker-search-proxy",version:wwe},{capabilities:{}}),this.server=new qv({getInitializationComplete:()=>this.initializationCompleteFlag,getMcpReady:()=>this.mcpReady,onShutdown:()=>this.shutdown(),onRestart:()=>this.shutdown(),workerPath:__filename,getAiStatus:()=>{let e="claude";return Ju()&&La()?e="openrouter":Ku()&&za()&&(e="gemini"),{provider:e,authMethod:vg(),lastInteraction:this.lastAiInteraction?{timestamp:this.lastAiInteraction.timestamp,success:this.lastAiInteraction.success,...this.lastAiInteraction.error&&{error:this.lastAiInteraction.error}}:null}}}),this.registerRoutes(),this.registerSignalHandlers()}registerSignalHandlers(){fD(async()=>{this.isShuttingDown=!0,await this.shutdown()})}registerRoutes(){this.server.app.get("/api/context/inject",async(e,r,n)=>{if(!this.initializationCompleteFlag||!this.searchRoutes){h.warn("SYSTEM","Context requested before initialization complete, returning empty"),r.status(200).json({content:[{type:"text",text:""}]});return}n()}),this.server.app.use("/api",async(e,r,n)=>{if(this.initializationCompleteFlag){n();return}let i=3e4,s=new Promise((o,a)=>setTimeout(()=>a(new Error("Database initialization timeout")),i));try{await Promise.race([this.initializationComplete,s]),n()}catch(o){o instanceof Error?h.error("WORKER",`Request to ${e.method} ${e.path} rejected \u2014 DB not initialized`,{},o):h.error("WORKER",`Request to ${e.method} ${e.path} rejected \u2014 DB not initialized with non-Error`,{},new Error(String(o))),r.status(503).json({error:"Service initializing",message:"Database is still initializing, please retry"});return}}),this.server.registerRoutes(new h_(this.sseBroadcaster,this.dbManager,this.sessionManager)),this.server.registerRoutes(new __(this.sessionManager,this.dbManager,this.sdkAgent,this.geminiAgent,this.openRouterAgent,this.sessionEventBroadcaster,this)),this.server.registerRoutes(new b_(this.paginationHelper,this.dbManager,this.sessionManager,this.sseBroadcaster,this,this.startTime)),this.server.registerRoutes(new I_(this.settingsManager)),this.server.registerRoutes(new O_),this.server.registerRoutes(new C_(this.dbManager,"claude-mem"))}async start(){let e=tn(),r=K0();await dD(),await this.server.listen(e,r),RD({pid:process.pid,port:e,startedAt:new Date().toISOString()}),bt().registerProcess("worker",{pid:process.pid,type:"worker",startedAt:new Date().toISOString()}),h.info("SYSTEM","Worker started",{host:r,port:e,pid:process.pid}),this.initializeBackground().catch(n=>{h.error("SYSTEM","Background initialization failed",{},n)})}async initializeBackground(){try{await OD();let{ModeManager:e}=await Promise.resolve().then(()=>(on(),O6)),{SettingsDefaultsManager:r}=await Promise.resolve().then(()=>(Xt(),qM)),{USER_SETTINGS_PATH:n}=await Promise.resolve().then(()=>($t(),KM)),i=r.loadFromFile(n);(i.CLAUDE_MEM_MODE==="local"||!i.CLAUDE_MEM_MODE)&&CD(),PD();let s=null;try{s=await WD({})}catch($){$ instanceof Error?h.error("WORKER","Worktree adoption failed (non-fatal)",{},$):h.error("WORKER","Worktree adoption failed (non-fatal) with non-Error",{},new Error(String($)))}if(s)for(let $ of s)($.adoptedObservations>0||$.adoptedSummaries>0||$.chromaUpdates>0)&&h.info("SYSTEM","Merged worktrees adopted on startup",$),$.errors.length>0&&h.warn("SYSTEM","Worktree adoption had per-branch errors",{repoPath:$.repoPath,errors:$.errors});i.CLAUDE_MEM_CHROMA_ENABLED!=="false"?(this.chromaMcpManager=Qi.getInstance(),h.info("SYSTEM","ChromaMcpManager initialized (lazy - connects on first use)")):h.info("SYSTEM","Chroma disabled via CLAUDE_MEM_CHROMA_ENABLED=false, skipping ChromaMcpManager");let a=i.CLAUDE_MEM_MODE;e.getInstance().loadMode(a),h.info("SYSTEM",`Mode loaded: ${a}`),await this.dbManager.initialize();let{PendingMessageStore:c}=await Promise.resolve().then(()=>(Oa(),Su)),l=new c(this.dbManager.getSessionStore().db,3).resetStaleProcessingMessages(0);l>0&&h.info("SYSTEM",`Reset ${l} stale processing messages to pending`);let d=new My,p=new Dy,f=new Ny(this.dbManager.getSessionSearch(),this.dbManager.getSessionStore(),this.dbManager.getChromaSync(),d,p);this.searchRoutes=new k_(f),this.server.registerRoutes(this.searchRoutes),h.info("WORKER","SearchManager initialized and search routes registered");let{SearchOrchestrator:m}=await Promise.resolve().then(()=>(zI(),g8)),g=new m(this.dbManager.getSessionSearch(),this.dbManager.getSessionStore(),this.dbManager.getChromaSync()),v=new M_(this.dbManager.getSessionStore(),g,this.corpusStore),y=new D_(this.corpusStore);this.server.registerRoutes(new P_(this.corpusStore,v,y)),h.info("WORKER","CorpusRoutes registered"),this.initializationCompleteFlag=!0,this.resolveInitialization(),h.info("SYSTEM","Core initialization complete (DB + search ready)"),await this.startTranscriptWatcher(i),this.chromaMcpManager&&bo.backfillAllProjects().then(()=>{h.info("CHROMA_SYNC","Backfill check complete for all projects")}).catch($=>{h.error("CHROMA_SYNC","Backfill failed (non-blocking)",{},$)});let b=n3.default.join(__dirname,"mcp-server.cjs");this.mcpReady=(0,LR.existsSync)(b),bt().assertCanSpawn("mcp server");let _=new Fc({command:"node",args:[b],env:Nn(process.env)}),S=3e5,x=this.mcpClient.connect(_),w,E=new Promise(($,O)=>{w=setTimeout(()=>O(new Error("MCP connection timeout after 5 minutes")),S)});try{await Promise.race([x,E])}catch($){clearTimeout(w),h.warn("WORKER","MCP loopback self-check failed, cleaning up subprocess",{error:$ instanceof Error?$.message:String($)});try{await _.close()}catch(O){h.debug("WORKER","transport.close() failed during MCP cleanup",{error:O instanceof Error?O.message:String(O)})}h.info("WORKER","Bundled MCP server remains available for external stdio clients",{path:b});return}clearTimeout(w);let k=_._process;k?.pid&&(bt().registerProcess("mcp-server",{pid:k.pid,type:"mcp",startedAt:new Date().toISOString()},k),k.once("exit",()=>{bt().unregisterProcess("mcp-server")})),h.success("WORKER","MCP loopback self-check connected"),this.stopOrphanReaper=$6(()=>{let $=new Set;for(let[O]of this.sessionManager.sessions)$.add(O);return $}),h.info("SYSTEM","Started orphan reaper (runs every 30 seconds)"),this.staleSessionReaperInterval=setInterval(async()=>{try{let $=await this.sessionManager.reapStaleSessions();$>0&&h.info("SYSTEM",`Reaped ${$} stale sessions`)}catch($){$ instanceof Error?h.error("WORKER","Stale session reaper error",{},$):h.error("WORKER","Stale session reaper error with non-Error",{},new Error(String($)))}try{let O=this.sessionManager.getPendingMessageStore().clearFailed();O>0&&h.info("SYSTEM",`Purged ${O} failed pending messages`)}catch($){$ instanceof Error?h.error("WORKER","Failed message purge error",{},$):h.error("WORKER","Failed message purge error with non-Error",{},new Error(String($)))}try{this.dbManager.getSessionStore().db.run("PRAGMA wal_checkpoint(PASSIVE)")}catch($){$ instanceof Error?h.error("WORKER","WAL checkpoint error",{},$):h.error("WORKER","WAL checkpoint error with non-Error",{},new Error(String($)))}},120*1e3),this.processPendingQueues(50).then($=>{$.sessionsStarted>0&&h.info("SYSTEM",`Auto-recovered ${$.sessionsStarted} sessions with pending work`,{totalPending:$.totalPendingSessions,started:$.sessionsStarted,sessionIds:$.startedSessionIds})}).catch($=>{h.error("SYSTEM","Auto-recovery of pending queues failed",{},$)})}catch(e){throw h.error("SYSTEM","Background initialization failed",{},e),e}}async startTranscriptWatcher(e){if(!(e.CLAUDE_MEM_TRANSCRIPTS_ENABLED!=="false")){h.info("TRANSCRIPT","Transcript watcher disabled via CLAUDE_MEM_TRANSCRIPTS_ENABLED=false");return}let n=e.CLAUDE_MEM_TRANSCRIPTS_CONFIG_PATH||Ly,i=Js(n);(0,LR.existsSync)(i)||(y8(n),h.info("TRANSCRIPT","Created default transcript watch config",{configPath:i}));let s=v8(n),o=Js(s.stateFile??Uy);try{this.transcriptWatcher=new f_(s,o),await this.transcriptWatcher.start()}catch(a){this.transcriptWatcher?.stop(),this.transcriptWatcher=null,a instanceof Error?h.error("WORKER","Failed to start transcript watcher (continuing without Codex ingestion)",{configPath:i},a):h.error("WORKER","Failed to start transcript watcher with non-Error (continuing without Codex ingestion)",{configPath:i},new Error(String(a)));return}h.info("TRANSCRIPT","Transcript watcher started",{configPath:i,statePath:o,watches:s.watches.length})}getActiveAgent(){return Ju()&&La()?this.openRouterAgent:Ku()&&za()?this.geminiAgent:this.sdkAgent}startSessionProcessor(e,r){if(!e)return;let n=e.sessionDbId,i=this.getActiveAgent(),s=i.constructor.name;e.abortController.signal.aborted&&(h.debug("SYSTEM","Replacing aborted AbortController before starting generator",{sessionId:e.sessionDbId}),e.abortController=new AbortController);let o=!1,a=!1;h.info("SYSTEM",`Starting generator (${r}) using ${s}`,{sessionId:n}),e.lastGeneratorActivity=Date.now(),e.generatorPromise=i.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},h.error("SDK","Unrecoverable generator error - will NOT restart",{sessionId:e.sessionDbId,project:e.project,errorMessage:u});return}if(this.isSessionTerminatedError(c))return h.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&&(h.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),h.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=us(e.sessionDbId);if(c&&c.process.exitCode===null&&await Co(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}let d=3;if(l>0){if(e.consecutiveRestarts=(e.consecutiveRestarts||0)+1,e.consecutiveRestarts>d){h.error("SYSTEM","Exceeded max pending-work restarts, stopping to prevent infinite loop",{sessionId:e.sessionDbId,pendingCount:l,consecutiveRestarts:e.consecutiveRestarts}),e.consecutiveRestarts=0,this.terminateSession(e.sessionDbId,"max_restarts_exceeded");return}h.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.consecutiveRestarts=0,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 n=(e instanceof Error?e.message:String(e)).toLowerCase();return t.SESSION_TERMINATED_PATTERNS.some(i=>n.includes(i))}async runFallbackForTerminatedSession(e,r){if(!e)return;let n=e.sessionDbId;if(!e.memorySessionId){let o=`fallback-${n}-${Date.now()}`;e.memorySessionId=o,this.dbManager.getSessionStore().updateMemorySessionId(n,o)}if(za())try{await this.geminiAgent.startSession(e,this);return}catch(o){o instanceof Error?(h.warn("WORKER","Fallback Gemini failed, trying OpenRouter",{sessionId:n}),h.error("WORKER","Gemini fallback error detail",{sessionId:n},o)):h.error("WORKER","Gemini fallback failed with non-Error",{sessionId:n},new Error(String(o)))}if(La())try{await this.openRouterAgent.startSession(e,this);return}catch(o){o instanceof Error?h.error("WORKER","Fallback OpenRouter failed, will abandon messages",{sessionId:n},o):h.error("WORKER","Fallback OpenRouter failed with non-Error, will abandon messages",{sessionId:n},new Error(String(o)))}let s=this.sessionManager.getPendingMessageStore().markAllSessionMessagesAbandoned(n);s>0&&h.warn("SDK","No fallback available; marked pending messages abandoned",{sessionId:n,abandoned:s}),this.sessionManager.removeSessionImmediate(n),this.sessionEventBroadcaster.broadcastSessionCompleted(n)}terminateSession(e,r){let i=this.sessionManager.getPendingMessageStore().markAllSessionMessagesAbandoned(e);h.info("SYSTEM","Session terminated",{sessionId:e,reason:r,abandonedMessages:i}),this.sessionManager.removeSessionImmediate(e)}async processPendingQueues(e=10){let{PendingMessageStore:r}=await Promise.resolve().then(()=>(Oa(),Su)),n=new r(this.dbManager.getSessionStore().db,3),i=this.dbManager.getSessionStore(),s=360*60*1e3,o=Date.now()-s,a=i.db.prepare(` +2. Set CLAUDE_CODE_PATH in ~/.claude-mem/settings.json`)}};var $we={},wwe="12.3.4";function i3(t,e){return{continue:!0,suppressOutput:!0,status:t,...e&&{message:e}}}var z_=class t{server;startTime=Date.now();mcpClient;mcpReady=!1;initializationCompleteFlag=!1;isShuttingDown=!1;dbManager;sessionManager;sseBroadcaster;sdkAgent;geminiAgent;openRouterAgent;paginationHelper;settingsManager;sessionEventBroadcaster;corpusStore;searchRoutes=null;chromaMcpManager=null;transcriptWatcher=null;initializationComplete;resolveInitialization;stopOrphanReaper=null;staleSessionReaperInterval=null;lastAiInteraction=null;constructor(){this.initializationComplete=new Promise(e=>{this.resolveInitialization=e}),this.dbManager=new Wv,this.sessionManager=new Jv(this.dbManager),this.sseBroadcaster=new Yv,this.sdkAgent=new $y(this.dbManager,this.sessionManager),this.geminiAgent=new Iy(this.dbManager,this.sessionManager),this.openRouterAgent=new Cy(this.dbManager,this.sessionManager),this.paginationHelper=new Py(this.dbManager),this.settingsManager=new Ay(this.dbManager),this.sessionEventBroadcaster=new jy(this.sseBroadcaster,this),this.corpusStore=new A_,this.sessionManager.setOnSessionDeleted(()=>{this.broadcastProcessingStatus()}),this.mcpClient=new zc({name:"worker-search-proxy",version:wwe},{capabilities:{}}),this.server=new qv({getInitializationComplete:()=>this.initializationCompleteFlag,getMcpReady:()=>this.mcpReady,onShutdown:()=>this.shutdown(),onRestart:()=>this.shutdown(),workerPath:__filename,getAiStatus:()=>{let e="claude";return Ju()&&La()?e="openrouter":Ku()&&za()&&(e="gemini"),{provider:e,authMethod:vg(),lastInteraction:this.lastAiInteraction?{timestamp:this.lastAiInteraction.timestamp,success:this.lastAiInteraction.success,...this.lastAiInteraction.error&&{error:this.lastAiInteraction.error}}:null}}}),this.registerRoutes(),this.registerSignalHandlers()}registerSignalHandlers(){fD(async()=>{this.isShuttingDown=!0,await this.shutdown()})}registerRoutes(){this.server.app.get("/api/context/inject",async(e,r,n)=>{if(!this.initializationCompleteFlag||!this.searchRoutes){h.warn("SYSTEM","Context requested before initialization complete, returning empty"),r.status(200).json({content:[{type:"text",text:""}]});return}n()}),this.server.app.use("/api",async(e,r,n)=>{if(this.initializationCompleteFlag){n();return}let i=3e4,s=new Promise((o,a)=>setTimeout(()=>a(new Error("Database initialization timeout")),i));try{await Promise.race([this.initializationComplete,s]),n()}catch(o){o instanceof Error?h.error("WORKER",`Request to ${e.method} ${e.path} rejected \u2014 DB not initialized`,{},o):h.error("WORKER",`Request to ${e.method} ${e.path} rejected \u2014 DB not initialized with non-Error`,{},new Error(String(o))),r.status(503).json({error:"Service initializing",message:"Database is still initializing, please retry"});return}}),this.server.registerRoutes(new h_(this.sseBroadcaster,this.dbManager,this.sessionManager)),this.server.registerRoutes(new __(this.sessionManager,this.dbManager,this.sdkAgent,this.geminiAgent,this.openRouterAgent,this.sessionEventBroadcaster,this)),this.server.registerRoutes(new b_(this.paginationHelper,this.dbManager,this.sessionManager,this.sseBroadcaster,this,this.startTime)),this.server.registerRoutes(new I_(this.settingsManager)),this.server.registerRoutes(new O_),this.server.registerRoutes(new C_(this.dbManager,"claude-mem"))}async start(){let e=tn(),r=K0();await dD(),await this.server.listen(e,r),RD({pid:process.pid,port:e,startedAt:new Date().toISOString()}),bt().registerProcess("worker",{pid:process.pid,type:"worker",startedAt:new Date().toISOString()}),h.info("SYSTEM","Worker started",{host:r,port:e,pid:process.pid}),this.initializeBackground().catch(n=>{h.error("SYSTEM","Background initialization failed",{},n)})}async initializeBackground(){try{await OD();let{ModeManager:e}=await Promise.resolve().then(()=>(on(),O6)),{SettingsDefaultsManager:r}=await Promise.resolve().then(()=>(Xt(),qM)),{USER_SETTINGS_PATH:n}=await Promise.resolve().then(()=>($t(),KM)),i=r.loadFromFile(n);(i.CLAUDE_MEM_MODE==="local"||!i.CLAUDE_MEM_MODE)&&CD(),PD();let s=null;try{s=await WD({})}catch($){$ instanceof Error?h.error("WORKER","Worktree adoption failed (non-fatal)",{},$):h.error("WORKER","Worktree adoption failed (non-fatal) with non-Error",{},new Error(String($)))}if(s)for(let $ of s)($.adoptedObservations>0||$.adoptedSummaries>0||$.chromaUpdates>0)&&h.info("SYSTEM","Merged worktrees adopted on startup",$),$.errors.length>0&&h.warn("SYSTEM","Worktree adoption had per-branch errors",{repoPath:$.repoPath,errors:$.errors});i.CLAUDE_MEM_CHROMA_ENABLED!=="false"?(this.chromaMcpManager=Qi.getInstance(),h.info("SYSTEM","ChromaMcpManager initialized (lazy - connects on first use)")):h.info("SYSTEM","Chroma disabled via CLAUDE_MEM_CHROMA_ENABLED=false, skipping ChromaMcpManager");let a=i.CLAUDE_MEM_MODE;e.getInstance().loadMode(a),h.info("SYSTEM",`Mode loaded: ${a}`),await this.dbManager.initialize();let{PendingMessageStore:c}=await Promise.resolve().then(()=>(Oa(),Su)),l=new c(this.dbManager.getSessionStore().db,3).resetStaleProcessingMessages(0);l>0&&h.info("SYSTEM",`Reset ${l} stale processing messages to pending`);let d=new My,p=new Dy,f=new Ny(this.dbManager.getSessionSearch(),this.dbManager.getSessionStore(),this.dbManager.getChromaSync(),d,p);this.searchRoutes=new k_(f),this.server.registerRoutes(this.searchRoutes),h.info("WORKER","SearchManager initialized and search routes registered");let{SearchOrchestrator:m}=await Promise.resolve().then(()=>(zI(),g8)),g=new m(this.dbManager.getSessionSearch(),this.dbManager.getSessionStore(),this.dbManager.getChromaSync()),v=new M_(this.dbManager.getSessionStore(),g,this.corpusStore),y=new D_(this.corpusStore);this.server.registerRoutes(new P_(this.corpusStore,v,y)),h.info("WORKER","CorpusRoutes registered"),this.initializationCompleteFlag=!0,this.resolveInitialization(),h.info("SYSTEM","Core initialization complete (DB + search ready)"),await this.startTranscriptWatcher(i),this.chromaMcpManager&&bo.backfillAllProjects().then(()=>{h.info("CHROMA_SYNC","Backfill check complete for all projects")}).catch($=>{h.error("CHROMA_SYNC","Backfill failed (non-blocking)",{},$)});let b=n3.default.join(__dirname,"mcp-server.cjs");this.mcpReady=(0,LR.existsSync)(b),bt().assertCanSpawn("mcp server");let _=new Fc({command:"node",args:[b],env:Nn(process.env)}),S=3e5,x=this.mcpClient.connect(_),w,E=new Promise(($,O)=>{w=setTimeout(()=>O(new Error("MCP connection timeout after 5 minutes")),S)});try{await Promise.race([x,E])}catch($){clearTimeout(w),h.warn("WORKER","MCP loopback self-check failed, cleaning up subprocess",{error:$ instanceof Error?$.message:String($)});try{await _.close()}catch(O){h.debug("WORKER","transport.close() failed during MCP cleanup",{error:O instanceof Error?O.message:String(O)})}h.info("WORKER","Bundled MCP server remains available for external stdio clients",{path:b});return}clearTimeout(w);let k=_._process;k?.pid&&(bt().registerProcess("mcp-server",{pid:k.pid,type:"mcp",startedAt:new Date().toISOString()},k),k.once("exit",()=>{bt().unregisterProcess("mcp-server")})),h.success("WORKER","MCP loopback self-check connected"),this.stopOrphanReaper=$6(()=>{let $=new Set;for(let[O]of this.sessionManager.sessions)$.add(O);return $}),h.info("SYSTEM","Started orphan reaper (runs every 30 seconds)"),this.staleSessionReaperInterval=setInterval(async()=>{try{let $=await this.sessionManager.reapStaleSessions();$>0&&h.info("SYSTEM",`Reaped ${$} stale sessions`)}catch($){$ instanceof Error?h.error("WORKER","Stale session reaper error",{},$):h.error("WORKER","Stale session reaper error with non-Error",{},new Error(String($)))}try{let O=this.sessionManager.getPendingMessageStore().clearFailed();O>0&&h.info("SYSTEM",`Purged ${O} failed pending messages`)}catch($){$ instanceof Error?h.error("WORKER","Failed message purge error",{},$):h.error("WORKER","Failed message purge error with non-Error",{},new Error(String($)))}try{this.dbManager.getSessionStore().db.run("PRAGMA wal_checkpoint(PASSIVE)")}catch($){$ instanceof Error?h.error("WORKER","WAL checkpoint error",{},$):h.error("WORKER","WAL checkpoint error with non-Error",{},new Error(String($)))}},120*1e3),this.processPendingQueues(50).then($=>{$.sessionsStarted>0&&h.info("SYSTEM",`Auto-recovered ${$.sessionsStarted} sessions with pending work`,{totalPending:$.totalPendingSessions,started:$.sessionsStarted,sessionIds:$.startedSessionIds})}).catch($=>{h.error("SYSTEM","Auto-recovery of pending queues failed",{},$)})}catch(e){throw h.error("SYSTEM","Background initialization failed",{},e),e}}async startTranscriptWatcher(e){if(!(e.CLAUDE_MEM_TRANSCRIPTS_ENABLED!=="false")){h.info("TRANSCRIPT","Transcript watcher disabled via CLAUDE_MEM_TRANSCRIPTS_ENABLED=false");return}let n=e.CLAUDE_MEM_TRANSCRIPTS_CONFIG_PATH||Ly,i=Js(n);(0,LR.existsSync)(i)||(y8(n),h.info("TRANSCRIPT","Created default transcript watch config",{configPath:i}));let s=v8(n),o=Js(s.stateFile??Uy);try{this.transcriptWatcher=new f_(s,o),await this.transcriptWatcher.start()}catch(a){this.transcriptWatcher?.stop(),this.transcriptWatcher=null,a instanceof Error?h.error("WORKER","Failed to start transcript watcher (continuing without Codex ingestion)",{configPath:i},a):h.error("WORKER","Failed to start transcript watcher with non-Error (continuing without Codex ingestion)",{configPath:i},new Error(String(a)));return}h.info("TRANSCRIPT","Transcript watcher started",{configPath:i,statePath:o,watches:s.watches.length})}getActiveAgent(){return Ju()&&La()?this.openRouterAgent:Ku()&&za()?this.geminiAgent:this.sdkAgent}startSessionProcessor(e,r){if(!e)return;let n=e.sessionDbId,i=this.getActiveAgent(),s=i.constructor.name;e.abortController.signal.aborted&&(h.debug("SYSTEM","Replacing aborted AbortController before starting generator",{sessionId:e.sessionDbId}),e.abortController=new AbortController);let o=!1,a=!1;h.info("SYSTEM",`Starting generator (${r}) using ${s}`,{sessionId:n}),e.lastGeneratorActivity=Date.now(),e.generatorPromise=i.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},h.error("SDK","Unrecoverable generator error - will NOT restart",{sessionId:e.sessionDbId,project:e.project,errorMessage:u});return}if(this.isSessionTerminatedError(c))return h.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&&(h.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),h.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=us(e.sessionDbId);if(c&&c.process.exitCode===null&&await Co(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}let d=3;if(l>0){if(e.consecutiveRestarts=(e.consecutiveRestarts||0)+1,e.consecutiveRestarts>d){h.error("SYSTEM","Exceeded max pending-work restarts, stopping to prevent infinite loop",{sessionId:e.sessionDbId,pendingCount:l,consecutiveRestarts:e.consecutiveRestarts}),e.consecutiveRestarts=0,this.terminateSession(e.sessionDbId,"max_restarts_exceeded");return}h.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.consecutiveRestarts=0,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 n=(e instanceof Error?e.message:String(e)).toLowerCase();return t.SESSION_TERMINATED_PATTERNS.some(i=>n.includes(i))}async runFallbackForTerminatedSession(e,r){if(!e)return;let n=e.sessionDbId;if(!e.memorySessionId){let o=`fallback-${n}-${Date.now()}`;e.memorySessionId=o,this.dbManager.getSessionStore().updateMemorySessionId(n,o)}if(za())try{await this.geminiAgent.startSession(e,this);return}catch(o){o instanceof Error?(h.warn("WORKER","Fallback Gemini failed, trying OpenRouter",{sessionId:n}),h.error("WORKER","Gemini fallback error detail",{sessionId:n},o)):h.error("WORKER","Gemini fallback failed with non-Error",{sessionId:n},new Error(String(o)))}if(La())try{await this.openRouterAgent.startSession(e,this);return}catch(o){o instanceof Error?h.error("WORKER","Fallback OpenRouter failed, will abandon messages",{sessionId:n},o):h.error("WORKER","Fallback OpenRouter failed with non-Error, will abandon messages",{sessionId:n},new Error(String(o)))}let s=this.sessionManager.getPendingMessageStore().markAllSessionMessagesAbandoned(n);s>0&&h.warn("SDK","No fallback available; marked pending messages abandoned",{sessionId:n,abandoned:s}),this.sessionManager.removeSessionImmediate(n),this.sessionEventBroadcaster.broadcastSessionCompleted(n)}terminateSession(e,r){let i=this.sessionManager.getPendingMessageStore().markAllSessionMessagesAbandoned(e);h.info("SYSTEM","Session terminated",{sessionId:e,reason:r,abandonedMessages:i}),this.sessionManager.removeSessionImmediate(e)}async processPendingQueues(e=10){let{PendingMessageStore:r}=await Promise.resolve().then(()=>(Oa(),Su)),n=new r(this.dbManager.getSessionStore().db,3),i=this.dbManager.getSessionStore(),s=360*60*1e3,o=Date.now()-s,a=i.db.prepare(` SELECT id FROM sdk_sessions WHERE status = 'active' AND started_at_epoch < ? `).all(o);if(a.length>0){let l=a.map(f=>f.id),d=l.map(()=>"?").join(","),p=Date.now();try{i.db.prepare(`