diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 444df75f..02a07490 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -10,7 +10,7 @@ "plugins": [ { "name": "claude-mem", - "version": "10.6.1", + "version": "10.6.2", "source": "./plugin", "description": "Persistent memory system for Claude Code - context compression across sessions" } diff --git a/package.json b/package.json index 2fa51937..74cd1ad3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "claude-mem", - "version": "10.6.1", + "version": "10.6.2", "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 79aa0091..196be884 100644 --- a/plugin/.claude-plugin/plugin.json +++ b/plugin/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "claude-mem", - "version": "10.6.1", + "version": "10.6.2", "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 a74560df..7e910a4c 100644 --- a/plugin/package.json +++ b/plugin/package.json @@ -1,6 +1,6 @@ { "name": "claude-mem-plugin", - "version": "10.6.1", + "version": "10.6.2", "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 404e87bd..5a4d18ab 100755 --- a/plugin/scripts/mcp-server.cjs +++ b/plugin/scripts/mcp-server.cjs @@ -114,7 +114,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs. ${c}`}var xP=new Set([".js",".jsx",".ts",".tsx",".mjs",".cjs",".py",".pyw",".go",".rs",".rb",".java",".cs",".cpp",".c",".h",".hpp",".swift",".kt",".php",".vue",".svelte"]),kP=new Set(["node_modules",".git","dist","build",".next","__pycache__",".venv","venv","env",".env","target","vendor",".cache",".turbo","coverage",".nyc_output",".claude",".smart-file-read"]),SP=512*1024;async function*u$(t,e,r=20){if(r<=0)return;let n;try{n=await(0,zn.readdir)(t,{withFileTypes:!0})}catch{return}for(let o of n){if(o.name.startsWith(".")&&o.name!=="."||kP.has(o.name))continue;let i=(0,hi.join)(t,o.name);if(o.isDirectory())yield*u$(i,e,r-1);else if(o.isFile()){let a=o.name.slice(o.name.lastIndexOf("."));xP.has(a)&&(yield i)}}}async function wP(t){try{let e=await(0,zn.stat)(t);if(e.size>SP||e.size===0)return null;let r=await(0,zn.readFile)(t,"utf-8");return r.slice(0,1e3).includes("\0")?null:r}catch{return null}}async function l$(t,e,r={}){let n=r.maxResults||20,o=e.toLowerCase(),i=o.split(/[\s_\-./]+/).filter(h=>h.length>0),a=[];for await(let h of u$(t,t)){if(r.filePattern&&!(0,hi.relative)(t,h).toLowerCase().includes(r.filePattern.toLowerCase()))continue;let _=await wP(h);_&&a.push({absolutePath:h,relativePath:(0,hi.relative)(t,h),content:_})}let s=a$(a),c=[],u=[],l=0;for(let[h,_]of s){l+=zP(_);let E=js(h.toLowerCase(),i)>0,I=[],A=(j,Le)=>{for(let de of j){let Wt=0,Qe="",Kt=js(de.name.toLowerCase(),i);Kt>0&&(Wt+=Kt*3,Qe="name match"),de.signature.toLowerCase().includes(o)&&(Wt+=2,Qe=Qe?`${Qe} + signature`:"signature match"),de.jsdoc&&de.jsdoc.toLowerCase().includes(o)&&(Wt+=1,Qe=Qe?`${Qe} + jsdoc`:"jsdoc match"),Wt>0&&(E=!0,I.push({filePath:h,symbolName:Le?`${Le}.${de.name}`:de.name,kind:de.kind,signature:de.signature,jsdoc:de.jsdoc,lineStart:de.lineStart,lineEnd:de.lineEnd,matchReason:Qe})),de.children&&A(de.children,de.name)}};A(_.symbols),E&&(c.push(_),u.push(...I))}u.sort((h,_)=>{let b=js(h.symbolName.toLowerCase(),i);return js(_.symbolName.toLowerCase(),i)-b});let d=u.slice(0,n),p=new Set(d.map(h=>h.filePath)),f=c.filter(h=>p.has(h.filePath)).slice(0,n),g=f.reduce((h,_)=>h+_.foldedTokenEstimate,0);return{foldedFiles:f,matchingSymbols:d,totalFilesScanned:a.length,totalSymbolsFound:l,tokenEstimate:g}}function js(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 zP(t){let e=t.symbols.length;for(let r of t.symbols)r.children&&(e+=r.children.length);return e}function d$(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(wn(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 jf=require("node:fs/promises"),Ds=require("node:path"),IP="10.6.1";console.log=(...t)=>{ve.error("CONSOLE","Intercepted console output (MCP protocol protection)",void 0,{args:t})};var p$={search:"/api/search",timeline:"/api/timeline"};async function f$(t,e){ve.debug("SYSTEM","\u2192 Worker API",void 0,{endpoint:t,params:e});try{let r=new URLSearchParams;for(let[a,s]of Object.entries(e))s!=null&&r.append(a,String(s));let n=`${t}?${r}`,o=await Ps(n);if(!o.ok){let a=await o.text();throw new Error(`Worker API error (${o.status}): ${a}`)}let i=await o.json();return ve.debug("SYSTEM","\u2190 Worker API success",void 0,{endpoint:t}),i}catch(r){return ve.error("SYSTEM","\u2190 Worker API error",{endpoint:t},r),{content:[{type:"text",text:`Error calling Worker API: ${r instanceof Error?r.message:String(r)}`}],isError:!0}}}async function EP(t,e){ve.debug("HTTP","Worker API request (POST)",void 0,{endpoint:t});try{let r=await Ps(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 ve.debug("HTTP","Worker API success (POST)",void 0,{endpoint:t}),{content:[{type:"text",text:JSON.stringify(n,null,2)}]}}catch(r){return ve.error("HTTP","Worker API error (POST)",{endpoint:t},r),{content:[{type:"text",text:`Error calling Worker API: ${r instanceof Error?r.message:String(r)}`}],isError:!0}}}async function TP(){try{return(await Ps("/api/health")).ok}catch(t){return ve.debug("SYSTEM","Worker health check failed",{},t),!1}}var m$=[{name:"__IMPORTANT",description:`3-LAYER WORKFLOW (ALWAYS FOLLOW): +`)}var jf=require("node:fs/promises"),Ds=require("node:path"),IP="10.6.2";console.log=(...t)=>{ve.error("CONSOLE","Intercepted console output (MCP protocol protection)",void 0,{args:t})};var p$={search:"/api/search",timeline:"/api/timeline"};async function f$(t,e){ve.debug("SYSTEM","\u2192 Worker API",void 0,{endpoint:t,params:e});try{let r=new URLSearchParams;for(let[a,s]of Object.entries(e))s!=null&&r.append(a,String(s));let n=`${t}?${r}`,o=await Ps(n);if(!o.ok){let a=await o.text();throw new Error(`Worker API error (${o.status}): ${a}`)}let i=await o.json();return ve.debug("SYSTEM","\u2190 Worker API success",void 0,{endpoint:t}),i}catch(r){return ve.error("SYSTEM","\u2190 Worker API error",{endpoint:t},r),{content:[{type:"text",text:`Error calling Worker API: ${r instanceof Error?r.message:String(r)}`}],isError:!0}}}async function EP(t,e){ve.debug("HTTP","Worker API request (POST)",void 0,{endpoint:t});try{let r=await Ps(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 ve.debug("HTTP","Worker API success (POST)",void 0,{endpoint:t}),{content:[{type:"text",text:JSON.stringify(n,null,2)}]}}catch(r){return ve.error("HTTP","Worker API error (POST)",{endpoint:t},r),{content:[{type:"text",text:`Error calling Worker API: ${r instanceof Error?r.message:String(r)}`}],isError:!0}}}async function TP(){try{return(await Ps("/api/health")).ok}catch(t){return ve.debug("SYSTEM","Worker health check failed",{},t),!1}}var m$=[{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 a82cf5fb..2ee5ba51 100755 --- a/plugin/scripts/worker-service.cjs +++ b/plugin/scripts/worker-service.cjs @@ -919,7 +919,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs. JOIN sdk_sessions s ON up.content_session_id = s.content_session_id WHERE s.project = ? `).get(r);y.info("CHROMA_SYNC","Backfilling user prompts",{project:r,missing:v.length,existing:n.prompts.size,total:x.count});let b=[];for(let _ of v)b.push(this.formatUserPromptDoc(_));for(let _=0;_s.trim()).find(s=>s.length>0)||null}catch{return null}}function MK(t={}){let e=t.platform??process.platform,r=t.execPath??process.execPath;if(e!=="win32"||CA(r))return r;let n=t.env??process.env,i=t.homeDirectory??(0,G0.homedir)(),s=t.pathExists??zt.existsSync,o=t.lookupInPath??NK,a=[n.BUN,n.BUN_PATH,yi.default.join(i,".bun","bin","bun.exe"),yi.default.join(i,".bun","bin","bun"),n.USERPROFILE?yi.default.join(n.USERPROFILE,".bun","bin","bun.exe"):void 0,n.LOCALAPPDATA?yi.default.join(n.LOCALAPPDATA,"bun","bun.exe"):void 0,n.LOCALAPPDATA?yi.default.join(n.LOCALAPPDATA,"bun","bin","bun.exe"):void 0];for(let c of a){let u=c?.trim();if(u&&(CA(u)&&s(u)||u.toLowerCase()==="bun"))return u}return o("bun",e)}function NA(t){(0,zt.mkdirSync)(W0,{recursive:!0}),(0,zt.writeFileSync)(_i,JSON.stringify(t,null,2))}function K0(){if(!(0,zt.existsSync)(_i))return null;try{return JSON.parse((0,zt.readFileSync)(_i,"utf-8"))}catch(t){return y.warn("SYSTEM","Failed to parse PID file",{path:_i},t),null}}function yo(){if((0,zt.existsSync)(_i))try{(0,zt.unlinkSync)(_i)}catch(t){y.warn("SYSTEM","Failed to remove PID file",{path:_i},t)}}function es(t){return process.platform==="win32"?Math.round(t*2):t}function DK(t){if(!t||t.trim()==="")return-1;let e=t.trim(),r=0,n=e.match(/^(\d+)-(\d+):(\d+):(\d+)$/);if(n)return r=parseInt(n[1],10)*24*60+parseInt(n[2],10)*60+parseInt(n[3],10),r;let i=e.match(/^(\d+):(\d+):(\d+)$/);if(i)return r=parseInt(i[1],10)*60+parseInt(i[2],10),r;let s=e.match(/^(\d+):(\d+)$/);return s?parseInt(s[1],10):-1}var V0=["worker-service.cjs","chroma-mcp"],jK=["mcp-server.cjs"];async function MA(){let t=process.platform==="win32",e=process.pid,r=[],n=[...V0,...jK];try{if(t){let s=`powershell -NoProfile -NonInteractive -Command "Get-CimInstance Win32_Process -Filter '(${n.map(l=>`CommandLine LIKE '%${l}%'`).join(" OR ")}) AND ProcessId != ${e}' | Select-Object ProcessId, CommandLine, CreationDate | ConvertTo-Json"`,{stdout:o}=await OA(s,{timeout:_r.POWERSHELL_COMMAND,windowsHide:!0});if(!o.trim()||o.trim()==="null"){y.debug("SYSTEM","No orphaned claude-mem processes found (Windows)");return}let a=JSON.parse(o),c=Array.isArray(a)?a:[a],u=Date.now();for(let l of c){let d=l.ProcessId;if(!Number.isInteger(d)||d<=0||d===e)continue;let p=l.CommandLine||"";if(V0.some(f=>p.includes(f)))r.push(d),y.debug("SYSTEM","Found orphaned process (aggressive)",{pid:d,commandLine:p.substring(0,80)});else{let f=l.CreationDate?.match(/\/Date\((\d+)\)\//);if(f){let g=parseInt(f[1],10),h=(u-g)/(1e3*60);h>=PA&&(r.push(d),y.debug("SYSTEM","Found orphaned process (age-gated)",{pid:d,ageMinutes:Math.round(h)}))}}}}else{let i=n.join("|"),{stdout:s}=await OA(`ps -eo pid,etime,command | grep -E "${i}" | grep -v grep || true`);if(!s.trim()){y.debug("SYSTEM","No orphaned claude-mem processes found (Unix)");return}let o=s.trim().split(` -`);for(let a of o){let c=a.trim().match(/^(\d+)\s+(\S+)\s+(.*)$/);if(!c)continue;let u=parseInt(c[1],10),l=c[2],d=c[3];if(!Number.isInteger(u)||u<=0||u===e)continue;if(V0.some(m=>d.includes(m)))r.push(u),y.debug("SYSTEM","Found orphaned process (aggressive)",{pid:u,command:d.substring(0,80)});else{let m=DK(l);m>=PA&&(r.push(u),y.debug("SYSTEM","Found orphaned process (age-gated)",{pid:u,ageMinutes:m,command:d.substring(0,80)}))}}}}catch(i){y.error("SYSTEM","Failed to enumerate orphaned processes during aggressive cleanup",{},i);return}if(r.length!==0){if(y.info("SYSTEM","Aggressive startup cleanup: killing orphaned processes",{platform:t?"Windows":"Unix",count:r.length,pids:r}),t){for(let i of r)if(!(!Number.isInteger(i)||i<=0))try{(0,Qi.execSync)(`taskkill /PID ${i} /T /F`,{timeout:_r.POWERSHELL_COMMAND,stdio:"ignore",windowsHide:!0})}catch(s){y.debug("SYSTEM","Failed to kill process, may have already exited",{pid:i},s)}}else for(let i of r)try{process.kill(i,"SIGKILL")}catch(s){y.debug("SYSTEM","Process already exited",{pid:i},s)}y.info("SYSTEM","Aggressive startup cleanup complete",{count:r.length})}}var zK=".chroma-cleaned-v10.3";function DA(t){let e=t??W0,r=yi.default.join(e,zK),n=yi.default.join(e,"chroma");if((0,zt.existsSync)(r)){y.debug("SYSTEM","Chroma migration marker exists, skipping wipe");return}y.warn("SYSTEM","Running one-time chroma data wipe (upgrade from pre-v10.3)",{chromaDir:n}),(0,zt.existsSync)(n)&&((0,zt.rmSync)(n,{recursive:!0,force:!0}),y.info("SYSTEM","Chroma data directory removed",{chromaDir:n})),(0,zt.mkdirSync)(e,{recursive:!0}),(0,zt.writeFileSync)(r,new Date().toISOString()),y.info("SYSTEM","Chroma migration marker written",{markerPath:r})}function J0(t,e,r={}){let n=process.platform==="win32";gt().assertCanSpawn("worker daemon");let i=vi({...process.env,CLAUDE_MEM_WORKER_PORT:String(e),...r});if(n){let a=MK();if(!a){y.error("SYSTEM","Failed to locate Bun runtime for Windows worker spawn");return}let c=a.replace(/'/g,"''"),u=t.replace(/'/g,"''"),l=`Start-Process -FilePath '${c}' -ArgumentList '${u}','--daemon' -WindowStyle Hidden`;try{return(0,Qi.execSync)(`powershell -NoProfile -Command "${l}"`,{stdio:"ignore",windowsHide:!0,env:i}),0}catch(d){y.error("SYSTEM","Failed to spawn worker daemon on Windows",{runtimePath:a},d);return}}let s="/usr/bin/setsid";if((0,zt.existsSync)(s)){let a=(0,Qi.spawn)(s,[process.execPath,t,"--daemon"],{detached:!0,stdio:"ignore",env:i});return a.pid===void 0?void 0:(a.unref(),a.pid)}let o=(0,Qi.spawn)(process.execPath,[t,"--daemon"],{detached:!0,stdio:"ignore",env:i});if(o.pid!==void 0)return o.unref(),o.pid}function jA(t){if(t===0)return!0;if(!Number.isInteger(t)||t<0)return!1;try{return process.kill(t,0),!0}catch(e){return e.code==="EPERM"}}function zA(t=15e3){try{let e=(0,zt.statSync)(_i);return Date.now()-e.mtimeMssetTimeout(s,500))}return!1}function _o(t,e=3e4){return HA(t,"/api/health",e,"Service not ready yet, will retry")}function ZA(t,e=3e4){return HA(t,"/api/readiness",e,"Worker not ready yet, will retry")}async function Bf(t,e=1e4){let r=Date.now();for(;Date.now()-rsetTimeout(n,500))}return!1}async function Vf(t){try{let e=await X0(t,"/api/admin/shutdown","POST");return e.ok?!0:(y.warn("SYSTEM","Shutdown request returned error",{status:e.statusCode}),!1)}catch(e){return e instanceof Error&&e.message?.includes("ECONNREFUSED")?(y.debug("SYSTEM","Worker already stopped",{},e),!1):(y.error("SYSTEM","Shutdown request failed unexpectedly",{},e),!1)}}function LK(){try{let t=qA.default.join(Ki,"package.json");return JSON.parse((0,FA.readFileSync)(t,"utf-8")).version}catch(t){let e=t.code;if(e==="ENOENT"||e==="EBUSY")return y.debug("SYSTEM","Could not read plugin version (shutdown race)",{code:e}),"unknown";throw t}}async function UK(t){try{let e=await X0(t,"/api/version");return e.ok?JSON.parse(e.body).version:null}catch{return y.debug("SYSTEM","Could not fetch worker version",{}),null}}async function BA(t){let e=LK(),r=await UK(t);return!r||e==="unknown"?{matches:!0,pluginVersion:e,workerVersion:r}:{matches:e===r,pluginVersion:e,workerVersion:r}}oe();async function VA(t){y.info("SYSTEM","Shutdown initiated"),t.server&&(await qK(t.server),y.info("SYSTEM","HTTP server closed")),await t.sessionManager.shutdownAll(),t.mcpClient&&(await t.mcpClient.close(),y.info("SYSTEM","MCP client closed")),t.chromaMcpManager&&(y.info("SHUTDOWN","Stopping Chroma MCP connection..."),await t.chromaMcpManager.stop(),y.info("SHUTDOWN","Chroma MCP connection stopped")),t.dbManager&&await t.dbManager.close(),await SA(),y.info("SYSTEM","Worker shutdown complete")}async function qK(t){t.closeAllConnections(),process.platform==="win32"&&await new Promise(e=>setTimeout(e,500)),await new Promise((e,r)=>{t.close(n=>n?r(n):e())}),process.platform==="win32"&&(await new Promise(e=>setTimeout(e,500)),y.info("SYSTEM","Waited for Windows port cleanup"))}var rU=Ge(Qh(),1),nk=Ge(require("fs"),1),Pd=Ge(require("path"),1);var HL=["search","context","summarize","import","export"],ZL=["workflow","search_params","examples","all"];oe();var ek=Ge(Qh(),1),JL=Ge(KL(),1),XL=Ge(require("path"),1);Dt();oe();function tk(t){let e=[];e.push(ek.default.json({limit:"50mb"})),e.push((0,JL.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(f=>i.path.endsWith(f)),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);y.debug("HTTP",`\u2192 ${i.method} ${i.path}`,{requestId:d},p);let m=s.send.bind(s);s.send=function(f){let g=Date.now()-l;return y.debug("HTTP",`\u2190 ${s.statusCode} ${i.path}`,{requestId:d,duration:`${g}ms`}),m(f)},o()});let r=Qr(),n=XL.default.join(r,"plugin","ui");return e.push(ek.default.static(n)),e}function Od(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")){y.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 rk(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=${y.formatTool(n,i)}`}return e.includes("/summarize")?"requesting summary":""}oe();var wc=class extends Error{constructor(r,n=500,i,s){super(r);this.statusCode=n;this.code=i;this.details=s;this.name="AppError"}};function YL(t,e,r,n){let i={error:t,message:e};return r&&(i.code=r),n&&(i.details=n),i}var QL=(t,e,r,n)=>{let i=t instanceof wc?t.statusCode:500;y.error("HTTP",`Error handling ${e.method} ${e.path}`,{statusCode:i,error:t.message,code:t instanceof wc?t.code:void 0},t);let s=YL(t.name||"Error",t.message,t instanceof wc?t.code:void 0,t instanceof wc?t.details:void 0);r.status(i).json(s)};function eU(t,e){e.status(404).json(YL("NotFound",`Cannot ${t.method} ${t.path}`))}var tU="10.6.1",eg=class{app;server=null;options;startTime=Date.now();constructor(e){this.options=e,this.app=(0,rU.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,()=>{y.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,y.info("SYSTEM","HTTP server closed"))}registerRoutes(e){e.setupRoutes(this.app)}finalizeRoutes(){this.app.use(eU),this.app.use(QL)}setupMiddleware(){tk(rk).forEach(r=>this.app.use(r))}setupCoreRoutes(){this.app.get("/api/health",(e,r)=>{r.status(200).json({status:"ok",version:tU,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:tU})}),this.app.get("/api/instructions",async(e,r)=>{let n=e.query.topic||"all",i=e.query.operation;if(n&&!ZL.includes(n))return r.status(400).json({error:"Invalid topic"});try{let s;if(i){if(!HL.includes(i))return r.status(400).json({error:"Invalid operation"});let o=Pd.default.resolve(__dirname,"../skills/mem-search/operations"),a=Pd.default.resolve(o,`${i}.md`);if(!a.startsWith(o+Pd.default.sep))return r.status(400).json({error:"Invalid request"});s=await nk.promises.readFile(a,"utf-8")}else{let o=Pd.default.join(__dirname,"../skills/mem-search/SKILL.md"),a=await nk.promises.readFile(o,"utf-8");s=this.extractInstructionSection(a,n)}r.json({content:[{type:"text",text:s}]})}catch{r.status(404).json({error:"Instruction not found"})}}),this.app.post("/api/admin/restart",Od,async(e,r)=>{r.json({status:"restarting"}),process.platform==="win32"&&process.env.CLAUDE_MEM_MANAGED==="true"&&process.send?(y.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",Od,async(e,r)=>{r.json({status:"shutting_down"}),process.platform==="win32"&&process.env.CLAUDE_MEM_MANAGED==="true"&&process.send?(y.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",Od,(e,r)=>{let o=gt().getRegistry().getAll().map(f=>({id:f.id,pid:f.pid,type:f.type,status:vn(f.pid)?"alive":"dead",startedAt:f.startedAt})),a=o.filter(f=>f.status==="dead").map(f=>f.pid),c=!Object.keys(process.env).some(f=>M0.has(f)||N0.some(g=>f.startsWith(g))),u=Date.now()-this.startTime,l=Math.floor(u/1e3),d=Math.floor(l/3600),p=Math.floor(l%3600/60),m=d>0?`${d}h ${p}m`:`${p}m`;r.json({supervisor:{running:!0,pid:process.pid,uptime:m},processes:o,health:{deadProcessPids:a,envClean:c}})})}extractInstructionSection(e,r){let 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 yt=Ge(require("path"),1),Ad=require("os"),Kt=require("fs"),sU=require("child_process"),oU=require("util");oe();qr();Dt();var Dn=require("fs"),Cd=require("path");oe();function nU(t){try{return(0,Dn.existsSync)(t)?JSON.parse((0,Dn.readFileSync)(t,"utf-8")):{}}catch(e){return y.error("CONFIG","Failed to read Cursor registry, using empty registry",{file:t,error:e instanceof Error?e.message:String(e)}),{}}}function iU(t,e){let r=(0,Cd.join)(t,"..");(0,Dn.mkdirSync)(r,{recursive:!0}),(0,Dn.writeFileSync)(t,JSON.stringify(e,null,2))}function ik(t,e){let r=(0,Cd.join)(t,".cursor","rules"),n=(0,Cd.join)(r,"claude-mem-context.mdc"),i=`${n}.tmp`;(0,Dn.mkdirSync)(r,{recursive:!0});let s=`--- +`);for(let a of o){let c=a.trim().match(/^(\d+)\s+(\S+)\s+(.*)$/);if(!c)continue;let u=parseInt(c[1],10),l=c[2],d=c[3];if(!Number.isInteger(u)||u<=0||u===e)continue;if(V0.some(m=>d.includes(m)))r.push(u),y.debug("SYSTEM","Found orphaned process (aggressive)",{pid:u,command:d.substring(0,80)});else{let m=DK(l);m>=PA&&(r.push(u),y.debug("SYSTEM","Found orphaned process (age-gated)",{pid:u,ageMinutes:m,command:d.substring(0,80)}))}}}}catch(i){y.error("SYSTEM","Failed to enumerate orphaned processes during aggressive cleanup",{},i);return}if(r.length!==0){if(y.info("SYSTEM","Aggressive startup cleanup: killing orphaned processes",{platform:t?"Windows":"Unix",count:r.length,pids:r}),t){for(let i of r)if(!(!Number.isInteger(i)||i<=0))try{(0,Qi.execSync)(`taskkill /PID ${i} /T /F`,{timeout:_r.POWERSHELL_COMMAND,stdio:"ignore",windowsHide:!0})}catch(s){y.debug("SYSTEM","Failed to kill process, may have already exited",{pid:i},s)}}else for(let i of r)try{process.kill(i,"SIGKILL")}catch(s){y.debug("SYSTEM","Process already exited",{pid:i},s)}y.info("SYSTEM","Aggressive startup cleanup complete",{count:r.length})}}var zK=".chroma-cleaned-v10.3";function DA(t){let e=t??W0,r=yi.default.join(e,zK),n=yi.default.join(e,"chroma");if((0,zt.existsSync)(r)){y.debug("SYSTEM","Chroma migration marker exists, skipping wipe");return}y.warn("SYSTEM","Running one-time chroma data wipe (upgrade from pre-v10.3)",{chromaDir:n}),(0,zt.existsSync)(n)&&((0,zt.rmSync)(n,{recursive:!0,force:!0}),y.info("SYSTEM","Chroma data directory removed",{chromaDir:n})),(0,zt.mkdirSync)(e,{recursive:!0}),(0,zt.writeFileSync)(r,new Date().toISOString()),y.info("SYSTEM","Chroma migration marker written",{markerPath:r})}function J0(t,e,r={}){let n=process.platform==="win32";gt().assertCanSpawn("worker daemon");let i=vi({...process.env,CLAUDE_MEM_WORKER_PORT:String(e),...r});if(n){let a=MK();if(!a){y.error("SYSTEM","Failed to locate Bun runtime for Windows worker spawn");return}let c=a.replace(/'/g,"''"),u=t.replace(/'/g,"''"),l=`Start-Process -FilePath '${c}' -ArgumentList '${u}','--daemon' -WindowStyle Hidden`;try{return(0,Qi.execSync)(`powershell -NoProfile -Command "${l}"`,{stdio:"ignore",windowsHide:!0,env:i}),0}catch(d){y.error("SYSTEM","Failed to spawn worker daemon on Windows",{runtimePath:a},d);return}}let s="/usr/bin/setsid";if((0,zt.existsSync)(s)){let a=(0,Qi.spawn)(s,[process.execPath,t,"--daemon"],{detached:!0,stdio:"ignore",env:i});return a.pid===void 0?void 0:(a.unref(),a.pid)}let o=(0,Qi.spawn)(process.execPath,[t,"--daemon"],{detached:!0,stdio:"ignore",env:i});if(o.pid!==void 0)return o.unref(),o.pid}function jA(t){if(t===0)return!0;if(!Number.isInteger(t)||t<0)return!1;try{return process.kill(t,0),!0}catch(e){return e.code==="EPERM"}}function zA(t=15e3){try{let e=(0,zt.statSync)(_i);return Date.now()-e.mtimeMssetTimeout(s,500))}return!1}function _o(t,e=3e4){return HA(t,"/api/health",e,"Service not ready yet, will retry")}function ZA(t,e=3e4){return HA(t,"/api/readiness",e,"Worker not ready yet, will retry")}async function Bf(t,e=1e4){let r=Date.now();for(;Date.now()-rsetTimeout(n,500))}return!1}async function Vf(t){try{let e=await X0(t,"/api/admin/shutdown","POST");return e.ok?!0:(y.warn("SYSTEM","Shutdown request returned error",{status:e.statusCode}),!1)}catch(e){return e instanceof Error&&e.message?.includes("ECONNREFUSED")?(y.debug("SYSTEM","Worker already stopped",{},e),!1):(y.error("SYSTEM","Shutdown request failed unexpectedly",{},e),!1)}}function LK(){try{let t=qA.default.join(Ki,"package.json");return JSON.parse((0,FA.readFileSync)(t,"utf-8")).version}catch(t){let e=t.code;if(e==="ENOENT"||e==="EBUSY")return y.debug("SYSTEM","Could not read plugin version (shutdown race)",{code:e}),"unknown";throw t}}async function UK(t){try{let e=await X0(t,"/api/version");return e.ok?JSON.parse(e.body).version:null}catch{return y.debug("SYSTEM","Could not fetch worker version",{}),null}}async function BA(t){let e=LK(),r=await UK(t);return!r||e==="unknown"?{matches:!0,pluginVersion:e,workerVersion:r}:{matches:e===r,pluginVersion:e,workerVersion:r}}oe();async function VA(t){y.info("SYSTEM","Shutdown initiated"),t.server&&(await qK(t.server),y.info("SYSTEM","HTTP server closed")),await t.sessionManager.shutdownAll(),t.mcpClient&&(await t.mcpClient.close(),y.info("SYSTEM","MCP client closed")),t.chromaMcpManager&&(y.info("SHUTDOWN","Stopping Chroma MCP connection..."),await t.chromaMcpManager.stop(),y.info("SHUTDOWN","Chroma MCP connection stopped")),t.dbManager&&await t.dbManager.close(),await SA(),y.info("SYSTEM","Worker shutdown complete")}async function qK(t){t.closeAllConnections(),process.platform==="win32"&&await new Promise(e=>setTimeout(e,500)),await new Promise((e,r)=>{t.close(n=>n?r(n):e())}),process.platform==="win32"&&(await new Promise(e=>setTimeout(e,500)),y.info("SYSTEM","Waited for Windows port cleanup"))}var rU=Ge(Qh(),1),nk=Ge(require("fs"),1),Pd=Ge(require("path"),1);var HL=["search","context","summarize","import","export"],ZL=["workflow","search_params","examples","all"];oe();var ek=Ge(Qh(),1),JL=Ge(KL(),1),XL=Ge(require("path"),1);Dt();oe();function tk(t){let e=[];e.push(ek.default.json({limit:"50mb"})),e.push((0,JL.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(f=>i.path.endsWith(f)),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);y.debug("HTTP",`\u2192 ${i.method} ${i.path}`,{requestId:d},p);let m=s.send.bind(s);s.send=function(f){let g=Date.now()-l;return y.debug("HTTP",`\u2190 ${s.statusCode} ${i.path}`,{requestId:d,duration:`${g}ms`}),m(f)},o()});let r=Qr(),n=XL.default.join(r,"plugin","ui");return e.push(ek.default.static(n)),e}function Od(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")){y.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 rk(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=${y.formatTool(n,i)}`}return e.includes("/summarize")?"requesting summary":""}oe();var wc=class extends Error{constructor(r,n=500,i,s){super(r);this.statusCode=n;this.code=i;this.details=s;this.name="AppError"}};function YL(t,e,r,n){let i={error:t,message:e};return r&&(i.code=r),n&&(i.details=n),i}var QL=(t,e,r,n)=>{let i=t instanceof wc?t.statusCode:500;y.error("HTTP",`Error handling ${e.method} ${e.path}`,{statusCode:i,error:t.message,code:t instanceof wc?t.code:void 0},t);let s=YL(t.name||"Error",t.message,t instanceof wc?t.code:void 0,t instanceof wc?t.details:void 0);r.status(i).json(s)};function eU(t,e){e.status(404).json(YL("NotFound",`Cannot ${t.method} ${t.path}`))}var tU="10.6.2",eg=class{app;server=null;options;startTime=Date.now();constructor(e){this.options=e,this.app=(0,rU.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,()=>{y.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,y.info("SYSTEM","HTTP server closed"))}registerRoutes(e){e.setupRoutes(this.app)}finalizeRoutes(){this.app.use(eU),this.app.use(QL)}setupMiddleware(){tk(rk).forEach(r=>this.app.use(r))}setupCoreRoutes(){this.app.get("/api/health",(e,r)=>{r.status(200).json({status:"ok",version:tU,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:tU})}),this.app.get("/api/instructions",async(e,r)=>{let n=e.query.topic||"all",i=e.query.operation;if(n&&!ZL.includes(n))return r.status(400).json({error:"Invalid topic"});try{let s;if(i){if(!HL.includes(i))return r.status(400).json({error:"Invalid operation"});let o=Pd.default.resolve(__dirname,"../skills/mem-search/operations"),a=Pd.default.resolve(o,`${i}.md`);if(!a.startsWith(o+Pd.default.sep))return r.status(400).json({error:"Invalid request"});s=await nk.promises.readFile(a,"utf-8")}else{let o=Pd.default.join(__dirname,"../skills/mem-search/SKILL.md"),a=await nk.promises.readFile(o,"utf-8");s=this.extractInstructionSection(a,n)}r.json({content:[{type:"text",text:s}]})}catch{r.status(404).json({error:"Instruction not found"})}}),this.app.post("/api/admin/restart",Od,async(e,r)=>{r.json({status:"restarting"}),process.platform==="win32"&&process.env.CLAUDE_MEM_MANAGED==="true"&&process.send?(y.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",Od,async(e,r)=>{r.json({status:"shutting_down"}),process.platform==="win32"&&process.env.CLAUDE_MEM_MANAGED==="true"&&process.send?(y.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",Od,(e,r)=>{let o=gt().getRegistry().getAll().map(f=>({id:f.id,pid:f.pid,type:f.type,status:vn(f.pid)?"alive":"dead",startedAt:f.startedAt})),a=o.filter(f=>f.status==="dead").map(f=>f.pid),c=!Object.keys(process.env).some(f=>M0.has(f)||N0.some(g=>f.startsWith(g))),u=Date.now()-this.startTime,l=Math.floor(u/1e3),d=Math.floor(l/3600),p=Math.floor(l%3600/60),m=d>0?`${d}h ${p}m`:`${p}m`;r.json({supervisor:{running:!0,pid:process.pid,uptime:m},processes:o,health:{deadProcessPids:a,envClean:c}})})}extractInstructionSection(e,r){let 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 yt=Ge(require("path"),1),Ad=require("os"),Kt=require("fs"),sU=require("child_process"),oU=require("util");oe();qr();Dt();var Dn=require("fs"),Cd=require("path");oe();function nU(t){try{return(0,Dn.existsSync)(t)?JSON.parse((0,Dn.readFileSync)(t,"utf-8")):{}}catch(e){return y.error("CONFIG","Failed to read Cursor registry, using empty registry",{file:t,error:e instanceof Error?e.message:String(e)}),{}}}function iU(t,e){let r=(0,Cd.join)(t,"..");(0,Dn.mkdirSync)(r,{recursive:!0}),(0,Dn.writeFileSync)(t,JSON.stringify(e,null,2))}function ik(t,e){let r=(0,Cd.join)(t,".cursor","rules"),n=(0,Cd.join)(r,"claude-mem-context.mdc"),i=`${n}.tmp`;(0,Dn.mkdirSync)(r,{recursive:!0});let s=`--- alwaysApply: true description: "Claude-mem context from past sessions (auto-updated)" --- @@ -1428,7 +1428,7 @@ Tips: `&&u++;if(u>=e||f===0)break;a=Math.min(a*2,i,o)}let l=c.split(` `);l.length>0&&l[l.length-1]===""&&l.pop();let d=Math.max(0,l.length-e),p=l.slice(d),m;if(i<=a)m=l.length;else{let f=c.length/Math.max(u,1);m=Math.round(i/f)}return{lines:p.join(` `),totalEstimate:m}}finally{(0,xn.closeSync)(r)}}var fv=class extends Cr{getLogFilePath(){let e=Ee.get("CLAUDE_MEM_DATA_DIR"),r=(0,mv.join)(e,"logs"),n=new Date().toISOString().split("T")[0];return(0,mv.join)(r,`claude-mem-${n}.log`)}getLogsDir(){let e=Ee.get("CLAUDE_MEM_DATA_DIR");return(0,mv.join)(e,"logs")}setupRoutes(e){e.get("/api/logs",this.handleGetLogs.bind(this)),e.post("/api/logs/clear",this.handleClearLogs.bind(this))}handleGetLogs=this.wrapHandler((e,r)=>{let n=this.getLogFilePath();if(!(0,xn.existsSync)(n)){r.json({logs:"",path:n,exists:!1});return}let i=parseInt(e.query.lines||"1000",10),s=Math.min(i,1e4),{lines:o,totalEstimate:a}=sge(n,s),c=o===""?0:o.split(` -`).length;r.json({logs:o,path:n,exists:!0,totalLines:a,returnedLines:c})});handleClearLogs=this.wrapHandler((e,r)=>{let n=this.getLogFilePath();if(!(0,xn.existsSync)(n)){r.json({success:!0,message:"Log file does not exist",path:n});return}(0,xn.writeFileSync)(n,"","utf-8"),y.info("SYSTEM","Log file cleared via UI",{path:n}),r.json({success:!0,message:"Log file cleared",path:n})})};oe();var hv=class extends Cr{constructor(r,n){super();this.dbManager=r;this.defaultProject=n}setupRoutes(r){r.post("/api/memory/save",this.handleSaveMemory.bind(this))}handleSaveMemory=this.wrapHandler(async(r,n)=>{let{text:i,title:s,project:o}=r.body,a=o||this.defaultProject;if(!i||typeof i!="string"||i.trim().length===0){this.badRequest(n,"text is required and must be non-empty");return}let c=this.dbManager.getSessionStore(),u=this.dbManager.getChromaSync(),l=c.getOrCreateManualSession(a),d={type:"discovery",title:s||i.substring(0,60).trim()+(i.length>60?"...":""),subtitle:"Manual memory",facts:[],narrative:i,concepts:[],files_read:[],files_modified:[]},p=c.storeObservation(l,a,d,0,0);y.info("HTTP","Manual observation saved",{id:p.id,project:a,title:d.title}),u.syncObservation(p.id,l,a,d,0,p.createdAtEpoch,0).catch(m=>{y.error("CHROMA","ChromaDB sync failed",{id:p.id},m)}),n.json({success:!0,id:p.id,title:d.title,project:a,message:`Memory saved as observation #${p.id}`})})};var Nge={},$ge=120*1e3;function F$(){return q$.default.join(Ee.get("CLAUDE_MEM_DATA_DIR"),".worker-start-attempted")}function Tge(){if(process.platform!=="win32")return!1;let t=F$();if(!(0,ms.existsSync)(t))return!1;try{let e=(0,ms.statSync)(t).mtimeMs;return Date.now()-e<$ge}catch{return!1}}function Ige(){if(process.platform==="win32")try{(0,ms.writeFileSync)(F$(),"","utf-8")}catch{}}function Rge(){if(process.platform==="win32")try{let t=F$();(0,ms.existsSync)(t)&&(0,ms.unlinkSync)(t)}catch{}}var Oge="10.6.1";function U9(t,e){return{continue:!0,suppressOutput:!0,status:t,...e&&{message:e}}}var yv=class{server;startTime=Date.now();mcpClient;mcpReady=!1;initializationCompleteFlag=!1;isShuttingDown=!1;dbManager;sessionManager;sseBroadcaster;sdkAgent;geminiAgent;openRouterAgent;paginationHelper;settingsManager;sessionEventBroadcaster;searchRoutes=null;chromaMcpManager=null;initializationComplete;resolveInitialization;stopOrphanReaper=null;staleSessionReaperInterval=null;lastAiInteraction=null;constructor(){this.initializationComplete=new Promise(e=>{this.resolveInitialization=e}),this.dbManager=new rg,this.sessionManager=new og(this.dbManager),this.sseBroadcaster=new ag,this.sdkAgent=new Lg(this.dbManager,this.sessionManager),this.geminiAgent=new Ug(this.dbManager,this.sessionManager),this.openRouterAgent=new Hg(this.dbManager,this.sessionManager),this.paginationHelper=new Zg(this.dbManager),this.settingsManager=new Bg(this.dbManager),this.sessionEventBroadcaster=new Kg(this.sseBroadcaster,this),this.sessionManager.setOnSessionDeleted(()=>{this.broadcastProcessingStatus()}),this.mcpClient=new Fa({name:"worker-search-proxy",version:Oge},{capabilities:{}}),this.server=new eg({getInitializationComplete:()=>this.initializationCompleteFlag,getMcpReady:()=>this.mcpReady,onShutdown:()=>this.shutdown(),onRestart:()=>this.shutdown(),workerPath:__filename,getAiStatus:()=>{let e="claude";return eu()&&Vo()?e="openrouter":Qc()&&Bo()&&(e="gemini"),{provider:e,authMethod:Df(),lastInteraction:this.lastAiInteraction?{timestamp:this.lastAiInteraction.timestamp,success:this.lastAiInteraction.success,...this.lastAiInteraction.error&&{error:this.lastAiInteraction.error}}:null}}}),this.registerRoutes(),this.registerSignalHandlers()}registerSignalHandlers(){wA(async()=>{this.isShuttingDown=!0,await this.shutdown()})}registerRoutes(){this.server.app.get("/api/context/inject",async(e,r,n)=>{if(!this.initializationCompleteFlag||!this.searchRoutes){y.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){y.error("HTTP",`Request to ${e.method} ${e.path} rejected \u2014 DB not initialized`,{},o),r.status(503).json({error:"Service initializing",message:"Database is still initializing, please retry"})}}),this.server.registerRoutes(new Xg(this.sseBroadcaster,this.dbManager,this.sessionManager)),this.server.registerRoutes(new ev(this.sessionManager,this.dbManager,this.sdkAgent,this.geminiAgent,this.openRouterAgent,this.sessionEventBroadcaster,this)),this.server.registerRoutes(new tv(this.paginationHelper,this.dbManager,this.sessionManager,this.sseBroadcaster,this,this.startTime)),this.server.registerRoutes(new pv(this.settingsManager)),this.server.registerRoutes(new fv),this.server.registerRoutes(new hv(this.dbManager,"claude-mem"))}async start(){let e=Ur(),r=O0();await xA(),await this.server.listen(e,r),NA({pid:process.pid,port:e,startedAt:new Date().toISOString()}),gt().registerProcess("worker",{pid:process.pid,type:"worker",startedAt:new Date().toISOString()}),y.info("SYSTEM","Worker started",{host:r,port:e,pid:process.pid}),this.initializeBackground().catch(n=>{y.error("SYSTEM","Background initialization failed",{},n)})}async initializeBackground(){try{await MA();let{ModeManager:e}=await Promise.resolve().then(()=>(Zr(),wU)),{SettingsDefaultsManager:r}=await Promise.resolve().then(()=>(tr(),JC)),{USER_SETTINGS_PATH:n}=await Promise.resolve().then(()=>(Dt(),iA)),i=r.loadFromFile(n);(i.CLAUDE_MEM_MODE==="local"||!i.CLAUDE_MEM_MODE)&&DA(),i.CLAUDE_MEM_CHROMA_ENABLED!=="false"?(this.chromaMcpManager=Xi.getInstance(),y.info("SYSTEM","ChromaMcpManager initialized (lazy - connects on first use)")):y.info("SYSTEM","Chroma disabled via CLAUDE_MEM_CHROMA_ENABLED=false, skipping ChromaMcpManager");let o=i.CLAUDE_MEM_MODE;e.getInstance().loadMode(o),y.info("SYSTEM",`Mode loaded: ${o}`),await this.dbManager.initialize();let{PendingMessageStore:a}=await Promise.resolve().then(()=>(jo(),Ec)),u=new a(this.dbManager.getSessionStore().db,3).resetStaleProcessingMessages(0);u>0&&y.info("SYSTEM",`Reset ${u} stale processing messages to pending`);let l=new Gg,d=new Wg,p=new Vg(this.dbManager.getSessionSearch(),this.dbManager.getSessionStore(),this.dbManager.getChromaSync(),l,d);this.searchRoutes=new uv(p),this.server.registerRoutes(this.searchRoutes),y.info("WORKER","SearchManager initialized and search routes registered"),this.initializationCompleteFlag=!0,this.resolveInitialization(),y.info("SYSTEM","Core initialization complete (DB + search ready)"),this.chromaMcpManager&&Ka.backfillAllProjects().then(()=>{y.info("CHROMA_SYNC","Backfill check complete for all projects")}).catch(_=>{y.error("CHROMA_SYNC","Backfill failed (non-blocking)",{},_)});let m=q$.default.join(__dirname,"mcp-server.cjs");gt().assertCanSpawn("mcp server");let f=new Ba({command:"node",args:[m],env:vi(process.env)}),g=3e5,h=this.mcpClient.connect(f),v,x=new Promise((_,S)=>{v=setTimeout(()=>S(new Error("MCP connection timeout after 5 minutes")),g)});try{await Promise.race([h,x])}catch(_){clearTimeout(v),y.warn("WORKER","MCP server connection failed, cleaning up subprocess",{error:_ instanceof Error?_.message:String(_)});try{await f.close()}catch{}throw _}clearTimeout(v);let b=f._process;b?.pid&&(gt().registerProcess("mcp-server",{pid:b.pid,type:"mcp",startedAt:new Date().toISOString()},b),b.once("exit",()=>{gt().unregisterProcess("mcp-server")})),this.mcpReady=!0,y.success("WORKER","MCP server connected"),this.stopOrphanReaper=xU(()=>{let _=new Set;for(let[S]of this.sessionManager.sessions)_.add(S);return _}),y.info("SYSTEM","Started orphan reaper (runs every 30 seconds)"),this.staleSessionReaperInterval=setInterval(async()=>{try{let _=await this.sessionManager.reapStaleSessions();_>0&&y.info("SYSTEM",`Reaped ${_} stale sessions`)}catch(_){y.error("SYSTEM","Stale session reaper error",{error:_ instanceof Error?_.message:String(_)})}},120*1e3),this.processPendingQueues(50).then(_=>{_.sessionsStarted>0&&y.info("SYSTEM",`Auto-recovered ${_.sessionsStarted} sessions with pending work`,{totalPending:_.totalPendingSessions,started:_.sessionsStarted,sessionIds:_.startedSessionIds})}).catch(_=>{y.error("SYSTEM","Auto-recovery of pending queues failed",{},_)})}catch(e){throw y.error("SYSTEM","Background initialization failed",{},e),e}}getActiveAgent(){return eu()&&Vo()?this.openRouterAgent:Qc()&&Bo()?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&&(y.debug("SYSTEM","Replacing aborted AbortController before starting generator",{sessionId:e.sessionDbId}),e.abortController=new AbortController);let o=!1,a=!1;y.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","FOREIGN KEY constraint failed"].some(d=>u.includes(d))){o=!0,this.lastAiInteraction={timestamp:Date.now(),success:!1,provider:s,error:u},y.error("SDK","Unrecoverable generator error - will NOT restart",{sessionId:e.sessionDbId,project:e.project,errorMessage:u});return}if(this.isSessionTerminatedError(c))return y.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(u.includes("aborted by user")||u.includes("No conversation found"))&&e.memorySessionId&&(y.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),y.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 qs(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 u=this.sessionManager.getPendingMessageStore();if(e.idleTimedOut){e.idleTimedOut=!1,this.terminateSession(e.sessionDbId,"idle_timeout");return}let l=u.getPendingCount(e.sessionDbId),d=3;if(l>0){if(e.consecutiveRestarts=(e.consecutiveRestarts||0)+1,e.consecutiveRestarts>d){y.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}y.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")}else e.consecutiveRestarts=0,this.sessionManager.removeSessionImmediate(e.sessionDbId);this.broadcastProcessingStatus()})}isSessionTerminatedError(e){let n=(e instanceof Error?e.message:String(e)).toLowerCase();return n.includes("process aborted by user")||n.includes("processtransport")||n.includes("not ready for writing")||n.includes("session generator failed")||n.includes("claude code process")}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(Bo())try{await this.geminiAgent.startSession(e,this);return}catch(o){y.warn("SDK","Fallback Gemini failed, trying OpenRouter",{sessionId:n,error:o instanceof Error?o.message:String(o)})}if(Vo())try{await this.openRouterAgent.startSession(e,this);return}catch(o){y.warn("SDK","Fallback OpenRouter failed",{sessionId:n,error:o instanceof Error?o.message:String(o)})}let s=this.sessionManager.getPendingMessageStore().markAllSessionMessagesAbandoned(n);s>0&&y.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);y.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(()=>(jo(),Ec)),n=new r(this.dbManager.getSessionStore().db,3),i=this.dbManager.getSessionStore(),s=360*60*1e3,o=Date.now()-s;try{let u=i.db.prepare(` +`).length;r.json({logs:o,path:n,exists:!0,totalLines:a,returnedLines:c})});handleClearLogs=this.wrapHandler((e,r)=>{let n=this.getLogFilePath();if(!(0,xn.existsSync)(n)){r.json({success:!0,message:"Log file does not exist",path:n});return}(0,xn.writeFileSync)(n,"","utf-8"),y.info("SYSTEM","Log file cleared via UI",{path:n}),r.json({success:!0,message:"Log file cleared",path:n})})};oe();var hv=class extends Cr{constructor(r,n){super();this.dbManager=r;this.defaultProject=n}setupRoutes(r){r.post("/api/memory/save",this.handleSaveMemory.bind(this))}handleSaveMemory=this.wrapHandler(async(r,n)=>{let{text:i,title:s,project:o}=r.body,a=o||this.defaultProject;if(!i||typeof i!="string"||i.trim().length===0){this.badRequest(n,"text is required and must be non-empty");return}let c=this.dbManager.getSessionStore(),u=this.dbManager.getChromaSync(),l=c.getOrCreateManualSession(a),d={type:"discovery",title:s||i.substring(0,60).trim()+(i.length>60?"...":""),subtitle:"Manual memory",facts:[],narrative:i,concepts:[],files_read:[],files_modified:[]},p=c.storeObservation(l,a,d,0,0);y.info("HTTP","Manual observation saved",{id:p.id,project:a,title:d.title}),u.syncObservation(p.id,l,a,d,0,p.createdAtEpoch,0).catch(m=>{y.error("CHROMA","ChromaDB sync failed",{id:p.id},m)}),n.json({success:!0,id:p.id,title:d.title,project:a,message:`Memory saved as observation #${p.id}`})})};var Nge={},$ge=120*1e3;function F$(){return q$.default.join(Ee.get("CLAUDE_MEM_DATA_DIR"),".worker-start-attempted")}function Tge(){if(process.platform!=="win32")return!1;let t=F$();if(!(0,ms.existsSync)(t))return!1;try{let e=(0,ms.statSync)(t).mtimeMs;return Date.now()-e<$ge}catch{return!1}}function Ige(){if(process.platform==="win32")try{(0,ms.writeFileSync)(F$(),"","utf-8")}catch{}}function Rge(){if(process.platform==="win32")try{let t=F$();(0,ms.existsSync)(t)&&(0,ms.unlinkSync)(t)}catch{}}var Oge="10.6.2";function U9(t,e){return{continue:!0,suppressOutput:!0,status:t,...e&&{message:e}}}var yv=class{server;startTime=Date.now();mcpClient;mcpReady=!1;initializationCompleteFlag=!1;isShuttingDown=!1;dbManager;sessionManager;sseBroadcaster;sdkAgent;geminiAgent;openRouterAgent;paginationHelper;settingsManager;sessionEventBroadcaster;searchRoutes=null;chromaMcpManager=null;initializationComplete;resolveInitialization;stopOrphanReaper=null;staleSessionReaperInterval=null;lastAiInteraction=null;constructor(){this.initializationComplete=new Promise(e=>{this.resolveInitialization=e}),this.dbManager=new rg,this.sessionManager=new og(this.dbManager),this.sseBroadcaster=new ag,this.sdkAgent=new Lg(this.dbManager,this.sessionManager),this.geminiAgent=new Ug(this.dbManager,this.sessionManager),this.openRouterAgent=new Hg(this.dbManager,this.sessionManager),this.paginationHelper=new Zg(this.dbManager),this.settingsManager=new Bg(this.dbManager),this.sessionEventBroadcaster=new Kg(this.sseBroadcaster,this),this.sessionManager.setOnSessionDeleted(()=>{this.broadcastProcessingStatus()}),this.mcpClient=new Fa({name:"worker-search-proxy",version:Oge},{capabilities:{}}),this.server=new eg({getInitializationComplete:()=>this.initializationCompleteFlag,getMcpReady:()=>this.mcpReady,onShutdown:()=>this.shutdown(),onRestart:()=>this.shutdown(),workerPath:__filename,getAiStatus:()=>{let e="claude";return eu()&&Vo()?e="openrouter":Qc()&&Bo()&&(e="gemini"),{provider:e,authMethod:Df(),lastInteraction:this.lastAiInteraction?{timestamp:this.lastAiInteraction.timestamp,success:this.lastAiInteraction.success,...this.lastAiInteraction.error&&{error:this.lastAiInteraction.error}}:null}}}),this.registerRoutes(),this.registerSignalHandlers()}registerSignalHandlers(){wA(async()=>{this.isShuttingDown=!0,await this.shutdown()})}registerRoutes(){this.server.app.get("/api/context/inject",async(e,r,n)=>{if(!this.initializationCompleteFlag||!this.searchRoutes){y.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){y.error("HTTP",`Request to ${e.method} ${e.path} rejected \u2014 DB not initialized`,{},o),r.status(503).json({error:"Service initializing",message:"Database is still initializing, please retry"})}}),this.server.registerRoutes(new Xg(this.sseBroadcaster,this.dbManager,this.sessionManager)),this.server.registerRoutes(new ev(this.sessionManager,this.dbManager,this.sdkAgent,this.geminiAgent,this.openRouterAgent,this.sessionEventBroadcaster,this)),this.server.registerRoutes(new tv(this.paginationHelper,this.dbManager,this.sessionManager,this.sseBroadcaster,this,this.startTime)),this.server.registerRoutes(new pv(this.settingsManager)),this.server.registerRoutes(new fv),this.server.registerRoutes(new hv(this.dbManager,"claude-mem"))}async start(){let e=Ur(),r=O0();await xA(),await this.server.listen(e,r),NA({pid:process.pid,port:e,startedAt:new Date().toISOString()}),gt().registerProcess("worker",{pid:process.pid,type:"worker",startedAt:new Date().toISOString()}),y.info("SYSTEM","Worker started",{host:r,port:e,pid:process.pid}),this.initializeBackground().catch(n=>{y.error("SYSTEM","Background initialization failed",{},n)})}async initializeBackground(){try{await MA();let{ModeManager:e}=await Promise.resolve().then(()=>(Zr(),wU)),{SettingsDefaultsManager:r}=await Promise.resolve().then(()=>(tr(),JC)),{USER_SETTINGS_PATH:n}=await Promise.resolve().then(()=>(Dt(),iA)),i=r.loadFromFile(n);(i.CLAUDE_MEM_MODE==="local"||!i.CLAUDE_MEM_MODE)&&DA(),i.CLAUDE_MEM_CHROMA_ENABLED!=="false"?(this.chromaMcpManager=Xi.getInstance(),y.info("SYSTEM","ChromaMcpManager initialized (lazy - connects on first use)")):y.info("SYSTEM","Chroma disabled via CLAUDE_MEM_CHROMA_ENABLED=false, skipping ChromaMcpManager");let o=i.CLAUDE_MEM_MODE;e.getInstance().loadMode(o),y.info("SYSTEM",`Mode loaded: ${o}`),await this.dbManager.initialize();let{PendingMessageStore:a}=await Promise.resolve().then(()=>(jo(),Ec)),u=new a(this.dbManager.getSessionStore().db,3).resetStaleProcessingMessages(0);u>0&&y.info("SYSTEM",`Reset ${u} stale processing messages to pending`);let l=new Gg,d=new Wg,p=new Vg(this.dbManager.getSessionSearch(),this.dbManager.getSessionStore(),this.dbManager.getChromaSync(),l,d);this.searchRoutes=new uv(p),this.server.registerRoutes(this.searchRoutes),y.info("WORKER","SearchManager initialized and search routes registered"),this.initializationCompleteFlag=!0,this.resolveInitialization(),y.info("SYSTEM","Core initialization complete (DB + search ready)"),this.chromaMcpManager&&Ka.backfillAllProjects().then(()=>{y.info("CHROMA_SYNC","Backfill check complete for all projects")}).catch(_=>{y.error("CHROMA_SYNC","Backfill failed (non-blocking)",{},_)});let m=q$.default.join(__dirname,"mcp-server.cjs");gt().assertCanSpawn("mcp server");let f=new Ba({command:"node",args:[m],env:vi(process.env)}),g=3e5,h=this.mcpClient.connect(f),v,x=new Promise((_,S)=>{v=setTimeout(()=>S(new Error("MCP connection timeout after 5 minutes")),g)});try{await Promise.race([h,x])}catch(_){clearTimeout(v),y.warn("WORKER","MCP server connection failed, cleaning up subprocess",{error:_ instanceof Error?_.message:String(_)});try{await f.close()}catch{}throw _}clearTimeout(v);let b=f._process;b?.pid&&(gt().registerProcess("mcp-server",{pid:b.pid,type:"mcp",startedAt:new Date().toISOString()},b),b.once("exit",()=>{gt().unregisterProcess("mcp-server")})),this.mcpReady=!0,y.success("WORKER","MCP server connected"),this.stopOrphanReaper=xU(()=>{let _=new Set;for(let[S]of this.sessionManager.sessions)_.add(S);return _}),y.info("SYSTEM","Started orphan reaper (runs every 30 seconds)"),this.staleSessionReaperInterval=setInterval(async()=>{try{let _=await this.sessionManager.reapStaleSessions();_>0&&y.info("SYSTEM",`Reaped ${_} stale sessions`)}catch(_){y.error("SYSTEM","Stale session reaper error",{error:_ instanceof Error?_.message:String(_)})}},120*1e3),this.processPendingQueues(50).then(_=>{_.sessionsStarted>0&&y.info("SYSTEM",`Auto-recovered ${_.sessionsStarted} sessions with pending work`,{totalPending:_.totalPendingSessions,started:_.sessionsStarted,sessionIds:_.startedSessionIds})}).catch(_=>{y.error("SYSTEM","Auto-recovery of pending queues failed",{},_)})}catch(e){throw y.error("SYSTEM","Background initialization failed",{},e),e}}getActiveAgent(){return eu()&&Vo()?this.openRouterAgent:Qc()&&Bo()?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&&(y.debug("SYSTEM","Replacing aborted AbortController before starting generator",{sessionId:e.sessionDbId}),e.abortController=new AbortController);let o=!1,a=!1;y.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","FOREIGN KEY constraint failed"].some(d=>u.includes(d))){o=!0,this.lastAiInteraction={timestamp:Date.now(),success:!1,provider:s,error:u},y.error("SDK","Unrecoverable generator error - will NOT restart",{sessionId:e.sessionDbId,project:e.project,errorMessage:u});return}if(this.isSessionTerminatedError(c))return y.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(u.includes("aborted by user")||u.includes("No conversation found"))&&e.memorySessionId&&(y.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),y.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 qs(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){y.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}y.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)})}isSessionTerminatedError(e){let n=(e instanceof Error?e.message:String(e)).toLowerCase();return n.includes("process aborted by user")||n.includes("processtransport")||n.includes("not ready for writing")||n.includes("session generator failed")||n.includes("claude code process")}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(Bo())try{await this.geminiAgent.startSession(e,this);return}catch(o){y.warn("SDK","Fallback Gemini failed, trying OpenRouter",{sessionId:n,error:o instanceof Error?o.message:String(o)})}if(Vo())try{await this.openRouterAgent.startSession(e,this);return}catch(o){y.warn("SDK","Fallback OpenRouter failed",{sessionId:n,error:o instanceof Error?o.message:String(o)})}let s=this.sessionManager.getPendingMessageStore().markAllSessionMessagesAbandoned(n);s>0&&y.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);y.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(()=>(jo(),Ec)),n=new r(this.dbManager.getSessionStore().db,3),i=this.dbManager.getSessionStore(),s=360*60*1e3,o=Date.now()-s;try{let u=i.db.prepare(` SELECT id FROM sdk_sessions WHERE status = 'active' AND started_at_epoch < ? `).all(o);if(u.length>0){let l=u.map(m=>m.id),d=l.map(()=>"?").join(",");i.db.prepare(` @@ -1440,7 +1440,7 @@ Tips: SET status = 'failed', failed_at_epoch = ? WHERE status = 'pending' AND session_db_id IN (${d}) - `).run(Date.now(),...l);p.changes>0&&y.info("SYSTEM",`Marked ${p.changes} pending messages from stale sessions as failed`)}}catch(u){y.error("SYSTEM","Failed to clean up stale sessions",{},u)}let a=n.getSessionsWithPendingMessages(),c={totalPendingSessions:a.length,sessionsStarted:0,sessionsSkipped:0,startedSessionIds:[]};if(a.length===0)return c;y.info("SYSTEM",`Processing up to ${e} of ${a.length} pending session queues`);for(let u of a){if(c.sessionsStarted>=e)break;try{if(this.sessionManager.getSession(u)?.generatorPromise){c.sessionsSkipped++;continue}let d=this.sessionManager.initializeSession(u);y.info("SYSTEM",`Starting processor for session ${u}`,{project:d.project,pendingCount:n.getPendingCount(u)}),this.startSessionProcessor(d,"startup-recovery"),c.sessionsStarted++,c.startedSessionIds.push(u),await new Promise(p=>setTimeout(p,100))}catch(l){y.error("SYSTEM",`Failed to process session ${u}`,{},l),c.sessionsSkipped++}}return c}async shutdown(){this.stopOrphanReaper&&(this.stopOrphanReaper(),this.stopOrphanReaper=null),this.staleSessionReaperInterval&&(clearInterval(this.staleSessionReaperInterval),this.staleSessionReaperInterval=null),await VA({server:this.server.getHttpServer(),sessionManager:this.sessionManager,mcpClient:this.mcpClient,dbManager:this.dbManager,chromaMcpManager:this.chromaMcpManager||void 0})}broadcastProcessingStatus(){let e=this.sessionManager.isAnySessionProcessing(),r=this.sessionManager.getTotalActiveWork(),n=this.sessionManager.getActiveSessionCount();y.info("WORKER","Broadcasting processing status",{isProcessing:e,queueDepth:r,activeSessions:n}),this.sseBroadcaster.broadcast({type:"processing_status",isProcessing:e,queueDepth:r})}};async function L9(t){if(UA()==="alive")return y.info("SYSTEM","Worker PID file points to a live process, skipping duplicate spawn"),await _o(t,es(_r.PORT_IN_USE_WAIT))?(y.info("SYSTEM","Worker became healthy while waiting on live PID"),!0):(y.warn("SYSTEM","Live PID detected but worker did not become healthy before timeout"),!1);if(await _o(t,1e3)){let o=await BA(t);if(o.matches)return y.info("SYSTEM","Worker already running and healthy"),!0;if(zA(15e3)){if(y.info("SYSTEM","Version mismatch detected but PID file is recent \u2014 another restart likely in progress, polling health",{pluginVersion:o.pluginVersion,workerVersion:o.workerVersion}),await _o(t,15e3))return y.info("SYSTEM","Worker became healthy after waiting for concurrent restart"),!0;y.warn("SYSTEM","Worker did not become healthy after waiting \u2014 proceeding with own restart")}if(y.info("SYSTEM","Worker version mismatch detected - auto-restarting",{pluginVersion:o.pluginVersion,workerVersion:o.workerVersion}),await Vf(t),!await Bf(t,es(_r.PORT_IN_USE_WAIT)))return y.error("SYSTEM","Port did not free up after shutdown for version mismatch restart",{port:t}),!1;yo()}return await Vl(t)?(y.info("SYSTEM","Port in use, waiting for worker to become healthy"),await _o(t,es(_r.PORT_IN_USE_WAIT))?(y.info("SYSTEM","Worker is now healthy"),!0):(y.error("SYSTEM","Port in use but worker not responding to health checks"),!1)):Tge()?(y.warn("SYSTEM","Worker unavailable on Windows \u2014 skipping spawn (recent attempt failed within cooldown)"),!1):(y.info("SYSTEM","Starting worker daemon"),Ige(),J0(__filename,t)===void 0?(y.error("SYSTEM","Failed to spawn worker daemon"),!1):await _o(t,es(_r.POST_SPAWN_WAIT))?(await ZA(t,es(_r.READINESS_WAIT))||y.warn("SYSTEM","Worker is alive but readiness timed out \u2014 proceeding anyway"),Rge(),LA(),y.info("SYSTEM","Worker started successfully"),!0):(yo(),y.error("SYSTEM","Worker failed to start (health check timeout)"),!1))}async function Pge(){let t=process.argv[2];(["start","hook","restart","--daemon"].includes(t)||t===void 0)&&Zf()&&process.exit(0);let r=Ur();function n(i,s){let o=U9(i,s);console.log(JSON.stringify(o)),process.exit(0)}switch(t){case"start":{await L9(r)?n("ready"):n("error","Failed to start worker");break}case"stop":{await Vf(r),await Bf(r,es(15e3))||y.warn("SYSTEM","Port did not free up after shutdown",{port:r}),yo(),y.info("SYSTEM","Worker stopped successfully"),process.exit(0);break}case"restart":{y.info("SYSTEM","Restarting worker"),await Vf(r),await Bf(r,es(15e3))||(y.error("SYSTEM","Port did not free up after shutdown, aborting restart",{port:r}),process.exit(0)),yo(),J0(__filename,r)===void 0&&(y.error("SYSTEM","Failed to spawn worker daemon during restart"),process.exit(0)),await _o(r,es(_r.POST_SPAWN_WAIT))||(yo(),y.error("SYSTEM","Worker failed to restart"),process.exit(0)),y.info("SYSTEM","Worker restarted successfully"),process.exit(0);break}case"status":{let i=await Vl(r),s=K0();i&&s?(console.log("Worker is running"),console.log(` PID: ${s.pid}`),console.log(` Port: ${s.port}`),console.log(` Started: ${s.startedAt}`)):console.log("Worker is not running"),process.exit(0);break}case"cursor":{let i=process.argv[3],s=await dU(i,process.argv.slice(4));process.exit(s);break}case"hook":{let i=process.argv[3],s=process.argv[4];(!i||!s)&&(console.error("Usage: claude-mem hook "),console.error("Platforms: claude-code, cursor, raw"),console.error("Events: context, session-init, observation, summarize, session-complete"),process.exit(1)),await L9(r)||y.warn("SYSTEM","Worker failed to start before hook, handler will proceed gracefully");let{hookCommand:a}=await Promise.resolve().then(()=>(N9(),A9));await a(i,s);break}case"generate":{let i=process.argv.includes("--dry-run"),{generateClaudeMd:s}=await Promise.resolve().then(()=>(U$(),L$)),o=await s(i);process.exit(o);break}case"clean":{let i=process.argv.includes("--dry-run"),{cleanClaudeMd:s}=await Promise.resolve().then(()=>(U$(),L$)),o=await s(i);process.exit(o);break}default:{let i=K0();i&&jA(i.pid)&&(y.info("SYSTEM","Worker already running (PID alive), refusing to start duplicate",{existingPid:i.pid,existingPort:i.port,startedAt:i.startedAt}),process.exit(0)),await Vl(r)&&(y.info("SYSTEM","Port already in use, refusing to start duplicate",{port:r}),process.exit(0)),process.on("unhandledRejection",o=>{y.error("SYSTEM","Unhandled rejection in daemon",{reason:o instanceof Error?o.message:String(o)})}),process.on("uncaughtException",o=>{y.error("SYSTEM","Uncaught exception in daemon",{},o)}),new yv().start().catch(o=>{y.failure("SYSTEM","Worker failed to start",{},o),yo(),process.exit(0)})}}}var Cge=typeof require<"u"&&typeof module<"u"?require.main===module||!module.parent:Nge.url===`file://${process.argv[1]}`||process.argv[1]?.endsWith("worker-service");Cge&&Pge().catch(t=>{y.error("SYSTEM","Fatal error in main",{},t instanceof Error?t:void 0),process.exit(0)});0&&(module.exports={WorkerService,buildStatusOutput,isPluginDisabledInClaudeSettings}); + `).run(Date.now(),...l);p.changes>0&&y.info("SYSTEM",`Marked ${p.changes} pending messages from stale sessions as failed`)}}catch(u){y.error("SYSTEM","Failed to clean up stale sessions",{},u)}let a=n.getSessionsWithPendingMessages(),c={totalPendingSessions:a.length,sessionsStarted:0,sessionsSkipped:0,startedSessionIds:[]};if(a.length===0)return c;y.info("SYSTEM",`Processing up to ${e} of ${a.length} pending session queues`);for(let u of a){if(c.sessionsStarted>=e)break;try{if(this.sessionManager.getSession(u)?.generatorPromise){c.sessionsSkipped++;continue}let d=this.sessionManager.initializeSession(u);y.info("SYSTEM",`Starting processor for session ${u}`,{project:d.project,pendingCount:n.getPendingCount(u)}),this.startSessionProcessor(d,"startup-recovery"),c.sessionsStarted++,c.startedSessionIds.push(u),await new Promise(p=>setTimeout(p,100))}catch(l){y.error("SYSTEM",`Failed to process session ${u}`,{},l),c.sessionsSkipped++}}return c}async shutdown(){this.stopOrphanReaper&&(this.stopOrphanReaper(),this.stopOrphanReaper=null),this.staleSessionReaperInterval&&(clearInterval(this.staleSessionReaperInterval),this.staleSessionReaperInterval=null),await VA({server:this.server.getHttpServer(),sessionManager:this.sessionManager,mcpClient:this.mcpClient,dbManager:this.dbManager,chromaMcpManager:this.chromaMcpManager||void 0})}broadcastProcessingStatus(){let e=this.sessionManager.getTotalActiveWork(),r=e>0,n=this.sessionManager.getActiveSessionCount();y.info("WORKER","Broadcasting processing status",{isProcessing:r,queueDepth:e,activeSessions:n}),this.sseBroadcaster.broadcast({type:"processing_status",isProcessing:r,queueDepth:e})}};async function L9(t){if(UA()==="alive")return y.info("SYSTEM","Worker PID file points to a live process, skipping duplicate spawn"),await _o(t,es(_r.PORT_IN_USE_WAIT))?(y.info("SYSTEM","Worker became healthy while waiting on live PID"),!0):(y.warn("SYSTEM","Live PID detected but worker did not become healthy before timeout"),!1);if(await _o(t,1e3)){let o=await BA(t);if(o.matches)return y.info("SYSTEM","Worker already running and healthy"),!0;if(zA(15e3)){if(y.info("SYSTEM","Version mismatch detected but PID file is recent \u2014 another restart likely in progress, polling health",{pluginVersion:o.pluginVersion,workerVersion:o.workerVersion}),await _o(t,15e3))return y.info("SYSTEM","Worker became healthy after waiting for concurrent restart"),!0;y.warn("SYSTEM","Worker did not become healthy after waiting \u2014 proceeding with own restart")}if(y.info("SYSTEM","Worker version mismatch detected - auto-restarting",{pluginVersion:o.pluginVersion,workerVersion:o.workerVersion}),await Vf(t),!await Bf(t,es(_r.PORT_IN_USE_WAIT)))return y.error("SYSTEM","Port did not free up after shutdown for version mismatch restart",{port:t}),!1;yo()}return await Vl(t)?(y.info("SYSTEM","Port in use, waiting for worker to become healthy"),await _o(t,es(_r.PORT_IN_USE_WAIT))?(y.info("SYSTEM","Worker is now healthy"),!0):(y.error("SYSTEM","Port in use but worker not responding to health checks"),!1)):Tge()?(y.warn("SYSTEM","Worker unavailable on Windows \u2014 skipping spawn (recent attempt failed within cooldown)"),!1):(y.info("SYSTEM","Starting worker daemon"),Ige(),J0(__filename,t)===void 0?(y.error("SYSTEM","Failed to spawn worker daemon"),!1):await _o(t,es(_r.POST_SPAWN_WAIT))?(await ZA(t,es(_r.READINESS_WAIT))||y.warn("SYSTEM","Worker is alive but readiness timed out \u2014 proceeding anyway"),Rge(),LA(),y.info("SYSTEM","Worker started successfully"),!0):(yo(),y.error("SYSTEM","Worker failed to start (health check timeout)"),!1))}async function Pge(){let t=process.argv[2];(["start","hook","restart","--daemon"].includes(t)||t===void 0)&&Zf()&&process.exit(0);let r=Ur();function n(i,s){let o=U9(i,s);console.log(JSON.stringify(o)),process.exit(0)}switch(t){case"start":{await L9(r)?n("ready"):n("error","Failed to start worker");break}case"stop":{await Vf(r),await Bf(r,es(15e3))||y.warn("SYSTEM","Port did not free up after shutdown",{port:r}),yo(),y.info("SYSTEM","Worker stopped successfully"),process.exit(0);break}case"restart":{y.info("SYSTEM","Restarting worker"),await Vf(r),await Bf(r,es(15e3))||(y.error("SYSTEM","Port did not free up after shutdown, aborting restart",{port:r}),process.exit(0)),yo(),J0(__filename,r)===void 0&&(y.error("SYSTEM","Failed to spawn worker daemon during restart"),process.exit(0)),await _o(r,es(_r.POST_SPAWN_WAIT))||(yo(),y.error("SYSTEM","Worker failed to restart"),process.exit(0)),y.info("SYSTEM","Worker restarted successfully"),process.exit(0);break}case"status":{let i=await Vl(r),s=K0();i&&s?(console.log("Worker is running"),console.log(` PID: ${s.pid}`),console.log(` Port: ${s.port}`),console.log(` Started: ${s.startedAt}`)):console.log("Worker is not running"),process.exit(0);break}case"cursor":{let i=process.argv[3],s=await dU(i,process.argv.slice(4));process.exit(s);break}case"hook":{let i=process.argv[3],s=process.argv[4];(!i||!s)&&(console.error("Usage: claude-mem hook "),console.error("Platforms: claude-code, cursor, raw"),console.error("Events: context, session-init, observation, summarize, session-complete"),process.exit(1)),await L9(r)||y.warn("SYSTEM","Worker failed to start before hook, handler will proceed gracefully");let{hookCommand:a}=await Promise.resolve().then(()=>(N9(),A9));await a(i,s);break}case"generate":{let i=process.argv.includes("--dry-run"),{generateClaudeMd:s}=await Promise.resolve().then(()=>(U$(),L$)),o=await s(i);process.exit(o);break}case"clean":{let i=process.argv.includes("--dry-run"),{cleanClaudeMd:s}=await Promise.resolve().then(()=>(U$(),L$)),o=await s(i);process.exit(o);break}default:{let i=K0();i&&jA(i.pid)&&(y.info("SYSTEM","Worker already running (PID alive), refusing to start duplicate",{existingPid:i.pid,existingPort:i.port,startedAt:i.startedAt}),process.exit(0)),await Vl(r)&&(y.info("SYSTEM","Port already in use, refusing to start duplicate",{port:r}),process.exit(0)),process.on("unhandledRejection",o=>{y.error("SYSTEM","Unhandled rejection in daemon",{reason:o instanceof Error?o.message:String(o)})}),process.on("uncaughtException",o=>{y.error("SYSTEM","Uncaught exception in daemon",{},o)}),new yv().start().catch(o=>{y.failure("SYSTEM","Worker failed to start",{},o),yo(),process.exit(0)})}}}var Cge=typeof require<"u"&&typeof module<"u"?require.main===module||!module.parent:Nge.url===`file://${process.argv[1]}`||process.argv[1]?.endsWith("worker-service");Cge&&Pge().catch(t=>{y.error("SYSTEM","Fatal error in main",{},t instanceof Error?t:void 0),process.exit(0)});0&&(module.exports={WorkerService,buildStatusOutput,isPluginDisabledInClaudeSettings}); /*! Bundled license information: depd/index.js: