From 2d146b78f22d427a8bd7eed68fbb2aa8973c59de Mon Sep 17 00:00:00 2001 From: Alex Newman Date: Sat, 25 Apr 2026 21:27:09 -0700 Subject: [PATCH] chore: bump version to 12.4.7 --- .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 f11d6f18..7919c5fc 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -10,7 +10,7 @@ "plugins": [ { "name": "claude-mem", - "version": "12.4.6", + "version": "12.4.7", "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 5b298fb9..6075abbd 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "claude-mem", - "version": "12.4.6", + "version": "12.4.7", "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 0e9a9b32..b010346e 100644 --- a/.codex-plugin/plugin.json +++ b/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "claude-mem", - "version": "12.4.6", + "version": "12.4.7", "description": "Memory compression system for Claude Code - persist context across sessions", "author": { "name": "Alex Newman", diff --git a/package.json b/package.json index 9a3a5539..74fe9b2e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "claude-mem", - "version": "12.4.6", + "version": "12.4.7", "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 e4dd9639..01052467 100644 --- a/plugin/.claude-plugin/plugin.json +++ b/plugin/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "claude-mem", - "version": "12.4.6", + "version": "12.4.7", "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 f1b62d73..a95f6cc9 100644 --- a/plugin/package.json +++ b/plugin/package.json @@ -1,6 +1,6 @@ { "name": "claude-mem-plugin", - "version": "12.4.6", + "version": "12.4.7", "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 a5c04c6c..9821ed9a 100755 --- a/plugin/scripts/mcp-server.cjs +++ b/plugin/scripts/mcp-server.cjs @@ -149,7 +149,7 @@ ${m}`}let c=o.lineStart;for(let u=o.lineStart-1;u>=0;u--){let d=i[u].trim();if(d ${l}`}var Yu=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"]),US=new Set(["node_modules",".git","dist","build",".next","__pycache__",".venv","venv","env",".env","target","vendor",".cache",".turbo","coverage",".nyc_output",".claude",".smart-file-read"]),FS=512*1024;async function*Ju(t,e,r=20,n){if(r<=0)return;let s;try{s=await(0,Ft.readdir)(t,{withFileTypes:!0})}catch(o){y.debug("WORKER",`walkDir: failed to read directory ${t}`,void 0,o instanceof Error?o:void 0);return}for(let o of s){if(o.name.startsWith(".")&&o.name!=="."||US.has(o.name))continue;let i=(0,jr.join)(t,o.name);if(o.isDirectory())yield*Ju(i,e,r-1,n);else if(o.isFile()){let c=o.name.slice(o.name.lastIndexOf("."));(Yu.has(c)||n&&n.has(c))&&(yield i)}}}async function HS(t){try{let e=await(0,Ft.stat)(t);if(e.size>FS||e.size===0)return null;let r=await(0,Ft.readFile)(t,"utf-8");return r.slice(0,1e3).includes("\0")?null:r}catch(e){return y.debug("WORKER",`safeReadFile: failed to read ${t}`,void 0,e instanceof Error?e:void 0),null}}async function Bu(t,e,r={}){let n=r.maxResults||20,s=e.toLowerCase(),o=s.split(/[\s_\-./]+/).filter(S=>S.length>0),i=r.projectRoot||t,c=Lr(i),l=new Set;for(let S of Object.values(c.grammars))for(let w of S.extensions)Yu.has(w)||l.add(w);let u=[];for await(let S of Ju(t,t,20,l.size>0?l:void 0)){if(r.filePattern&&!(0,jr.relative)(t,S).toLowerCase().includes(r.filePattern.toLowerCase()))continue;let w=await HS(S);w&&u.push({absolutePath:S,relativePath:(0,jr.relative)(t,S),content:w})}let d=Vu(u,i),f=[],p=[],m=0;for(let[S,w]of d){m+=WS(w);let k=rs(S.toLowerCase(),o)>0,le=[],de=(Wt,gt)=>{for(let H of Wt){let Ve=0,Ee="",Vt=rs(H.name.toLowerCase(),o);Vt>0&&(Ve+=Vt*3,Ee="name match"),H.signature.toLowerCase().includes(s)&&(Ve+=2,Ee=Ee?`${Ee} + signature`:"signature match"),H.jsdoc&&H.jsdoc.toLowerCase().includes(s)&&(Ve+=1,Ee=Ee?`${Ee} + jsdoc`:"jsdoc match"),Ve>0&&(k=!0,le.push({filePath:S,symbolName:gt?`${gt}.${H.name}`:H.name,kind:H.kind,signature:H.signature,jsdoc:H.jsdoc,lineStart:H.lineStart,lineEnd:H.lineEnd,matchReason:Ee})),H.children&&de(H.children,H.name)}};de(w.symbols),k&&(f.push(w),p.push(...le))}p.sort((S,w)=>{let A=rs(S.symbolName.toLowerCase(),o);return rs(w.symbolName.toLowerCase(),o)-A});let h=p.slice(0,n),g=new Set(h.map(S=>S.filePath)),_=f.filter(S=>g.has(S.filePath)).slice(0,n),E=_.reduce((S,w)=>S+w.foldedTokenEstimate,0);return{foldedFiles:_,matchingSymbols:h,totalFilesScanned:u.length,totalSymbolsFound:m,tokenEstimate:E}}function rs(t,e){let r=0;for(let n of e)if(t===n)r+=10;else if(t.includes(n))r+=5;else{let s=0,o=0;for(let i of n){let c=t.indexOf(i,s);c!==-1&&(o++,s=c+1)}o===n.length&&(r+=1)}return r}function WS(t){let e=t.symbols.length;for(let r of t.symbols)r.children&&(e+=r.children.length);return e}function Zu(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 s=n.jsdoc.split(` `).find(o=>o.replace(/^[\s*/]+/,"").trim().length>0);s&&r.push(` \u{1F4AC} ${s.replace(/^[\s*/]+/,"").trim()}`)}r.push("")}r.push("\u2500\u2500 Folded File Views \u2500\u2500"),r.push("");for(let n of t.foldedFiles)r.push(Ut(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 Gi=require("node:fs/promises"),ed=require("node:fs"),ht=require("node:path"),td=require("node:url"),tE={},VS="12.4.6";console.log=(...t)=>{y.error("CONSOLE","Intercepted console output (MCP protocol protection)",void 0,{args:t})};var rd=!1,nd=(()=>{if(typeof __dirname<"u")return __dirname;try{return(0,ht.dirname)((0,td.fileURLToPath)(tE.url))}catch{return rd=!0,process.cwd()}})(),Ki=(0,ht.resolve)(nd,"worker-service.cjs");function GS(){rd&&((0,ed.existsSync)(Ki)||y.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:Ki,mcpServerDir:nd}))}var Xu={search:"/api/search",timeline:"/api/timeline"};async function Vi(t,e){y.debug("SYSTEM","\u2192 Worker API",void 0,{endpoint:t,params:e});let r=new URLSearchParams;for(let[s,o]of Object.entries(e))o!=null&&r.append(s,String(o));let n=`${t}?${r}`;try{let s=await Qn(n);if(!s.ok){let i=await s.text();throw new Error(`Worker API error (${s.status}): ${i}`)}let o=await s.json();return y.debug("SYSTEM","\u2190 Worker API success",void 0,{endpoint:t}),o}catch(s){return y.error("SYSTEM","\u2190 Worker API error",{endpoint:t},s instanceof Error?s:new Error(String(s))),{content:[{type:"text",text:`Error calling Worker API: ${s instanceof Error?s.message:String(s)}`}],isError:!0}}}async function KS(t,e){let r=await Qn(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!r.ok){let s=await r.text();throw new Error(`Worker API error (${r.status}): ${s}`)}let n=await r.json();return y.debug("HTTP","Worker API success (POST)",void 0,{endpoint:t}),{content:[{type:"text",text:JSON.stringify(n,null,2)}]}}async function Ht(t,e){y.debug("HTTP","Worker API request (POST)",void 0,{endpoint:t});try{return await KS(t,e)}catch(r){return y.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 YS(){try{return(await Qn("/api/health")).ok}catch(t){return y.debug("SYSTEM","Worker health check failed",{},t instanceof Error?t:new Error(String(t))),!1}}async function JS(){if(await YS())return!0;y.warn("SYSTEM","Worker not available, attempting auto-start for MCP client"),GS();try{let t=xi(),e=await xu(t,Ki);return e||y.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 y.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 sd=[{name:"__IMPORTANT",description:`3-LAYER WORKFLOW (ALWAYS FOLLOW): +`)}var Gi=require("node:fs/promises"),ed=require("node:fs"),ht=require("node:path"),td=require("node:url"),tE={},VS="12.4.7";console.log=(...t)=>{y.error("CONSOLE","Intercepted console output (MCP protocol protection)",void 0,{args:t})};var rd=!1,nd=(()=>{if(typeof __dirname<"u")return __dirname;try{return(0,ht.dirname)((0,td.fileURLToPath)(tE.url))}catch{return rd=!0,process.cwd()}})(),Ki=(0,ht.resolve)(nd,"worker-service.cjs");function GS(){rd&&((0,ed.existsSync)(Ki)||y.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:Ki,mcpServerDir:nd}))}var Xu={search:"/api/search",timeline:"/api/timeline"};async function Vi(t,e){y.debug("SYSTEM","\u2192 Worker API",void 0,{endpoint:t,params:e});let r=new URLSearchParams;for(let[s,o]of Object.entries(e))o!=null&&r.append(s,String(o));let n=`${t}?${r}`;try{let s=await Qn(n);if(!s.ok){let i=await s.text();throw new Error(`Worker API error (${s.status}): ${i}`)}let o=await s.json();return y.debug("SYSTEM","\u2190 Worker API success",void 0,{endpoint:t}),o}catch(s){return y.error("SYSTEM","\u2190 Worker API error",{endpoint:t},s instanceof Error?s:new Error(String(s))),{content:[{type:"text",text:`Error calling Worker API: ${s instanceof Error?s.message:String(s)}`}],isError:!0}}}async function KS(t,e){let r=await Qn(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!r.ok){let s=await r.text();throw new Error(`Worker API error (${r.status}): ${s}`)}let n=await r.json();return y.debug("HTTP","Worker API success (POST)",void 0,{endpoint:t}),{content:[{type:"text",text:JSON.stringify(n,null,2)}]}}async function Ht(t,e){y.debug("HTTP","Worker API request (POST)",void 0,{endpoint:t});try{return await KS(t,e)}catch(r){return y.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 YS(){try{return(await Qn("/api/health")).ok}catch(t){return y.debug("SYSTEM","Worker health check failed",{},t instanceof Error?t:new Error(String(t))),!1}}async function JS(){if(await YS())return!0;y.warn("SYSTEM","Worker not available, attempting auto-start for MCP client"),GS();try{let t=xi(),e=await xu(t,Ki);return e||y.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 y.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 sd=[{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 8b9853f0..85ce4ba9 100755 --- a/plugin/scripts/worker-service.cjs +++ b/plugin/scripts/worker-service.cjs @@ -1066,7 +1066,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=CL(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 DI({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 B8=ke(fS(),1),W8=ke(require("http"),1),ZO=ke(require("fs"),1),$m=ke(require("path"),1);var LO=["search","context","summarize","import","export"],P8=["workflow","search_params","examples","all"];re();var UO=ke(fS(),1),z8=ke(j8(),1),L8=ke(require("path"),1);vt();re();function FO(t){let e=[];e.push(UO.default.json({limit:"5mb"})),e.push((0,z8.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","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=Rn(),n=L8.default.join(r,"plugin","ui");return e.push(UO.default.static(n)),e}function Tm(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 qO(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":""}km();Ko();gs();Bo();var G8=$m.default.resolve(__dirname,"../skills/mem-search"),Rme=$m.default.join(G8,"operations"),HO=$m.default.join(G8,"SKILL.md"),H8=(()=>{try{let t=ZO.readFileSync(HO,"utf-8");return h.info("SYSTEM","Cached SKILL.md at boot",{path:HO,bytes:Buffer.byteLength(t,"utf-8")}),t}catch(t){return h.debug("SYSTEM","SKILL.md not present at boot, /api/instructions will 404 for topic queries",{path:HO,message:t instanceof Error?t.message:String(t)}),null}})(),Ome=(()=>{let t=new Map;for(let e of LO){let r=$m.default.join(Rme,`${e}.md`);try{t.set(e,ZO.readFileSync(r,"utf-8"))}catch(n){h.debug("SYSTEM","Operation instruction file not present at boot",{path:r,message:n instanceof Error?n.message:String(n)})}}return t.size>0&&h.info("SYSTEM","Cached operation instruction files at boot",{count:t.size,operations:Array.from(t.keys())}),t})(),Z8="12.4.6",mS=class{app;server=null;options;startTime=Date.now();constructor(e){this.options=e,this.app=(0,B8.default)(),this.setupMiddleware(),this.setupCoreRoutes()}getHttpServer(){return this.server}async listen(e,r){return new Promise((n,i)=>{let s=W8.default.createServer(this.app);this.server=s;let o=c=>{s.off("listening",a),i(c)},a=()=>{s.off("error",o),h.info("SYSTEM","HTTP server started",{host:r,port:e,pid:process.pid}),n()};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(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(q8),this.app.use(F8)}setupMiddleware(){FO(qO).forEach(r=>this.app.use(r))}setupCoreRoutes(){this.app.get("/api/health",(e,r)=>{r.status(200).json({status:"ok",version:Z8,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:Z8})}),this.app.get("/api/instructions",(e,r)=>{let n=e.query.topic||"all",i=e.query.operation;if(n&&!P8.includes(n))return r.status(400).json({error:"Invalid topic"});if(i&&!LO.includes(i))return r.status(400).json({error:"Invalid operation"});if(i){let o=Ome.get(i);return o===void 0?(h.debug("HTTP","Instruction file not cached at boot",{operation:i}),r.status(404).json({error:"Instruction not found"})):r.json({content:[{type:"text",text:o}]})}if(H8===null)return h.debug("HTTP","SKILL.md not cached at boot",{topic:n}),r.status(404).json({error:"Instruction not found"});let s=this.extractInstructionSection(H8,n);r.json({content:[{type:"text",text:s}]})}),this.app.post("/api/admin/restart",Tm,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",Tm,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",Tm,(e,r)=>{let o=jr().getRegistry().getAll().map(m=>({id:m.id,pid:m.pid,type:m.type,status:Bn(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=>nI.has(m)||rI.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}})})}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 At=ke(require("path"),1),Rm=require("os"),tr=require("fs"),J8=require("child_process"),Y8=require("util");re();Vr();vt();var bi=require("fs"),Im=require("path");re();function V8(t){try{return(0,bi.existsSync)(t)?JSON.parse((0,bi.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 K8(t,e){let r=(0,Im.join)(t,"..");(0,bi.mkdirSync)(r,{recursive:!0}),(0,bi.writeFileSync)(t,JSON.stringify(e,null,2))}function BO(t,e){let r=(0,Im.join)(t,".cursor","rules"),n=(0,Im.join)(r,"claude-mem-context.mdc"),i=`${n}.tmp`;(0,bi.mkdirSync)(r,{recursive:!0});let s=`--- + `).all();for(let{cwd:u}of c){let l=CL(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 DI({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 B8=ke(fS(),1),W8=ke(require("http"),1),ZO=ke(require("fs"),1),$m=ke(require("path"),1);var LO=["search","context","summarize","import","export"],P8=["workflow","search_params","examples","all"];re();var UO=ke(fS(),1),z8=ke(j8(),1),L8=ke(require("path"),1);vt();re();function FO(t){let e=[];e.push(UO.default.json({limit:"5mb"})),e.push((0,z8.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","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=Rn(),n=L8.default.join(r,"plugin","ui");return e.push(UO.default.static(n)),e}function Tm(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 qO(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":""}km();Ko();gs();Bo();var G8=$m.default.resolve(__dirname,"../skills/mem-search"),Rme=$m.default.join(G8,"operations"),HO=$m.default.join(G8,"SKILL.md"),H8=(()=>{try{let t=ZO.readFileSync(HO,"utf-8");return h.info("SYSTEM","Cached SKILL.md at boot",{path:HO,bytes:Buffer.byteLength(t,"utf-8")}),t}catch(t){return h.debug("SYSTEM","SKILL.md not present at boot, /api/instructions will 404 for topic queries",{path:HO,message:t instanceof Error?t.message:String(t)}),null}})(),Ome=(()=>{let t=new Map;for(let e of LO){let r=$m.default.join(Rme,`${e}.md`);try{t.set(e,ZO.readFileSync(r,"utf-8"))}catch(n){h.debug("SYSTEM","Operation instruction file not present at boot",{path:r,message:n instanceof Error?n.message:String(n)})}}return t.size>0&&h.info("SYSTEM","Cached operation instruction files at boot",{count:t.size,operations:Array.from(t.keys())}),t})(),Z8="12.4.7",mS=class{app;server=null;options;startTime=Date.now();constructor(e){this.options=e,this.app=(0,B8.default)(),this.setupMiddleware(),this.setupCoreRoutes()}getHttpServer(){return this.server}async listen(e,r){return new Promise((n,i)=>{let s=W8.default.createServer(this.app);this.server=s;let o=c=>{s.off("listening",a),i(c)},a=()=>{s.off("error",o),h.info("SYSTEM","HTTP server started",{host:r,port:e,pid:process.pid}),n()};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(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(q8),this.app.use(F8)}setupMiddleware(){FO(qO).forEach(r=>this.app.use(r))}setupCoreRoutes(){this.app.get("/api/health",(e,r)=>{r.status(200).json({status:"ok",version:Z8,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:Z8})}),this.app.get("/api/instructions",(e,r)=>{let n=e.query.topic||"all",i=e.query.operation;if(n&&!P8.includes(n))return r.status(400).json({error:"Invalid topic"});if(i&&!LO.includes(i))return r.status(400).json({error:"Invalid operation"});if(i){let o=Ome.get(i);return o===void 0?(h.debug("HTTP","Instruction file not cached at boot",{operation:i}),r.status(404).json({error:"Instruction not found"})):r.json({content:[{type:"text",text:o}]})}if(H8===null)return h.debug("HTTP","SKILL.md not cached at boot",{topic:n}),r.status(404).json({error:"Instruction not found"});let s=this.extractInstructionSection(H8,n);r.json({content:[{type:"text",text:s}]})}),this.app.post("/api/admin/restart",Tm,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",Tm,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",Tm,(e,r)=>{let o=jr().getRegistry().getAll().map(m=>({id:m.id,pid:m.pid,type:m.type,status:Bn(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=>nI.has(m)||rI.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}})})}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 At=ke(require("path"),1),Rm=require("os"),tr=require("fs"),J8=require("child_process"),Y8=require("util");re();Vr();vt();var bi=require("fs"),Im=require("path");re();function V8(t){try{return(0,bi.existsSync)(t)?JSON.parse((0,bi.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 K8(t,e){let r=(0,Im.join)(t,"..");(0,bi.mkdirSync)(r,{recursive:!0}),(0,bi.writeFileSync)(t,JSON.stringify(e,null,2))}function BO(t,e){let r=(0,Im.join)(t,".cursor","rules"),n=(0,Im.join)(r,"claude-mem-context.mdc"),i=`${n}.tmp`;(0,bi.mkdirSync)(r,{recursive:!0});let s=`--- alwaysApply: true description: "Claude-mem context from past sessions (auto-updated)" --- @@ -1685,7 +1685,7 @@ ${s.formatTableHeader()}`,f=d.map((m,g)=>s.formatObservationIndex(m,g));n.json({ `);lr(li);let i=this.findClaudeExecutable(),s=Zn(Uf()),o=sh({prompt:n,options:{model:this.getModelId(),cwd:li,disallowedTools:vW,pathToClaudeCodeExecutable:i,env:s,mcpServers:{}}}),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){lr(li);let n=this.findClaudeExecutable(),i=Zn(Uf()),s=sh({prompt:r,options:{model:this.getModelId(),resume:e.session_id,cwd:li,disallowedTools:vW,pathToClaudeCodeExecutable:n,env:i,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?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 be.loadFromFile(gt).CLAUDE_MEM_MODEL}findClaudeExecutable(){let e=be.loadFromFile(gt);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,Y1.execSync)("where claude.cmd",{encoding:"utf8",windowsHide:!0,stdio:["ignore","pipe","ignore"]}),"claude.cmd"}catch{}try{let r=(0,Y1.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`)}};gs();var Wke={},qke="12.4.6";function GW(t,e){return{continue:!0,suppressOutput:!0,status:t,...e&&{message:e}}}var mw=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 yS,this.sessionManager=new xS(this.dbManager),this.sseBroadcaster=new wS,this.sdkAgent=new ix(this.dbManager,this.sessionManager),this.geminiAgent=new sx(this.dbManager,this.sessionManager),this.openRouterAgent=new cx(this.dbManager,this.sessionManager),this.paginationHelper=new ux(this.dbManager),this.settingsManager=new lx(this.dbManager),this.sessionEventBroadcaster=new hx(this.sseBroadcaster,this),this.completionHandler=new gx(this.sessionManager,this.sessionEventBroadcaster,this.dbManager),this.corpusStore=new uw,bH({sessionManager:this.sessionManager,dbManager:this.dbManager,eventBroadcaster:this.sessionEventBroadcaster}),this.sessionManager.setOnSessionDeleted(()=>{this.broadcastProcessingStatus()}),this.mcpClient=new Yu({name:"worker-search-proxy",version:qke},{capabilities:{}}),this.server=new mS({getInitializationComplete:()=>this.initializationCompleteFlag,getMcpReady:()=>this.mcpReady,onShutdown:()=>this.shutdown(),onRestart:()=>this.shutdown(),workerPath:__filename,getAiStatus:()=>{let e="claude";return ld()&&Ic()?e="openrouter":ud()&&$c()&&(e="gemini"),{provider:e,authMethod:Z_(),lastInteraction:this.lastAiInteraction?{timestamp:this.lastAiInteraction.timestamp,success:this.lastAiInteraction.success,...this.lastAiInteraction.error&&{error:this.lastAiInteraction.error}}:null}}}),this.registerRoutes(),this.registerSignalHandlers()}registerSignalHandlers(){B4(async()=>{this.isShuttingDown=!0,await this.shutdown()})}registerRoutes(){this.server.registerRoutes(new cw),this.server.app.get("/api/context/inject",async(r,n,i)=>{if(!this.initializationCompleteFlag||!this.searchRoutes){h.warn("SYSTEM","Context requested before initialization complete, returning empty"),n.status(200).json({content:[{type:"text",text:""}]});return}i()}),this.server.app.use("/api",async(r,n,i)=>{if(r.path==="/chroma/status"||r.path==="/health"||r.path==="/readiness"||r.path==="/version"){i();return}if(this.initializationCompleteFlag){i();return}let s=12e4,o=new Promise((a,c)=>setTimeout(()=>c(new Error("Database initialization timeout")),s));try{await Promise.race([this.initializationComplete,o]),i()}catch(a){a instanceof Error?h.error("WORKER",`Request to ${r.method} ${r.path} rejected \u2014 DB not initialized`,{},a):h.error("WORKER",`Request to ${r.method} ${r.path} rejected \u2014 DB not initialized with non-Error`,{},new Error(String(a))),n.status(503).json({error:"Service initializing",message:"Database is still initializing, please retry"});return}}),this.server.registerRoutes(new Wx(this.sseBroadcaster,this.dbManager,this.sessionManager));let e=new Vx(this.sessionManager,this.dbManager,this.sdkAgent,this.geminiAgent,this.openRouterAgent,this.sessionEventBroadcaster,this,this.completionHandler);this.server.registerRoutes(e),SH((r,n)=>e.ensureGeneratorRunning(r,n)),this.server.registerRoutes(new Kx(this.paginationHelper,this.dbManager,this.sessionManager,this.sseBroadcaster,this,this.startTime)),this.server.registerRoutes(new nw(this.settingsManager)),this.server.registerRoutes(new sw),this.server.registerRoutes(new ow(this.dbManager,"claude-mem"))}async start(){let e=ln(),r=pI();await Z4(),await this.server.listen(e,r),gL({pid:process.pid,port:e,startedAt:new Date().toISOString()}),jr().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{h.info("WORKER","Background initialization starting...");let{ModeManager:e}=await Promise.resolve().then(()=>(mn(),uH)),{SettingsDefaultsManager:r}=await Promise.resolve().then(()=>(Xt(),y4)),{USER_SETTINGS_PATH:n}=await Promise.resolve().then(()=>(vt(),T4)),i=r.loadFromFile(n),s=i.CLAUDE_MEM_MODE;e.getInstance().loadMode(s),h.info("SYSTEM",`Mode loaded: ${s}`),(i.CLAUDE_MEM_MODE==="local"||!i.CLAUDE_MEM_MODE)&&(h.info("WORKER","Checking for one-time Chroma migration..."),vL()),h.info("WORKER","Checking for one-time CWD remap..."),yL(),h.info("WORKER","Adopting merged worktrees (background)..."),PL({}).then(g=>{if(g)for(let v of g)(v.adoptedObservations>0||v.adoptedSummaries>0||v.chromaUpdates>0)&&h.info("SYSTEM","Merged worktrees adopted in background",v),v.errors.length>0&&h.warn("SYSTEM","Worktree adoption had per-branch errors",{repoPath:v.repoPath,errors:v.errors})}).catch(g=>{h.error("WORKER","Worktree adoption failed (background)",{},g instanceof Error?g:new Error(String(g)))}),i.CLAUDE_MEM_CHROMA_ENABLED!=="false"?(this.chromaMcpManager=pi.getInstance(),h.info("SYSTEM","ChromaMcpManager initialized (lazy - connects on first use)")):h.info("SYSTEM","Chroma disabled via CLAUDE_MEM_CHROMA_ENABLED=false, skipping ChromaMcpManager"),h.info("WORKER","Initializing database manager..."),await this.dbManager.initialize();try{h.info("WORKER","Running startup GC for pending messages...");let{PendingMessageStore:g}=await Promise.resolve().then(()=>(_S(),XO)),y=new g(this.dbManager.getSessionStore().db,3).clearFailedOlderThan(10080*60*1e3);y>0&&h.info("QUEUE","Startup GC cleared old failed pending_messages rows",{cleared:y})}catch(g){h.warn("QUEUE","Startup GC for failed pending_messages rows failed",{},g instanceof Error?g:void 0)}NI(),h.info("WORKER","Initializing search services...");let a=new fx,c=new mx,u=new px(this.dbManager.getSessionSearch(),this.dbManager.getSessionStore(),this.dbManager.getChromaSync(),a,c);this.searchRoutes=new ew(u),this.server.registerRoutes(this.searchRoutes),h.info("WORKER","SearchManager initialized and search routes registered");let{SearchOrchestrator:l}=await Promise.resolve().then(()=>(o1(),aZ)),d=new l(this.dbManager.getSessionSearch(),this.dbManager.getSessionStore(),this.dbManager.getChromaSync()),p=new dw(this.dbManager.getSessionStore(),d,this.corpusStore),f=new pw(this.corpusStore);this.server.registerRoutes(new aw(this.corpusStore,p,f)),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&&Yo.backfillAllProjects(this.dbManager.getSessionStore()).then(()=>{h.info("CHROMA_SYNC","Backfill check complete for all projects")}).catch(g=>{h.error("CHROMA_SYNC","Backfill failed (non-blocking)",{},g)});let m=WW.default.join(__dirname,"mcp-server.cjs");this.mcpReady=(0,pP.existsSync)(m),this.runMcpSelfCheck(m).catch(g=>{h.debug("WORKER","MCP self-check failed (non-fatal)",{error:g.message})});return}catch(e){h.error("SYSTEM","Background initialization failed",{},e instanceof Error?e:void 0)}}async runMcpSelfCheck(e){try{jr().assertCanSpawn("mcp server");let r=new el({command:process.execPath,args:[e],env:Object.fromEntries(Object.entries(Zn(process.env)).filter(([,o])=>o!==void 0))}),n=6e4,i=this.mcpClient.connect(r),s=new Promise((o,a)=>{setTimeout(()=>a(new Error("MCP connection timeout")),6e4)});await Promise.race([i,s]),h.info("WORKER","MCP loopback self-check connected successfully"),await r.close()}catch(r){h.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")){h.info("TRANSCRIPT","Transcript watcher disabled via CLAUDE_MEM_TRANSCRIPTS_ENABLED=false");return}let n=e.CLAUDE_MEM_TRANSCRIPTS_CONFIG_PATH||yx,i=mo(n);(0,pP.existsSync)(i)||(uZ(n),h.info("TRANSCRIPT","Created default transcript watch config",{configPath:i}));let s=cZ(n),o=mo(s.stateFile??_x);try{this.transcriptWatcher=new Hx(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 ld()&&Ic()?this.openRouterAgent:ud()&&$c()?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=Go(e.sessionDbId);if(c&&c.process.exitCode===null&&await Vo(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 ea);let d=e.restartGuard.recordRestart();if(e.consecutiveRestarts=(e.consecutiveRestarts||0)+1,!d){h.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}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.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 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 i=`fallback-${n}-${Date.now()}`;e.memorySessionId=i,this.dbManager.getSessionStore().updateMemorySessionId(n,i)}if($c())try{await this.geminiAgent.startSession(e,this);return}catch(i){i instanceof Error?(h.warn("WORKER","Fallback Gemini failed, trying OpenRouter",{sessionId:n}),h.error("WORKER","Gemini fallback error detail",{sessionId:n},i)):h.error("WORKER","Gemini fallback failed with non-Error",{sessionId:n},new Error(String(i)))}if(Ic())try{await this.openRouterAgent.startSession(e,this);return}catch(i){i instanceof Error?h.error("WORKER","Fallback OpenRouter failed, will abandon messages",{sessionId:n},i):h.error("WORKER","Fallback OpenRouter failed with non-Error, will abandon messages",{sessionId:n},new Error(String(i)))}this.completionHandler.finalizeSession(n),this.sessionManager.removeSessionImmediate(n)}terminateSession(e,r){h.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(()=>(_S(),XO)),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`)}};gs();var Wke={},qke="12.4.7";function GW(t,e){return{continue:!0,suppressOutput:!0,status:t,...e&&{message:e}}}var mw=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 yS,this.sessionManager=new xS(this.dbManager),this.sseBroadcaster=new wS,this.sdkAgent=new ix(this.dbManager,this.sessionManager),this.geminiAgent=new sx(this.dbManager,this.sessionManager),this.openRouterAgent=new cx(this.dbManager,this.sessionManager),this.paginationHelper=new ux(this.dbManager),this.settingsManager=new lx(this.dbManager),this.sessionEventBroadcaster=new hx(this.sseBroadcaster,this),this.completionHandler=new gx(this.sessionManager,this.sessionEventBroadcaster,this.dbManager),this.corpusStore=new uw,bH({sessionManager:this.sessionManager,dbManager:this.dbManager,eventBroadcaster:this.sessionEventBroadcaster}),this.sessionManager.setOnSessionDeleted(()=>{this.broadcastProcessingStatus()}),this.mcpClient=new Yu({name:"worker-search-proxy",version:qke},{capabilities:{}}),this.server=new mS({getInitializationComplete:()=>this.initializationCompleteFlag,getMcpReady:()=>this.mcpReady,onShutdown:()=>this.shutdown(),onRestart:()=>this.shutdown(),workerPath:__filename,getAiStatus:()=>{let e="claude";return ld()&&Ic()?e="openrouter":ud()&&$c()&&(e="gemini"),{provider:e,authMethod:Z_(),lastInteraction:this.lastAiInteraction?{timestamp:this.lastAiInteraction.timestamp,success:this.lastAiInteraction.success,...this.lastAiInteraction.error&&{error:this.lastAiInteraction.error}}:null}}}),this.registerRoutes(),this.registerSignalHandlers()}registerSignalHandlers(){B4(async()=>{this.isShuttingDown=!0,await this.shutdown()})}registerRoutes(){this.server.registerRoutes(new cw),this.server.app.get("/api/context/inject",async(r,n,i)=>{if(!this.initializationCompleteFlag||!this.searchRoutes){h.warn("SYSTEM","Context requested before initialization complete, returning empty"),n.status(200).json({content:[{type:"text",text:""}]});return}i()}),this.server.app.use("/api",async(r,n,i)=>{if(r.path==="/chroma/status"||r.path==="/health"||r.path==="/readiness"||r.path==="/version"){i();return}if(this.initializationCompleteFlag){i();return}let s=12e4,o=new Promise((a,c)=>setTimeout(()=>c(new Error("Database initialization timeout")),s));try{await Promise.race([this.initializationComplete,o]),i()}catch(a){a instanceof Error?h.error("WORKER",`Request to ${r.method} ${r.path} rejected \u2014 DB not initialized`,{},a):h.error("WORKER",`Request to ${r.method} ${r.path} rejected \u2014 DB not initialized with non-Error`,{},new Error(String(a))),n.status(503).json({error:"Service initializing",message:"Database is still initializing, please retry"});return}}),this.server.registerRoutes(new Wx(this.sseBroadcaster,this.dbManager,this.sessionManager));let e=new Vx(this.sessionManager,this.dbManager,this.sdkAgent,this.geminiAgent,this.openRouterAgent,this.sessionEventBroadcaster,this,this.completionHandler);this.server.registerRoutes(e),SH((r,n)=>e.ensureGeneratorRunning(r,n)),this.server.registerRoutes(new Kx(this.paginationHelper,this.dbManager,this.sessionManager,this.sseBroadcaster,this,this.startTime)),this.server.registerRoutes(new nw(this.settingsManager)),this.server.registerRoutes(new sw),this.server.registerRoutes(new ow(this.dbManager,"claude-mem"))}async start(){let e=ln(),r=pI();await Z4(),await this.server.listen(e,r),gL({pid:process.pid,port:e,startedAt:new Date().toISOString()}),jr().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{h.info("WORKER","Background initialization starting...");let{ModeManager:e}=await Promise.resolve().then(()=>(mn(),uH)),{SettingsDefaultsManager:r}=await Promise.resolve().then(()=>(Xt(),y4)),{USER_SETTINGS_PATH:n}=await Promise.resolve().then(()=>(vt(),T4)),i=r.loadFromFile(n),s=i.CLAUDE_MEM_MODE;e.getInstance().loadMode(s),h.info("SYSTEM",`Mode loaded: ${s}`),(i.CLAUDE_MEM_MODE==="local"||!i.CLAUDE_MEM_MODE)&&(h.info("WORKER","Checking for one-time Chroma migration..."),vL()),h.info("WORKER","Checking for one-time CWD remap..."),yL(),h.info("WORKER","Adopting merged worktrees (background)..."),PL({}).then(g=>{if(g)for(let v of g)(v.adoptedObservations>0||v.adoptedSummaries>0||v.chromaUpdates>0)&&h.info("SYSTEM","Merged worktrees adopted in background",v),v.errors.length>0&&h.warn("SYSTEM","Worktree adoption had per-branch errors",{repoPath:v.repoPath,errors:v.errors})}).catch(g=>{h.error("WORKER","Worktree adoption failed (background)",{},g instanceof Error?g:new Error(String(g)))}),i.CLAUDE_MEM_CHROMA_ENABLED!=="false"?(this.chromaMcpManager=pi.getInstance(),h.info("SYSTEM","ChromaMcpManager initialized (lazy - connects on first use)")):h.info("SYSTEM","Chroma disabled via CLAUDE_MEM_CHROMA_ENABLED=false, skipping ChromaMcpManager"),h.info("WORKER","Initializing database manager..."),await this.dbManager.initialize();try{h.info("WORKER","Running startup GC for pending messages...");let{PendingMessageStore:g}=await Promise.resolve().then(()=>(_S(),XO)),y=new g(this.dbManager.getSessionStore().db,3).clearFailedOlderThan(10080*60*1e3);y>0&&h.info("QUEUE","Startup GC cleared old failed pending_messages rows",{cleared:y})}catch(g){h.warn("QUEUE","Startup GC for failed pending_messages rows failed",{},g instanceof Error?g:void 0)}NI(),h.info("WORKER","Initializing search services...");let a=new fx,c=new mx,u=new px(this.dbManager.getSessionSearch(),this.dbManager.getSessionStore(),this.dbManager.getChromaSync(),a,c);this.searchRoutes=new ew(u),this.server.registerRoutes(this.searchRoutes),h.info("WORKER","SearchManager initialized and search routes registered");let{SearchOrchestrator:l}=await Promise.resolve().then(()=>(o1(),aZ)),d=new l(this.dbManager.getSessionSearch(),this.dbManager.getSessionStore(),this.dbManager.getChromaSync()),p=new dw(this.dbManager.getSessionStore(),d,this.corpusStore),f=new pw(this.corpusStore);this.server.registerRoutes(new aw(this.corpusStore,p,f)),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&&Yo.backfillAllProjects(this.dbManager.getSessionStore()).then(()=>{h.info("CHROMA_SYNC","Backfill check complete for all projects")}).catch(g=>{h.error("CHROMA_SYNC","Backfill failed (non-blocking)",{},g)});let m=WW.default.join(__dirname,"mcp-server.cjs");this.mcpReady=(0,pP.existsSync)(m),this.runMcpSelfCheck(m).catch(g=>{h.debug("WORKER","MCP self-check failed (non-fatal)",{error:g.message})});return}catch(e){h.error("SYSTEM","Background initialization failed",{},e instanceof Error?e:void 0)}}async runMcpSelfCheck(e){try{jr().assertCanSpawn("mcp server");let r=new el({command:process.execPath,args:[e],env:Object.fromEntries(Object.entries(Zn(process.env)).filter(([,o])=>o!==void 0))}),n=6e4,i=this.mcpClient.connect(r),s=new Promise((o,a)=>{setTimeout(()=>a(new Error("MCP connection timeout")),6e4)});await Promise.race([i,s]),h.info("WORKER","MCP loopback self-check connected successfully"),await r.close()}catch(r){h.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")){h.info("TRANSCRIPT","Transcript watcher disabled via CLAUDE_MEM_TRANSCRIPTS_ENABLED=false");return}let n=e.CLAUDE_MEM_TRANSCRIPTS_CONFIG_PATH||yx,i=mo(n);(0,pP.existsSync)(i)||(uZ(n),h.info("TRANSCRIPT","Created default transcript watch config",{configPath:i}));let s=cZ(n),o=mo(s.stateFile??_x);try{this.transcriptWatcher=new Hx(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 ld()&&Ic()?this.openRouterAgent:ud()&&$c()?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=Go(e.sessionDbId);if(c&&c.process.exitCode===null&&await Vo(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 ea);let d=e.restartGuard.recordRestart();if(e.consecutiveRestarts=(e.consecutiveRestarts||0)+1,!d){h.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}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.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 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 i=`fallback-${n}-${Date.now()}`;e.memorySessionId=i,this.dbManager.getSessionStore().updateMemorySessionId(n,i)}if($c())try{await this.geminiAgent.startSession(e,this);return}catch(i){i instanceof Error?(h.warn("WORKER","Fallback Gemini failed, trying OpenRouter",{sessionId:n}),h.error("WORKER","Gemini fallback error detail",{sessionId:n},i)):h.error("WORKER","Gemini fallback failed with non-Error",{sessionId:n},new Error(String(i)))}if(Ic())try{await this.openRouterAgent.startSession(e,this);return}catch(i){i instanceof Error?h.error("WORKER","Fallback OpenRouter failed, will abandon messages",{sessionId:n},i):h.error("WORKER","Fallback OpenRouter failed with non-Error, will abandon messages",{sessionId:n},new Error(String(i)))}this.completionHandler.finalizeSession(n),this.sessionManager.removeSessionImmediate(n)}terminateSession(e,r){h.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(()=>(_S(),XO)),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(`