diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 9fc4820c..f08757a1 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -10,7 +10,7 @@ "plugins": [ { "name": "claude-mem", - "version": "11.0.1", + "version": "12.0.0", "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 d84ee324..0efc4131 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "claude-mem", - "version": "11.0.1", + "version": "12.0.0", "description": "Memory compression system for Claude Code - persist context across sessions", "author": { "name": "Alex Newman" diff --git a/.claude/scheduled_tasks.lock b/.claude/scheduled_tasks.lock new file mode 100644 index 00000000..5cf85e7c --- /dev/null +++ b/.claude/scheduled_tasks.lock @@ -0,0 +1 @@ +{"sessionId":"e69a1f74-daa5-47f4-a6e8-ee55a9eebeaa","pid":82985,"acquiredAt":1775596215414} \ No newline at end of file diff --git a/.codex-plugin/plugin.json b/.codex-plugin/plugin.json index e9107755..c66c90d5 100644 --- a/.codex-plugin/plugin.json +++ b/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "claude-mem", - "version": "11.0.1", + "version": "12.0.0", "description": "Memory compression system for Claude Code - persist context across sessions", "author": { "name": "Alex Newman", diff --git a/package.json b/package.json index b54b1f1e..7819e832 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "claude-mem", - "version": "11.0.1", + "version": "12.0.0", "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 d6518dd9..98c83e53 100644 --- a/plugin/.claude-plugin/plugin.json +++ b/plugin/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "claude-mem", - "version": "11.0.1", + "version": "12.0.0", "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 5d2834bb..95a07c57 100644 --- a/plugin/package.json +++ b/plugin/package.json @@ -1,6 +1,6 @@ { "name": "claude-mem-plugin", - "version": "11.0.1", + "version": "12.0.0", "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 b79aeba6..b5b40b5c 100755 --- a/plugin/scripts/mcp-server.cjs +++ b/plugin/scripts/mcp-server.cjs @@ -1030,7 +1030,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);_.info("CHROMA_SYNC","Backfilling user prompts",{project:r,missing:v.length,existing:n.prompts.size,total:y.count});let b=[];for(let S of v)b.push(this.formatUserPromptDoc(S));for(let S=0;Ss.trim()).find(s=>s.length>0)||null}catch{return null}}function xee(t={}){let e=t.platform??process.platform,r=t.execPath??process.execPath;if(e!=="win32"||UD(r))return r;let n=t.env??process.env,i=t.homeDirectory??(0,Ck.homedir)(),s=t.pathExists??Ht.existsSync,o=t.lookupInPath??See,a=[n.BUN,n.BUN_PATH,Ki.default.join(i,".bun","bin","bun.exe"),Ki.default.join(i,".bun","bin","bun"),n.USERPROFILE?Ki.default.join(n.USERPROFILE,".bun","bin","bun.exe"):void 0,n.LOCALAPPDATA?Ki.default.join(n.LOCALAPPDATA,"bun","bun.exe"):void 0,n.LOCALAPPDATA?Ki.default.join(n.LOCALAPPDATA,"bun","bin","bun.exe"):void 0];for(let c of a){let u=c?.trim();if(u&&(UD(u)&&s(u)||u.toLowerCase()==="bun"))return u}return o("bun",e)}function qD(t){(0,Ht.mkdirSync)(Pk,{recursive:!0}),(0,Ht.writeFileSync)(As,JSON.stringify(t,null,2))}function Ak(){if(!(0,Ht.existsSync)(As))return null;try{return JSON.parse((0,Ht.readFileSync)(As,"utf-8"))}catch(t){return _.warn("SYSTEM","Failed to parse PID file",{path:As},t),null}}function Xc(){if((0,Ht.existsSync)(As))try{(0,Ht.unlinkSync)(As)}catch(t){_.warn("SYSTEM","Failed to remove PID file",{path:As},t)}}function Ms(t){return process.platform==="win32"?Math.round(t*2):t}function wee(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 Ok=["worker-service.cjs","chroma-mcp"],Eee=["mcp-server.cjs"];async function HD(){let t=process.platform==="win32",e=process.pid,r=[],n=[...Ok,...Eee],i=new Set([e]);process.ppid&&process.ppid>0&&i.add(process.ppid);try{if(t){let o=`powershell -NoProfile -NonInteractive -Command "Get-CimInstance Win32_Process -Filter '(${n.map(d=>`CommandLine LIKE '%${d}%'`).join(" OR ")}) AND ProcessId != ${e}' | Select-Object ProcessId, CommandLine, CreationDate | ConvertTo-Json"`,{stdout:a}=await zD(o,{timeout:Ir.POWERSHELL_COMMAND,windowsHide:!0});if(!a.trim()||a.trim()==="null"){_.debug("SYSTEM","No orphaned claude-mem processes found (Windows)");return}let c=JSON.parse(a),u=Array.isArray(c)?c:[c],l=Date.now();for(let d of u){let p=d.ProcessId;if(!Number.isInteger(p)||p<=0||i.has(p))continue;let f=d.CommandLine||"";if(Ok.some(h=>f.includes(h)))r.push(p),_.debug("SYSTEM","Found orphaned process (aggressive)",{pid:p,commandLine:f.substring(0,80)});else{let h=d.CreationDate?.match(/\/Date\((\d+)\)\//);if(h){let g=parseInt(h[1],10),v=(l-g)/(1e3*60);v>=LD&&(r.push(p),_.debug("SYSTEM","Found orphaned process (age-gated)",{pid:p,ageMinutes:Math.round(v)}))}}}}else{let s=n.join("|"),{stdout:o}=await zD(`ps -eo pid,etime,command | grep -E "${s}" | grep -v grep || true`);if(!o.trim()){_.debug("SYSTEM","No orphaned claude-mem processes found (Unix)");return}let a=o.trim().split(` -`);for(let c of a){let u=c.trim().match(/^(\d+)\s+(\S+)\s+(.*)$/);if(!u)continue;let l=parseInt(u[1],10),d=u[2],p=u[3];if(!Number.isInteger(l)||l<=0||i.has(l))continue;if(Ok.some(m=>p.includes(m)))r.push(l),_.debug("SYSTEM","Found orphaned process (aggressive)",{pid:l,command:p.substring(0,80)});else{let m=wee(d);m>=LD&&(r.push(l),_.debug("SYSTEM","Found orphaned process (age-gated)",{pid:l,ageMinutes:m,command:p.substring(0,80)}))}}}}catch(s){_.error("SYSTEM","Failed to enumerate orphaned processes during aggressive cleanup",{},s);return}if(r.length!==0){if(_.info("SYSTEM","Aggressive startup cleanup: killing orphaned processes",{platform:t?"Windows":"Unix",count:r.length,pids:r}),t){for(let s of r)if(!(!Number.isInteger(s)||s<=0))try{(0,Ns.execSync)(`taskkill /PID ${s} /T /F`,{timeout:Ir.POWERSHELL_COMMAND,stdio:"ignore",windowsHide:!0})}catch(o){_.debug("SYSTEM","Failed to kill process, may have already exited",{pid:s},o)}}else for(let s of r)try{process.kill(s,"SIGKILL")}catch(o){_.debug("SYSTEM","Process already exited",{pid:s},o)}_.info("SYSTEM","Aggressive startup cleanup complete",{count:r.length})}}var kee=".chroma-cleaned-v10.3";function ZD(t){let e=t??Pk,r=Ki.default.join(e,kee),n=Ki.default.join(e,"chroma");if((0,Ht.existsSync)(r)){_.debug("SYSTEM","Chroma migration marker exists, skipping wipe");return}_.warn("SYSTEM","Running one-time chroma data wipe (upgrade from pre-v10.3)",{chromaDir:n}),(0,Ht.existsSync)(n)&&((0,Ht.rmSync)(n,{recursive:!0,force:!0}),_.info("SYSTEM","Chroma data directory removed",{chromaDir:n})),(0,Ht.mkdirSync)(e,{recursive:!0}),(0,Ht.writeFileSync)(r,new Date().toISOString()),_.info("SYSTEM","Chroma migration marker written",{markerPath:r})}function Nk(t,e,r={}){let n=process.platform==="win32";yt().assertCanSpawn("worker daemon");let i=Wi({...process.env,CLAUDE_MEM_WORKER_PORT:String(e),...r});if(n){let a=xee();if(!a){_.error("SYSTEM","Failed to locate Bun runtime for Windows worker spawn");return}let c=`Start-Process -FilePath '${a.replace(/'/g,"''")}' -ArgumentList @('${t.replace(/'/g,"''")}','--daemon') -WindowStyle Hidden`,u=Buffer.from(c,"utf16le").toString("base64");try{return(0,Ns.execSync)(`powershell -NoProfile -EncodedCommand ${u}`,{stdio:"ignore",windowsHide:!0,env:i}),0}catch(l){_.error("SYSTEM","Failed to spawn worker daemon on Windows",{runtimePath:a},l);return}}let s="/usr/bin/setsid";if((0,Ht.existsSync)(s)){let a=(0,Ns.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,Ns.spawn)(process.execPath,[t,"--daemon"],{detached:!0,stdio:"ignore",env:i});if(o.pid!==void 0)return o.unref(),o.pid}function BD(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 GD(){try{if(!(0,Ht.existsSync)(As))return;let t=new Date;(0,Ht.utimesSync)(As,t,t)}catch{}}function WD(){return wk({logAlive:!1})}var VD=Pe(require("net"),1);te();It();async function KD(t,e,r="GET"){let n=await fetch(`http://127.0.0.1:${t}${e}`,{method:r}),i="";try{i=await n.text()}catch{}return{ok:n.ok,statusCode:n.status,body:i}}async function mp(t){if(process.platform==="win32")try{return(await fetch(`http://127.0.0.1:${t}/api/health`)).ok}catch{return!1}return new Promise(e=>{let r=VD.default.createServer();r.once("error",n=>{n.code==="EADDRINUSE"?e(!0):e(!1)}),r.once("listening",()=>{r.close(()=>e(!1))}),r.listen(t,"127.0.0.1")})}async function JD(t,e,r,n){let i=Date.now();for(;Date.now()-isetTimeout(s,500))}return!1}function Yc(t,e=3e4){return JD(t,"/api/health",e,"Service not ready yet, will retry")}function Mk(t,e=3e4){return JD(t,"/api/readiness",e,"Worker not ready yet, will retry")}async function Dk(t,e=1e4){let r=Date.now();for(;Date.now()-rsetTimeout(n,500))}return!1}async function jk(t){try{let e=await KD(t,"/api/admin/shutdown","POST");return e.ok?!0:(_.warn("SYSTEM","Shutdown request returned error",{status:e.statusCode}),!1)}catch(e){return e instanceof Error&&e.message?.includes("ECONNREFUSED")?(_.debug("SYSTEM","Worker already stopped",{},e),!1):(_.error("SYSTEM","Shutdown request failed unexpectedly",{},e),!1)}}te();async function XD(t){_.info("SYSTEM","Shutdown initiated"),t.server&&(await Tee(t.server),_.info("SYSTEM","HTTP server closed")),await t.sessionManager.shutdownAll(),t.mcpClient&&(await t.mcpClient.close(),_.info("SYSTEM","MCP client closed")),t.chromaMcpManager&&(_.info("SHUTDOWN","Stopping Chroma MCP connection..."),await t.chromaMcpManager.stop(),_.info("SHUTDOWN","Chroma MCP connection stopped")),t.dbManager&&await t.dbManager.close(),await RD(),_.info("SYSTEM","Worker shutdown complete")}async function Tee(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)),_.info("SYSTEM","Waited for Windows port cleanup"))}var aF=Pe(Kv(),1),H$=Pe(require("fs"),1),Qp=Pe(require("path"),1);var V6=["search","context","summarize","import","export"],K6=["workflow","search_params","examples","all"];te();var U$=Pe(Kv(),1),tF=Pe(eF(),1),rF=Pe(require("path"),1);It();te();function F$(t){let e=[];e.push(U$.default.json({limit:"50mb"})),e.push((0,tF.default)({origin:(i,s)=>{!i||i.startsWith("http://localhost:")||i.startsWith("http://127.0.0.1:")?s(null,!0):s(new Error("CORS not allowed"))},methods:["GET","HEAD","POST","PUT","PATCH","DELETE"],allowedHeaders:["Content-Type","Authorization","X-Requested-With"],credentials:!1})),e.push((i,s,o)=>{let c=[".html",".js",".css",".svg",".png",".jpg",".jpeg",".webp",".woff",".woff2",".ttf",".eot"].some(m=>i.path.endsWith(m)),u=i.path==="/api/logs";if(i.path.startsWith("/health")||i.path==="/"||c||u)return o();let l=Date.now(),d=`${i.method}-${Date.now()}`,p=t(i.method,i.path,i.body);_.debug("HTTP",`\u2192 ${i.method} ${i.path}`,{requestId:d},p);let f=s.send.bind(s);s.send=function(m){let h=Date.now()-l;return _.debug("HTTP",`\u2190 ${s.statusCode} ${i.path}`,{requestId:d,duration:`${h}ms`}),f(m)},o()});let r=gn(),n=rF.default.join(r,"plugin","ui");return e.push(U$.default.static(n)),e}function Yp(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")){_.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 q$(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=${_.formatTool(n,i)}`}return e.includes("/summarize")?"requesting summary":""}te();var Sn=class extends Error{constructor(r,n=500,i,s){super(r);this.statusCode=n;this.code=i;this.details=s;this.name="AppError"}};function nF(t,e,r,n){let i={error:t,message:e};return r&&(i.code=r),n&&(i.details=n),i}var iF=(t,e,r,n)=>{let i=t instanceof Sn?t.statusCode:500;_.error("HTTP",`Error handling ${e.method} ${e.path}`,{statusCode:i,error:t.message,code:t instanceof Sn?t.code:void 0},t);let s=nF(t.name||"Error",t.message,t instanceof Sn?t.code:void 0,t instanceof Sn?t.details:void 0);r.status(i).json(s)};function sF(t,e){e.status(404).json(nF("NotFound",`Cannot ${t.method} ${t.path}`))}var oF="11.0.1",Jv=class{app;server=null;options;startTime=Date.now();constructor(e){this.options=e,this.app=(0,aF.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,()=>{_.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,_.info("SYSTEM","HTTP server closed"))}registerRoutes(e){e.setupRoutes(this.app)}finalizeRoutes(){this.app.use(sF),this.app.use(iF)}setupMiddleware(){F$(q$).forEach(r=>this.app.use(r))}setupCoreRoutes(){this.app.get("/api/health",(e,r)=>{r.status(200).json({status:"ok",version:oF,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:oF})}),this.app.get("/api/instructions",async(e,r)=>{let n=e.query.topic||"all",i=e.query.operation;if(n&&!K6.includes(n))return r.status(400).json({error:"Invalid topic"});try{let s;if(i){if(!V6.includes(i))return r.status(400).json({error:"Invalid operation"});let o=Qp.default.resolve(__dirname,"../skills/mem-search/operations"),a=Qp.default.resolve(o,`${i}.md`);if(!a.startsWith(o+Qp.default.sep))return r.status(400).json({error:"Invalid request"});s=await H$.promises.readFile(a,"utf-8")}else{let o=Qp.default.join(__dirname,"../skills/mem-search/SKILL.md"),a=await H$.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",Yp,async(e,r)=>{r.json({status:"restarting"}),process.platform==="win32"&&process.env.CLAUDE_MEM_MANAGED==="true"&&process.send?(_.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",Yp,async(e,r)=>{r.json({status:"shutting_down"}),process.platform==="win32"&&process.env.CLAUDE_MEM_MANAGED==="true"&&process.send?(_.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",Yp,(e,r)=>{let o=yt().getRegistry().getAll().map(m=>({id:m.id,pid:m.pid,type:m.type,status:An(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=>vk.has(m)||gk.some(h=>m.startsWith(h))),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 Ct=Pe(require("path"),1),tf=require("os"),Jt=require("fs"),lF=require("child_process"),dF=require("util");te();fr();It();var ti=require("fs"),ef=require("path");te();function cF(t){try{return(0,ti.existsSync)(t)?JSON.parse((0,ti.readFileSync)(t,"utf-8")):{}}catch(e){return _.error("CONFIG","Failed to read Cursor registry, using empty registry",{file:t,error:e instanceof Error?e.message:String(e)}),{}}}function uF(t,e){let r=(0,ef.join)(t,"..");(0,ti.mkdirSync)(r,{recursive:!0}),(0,ti.writeFileSync)(t,JSON.stringify(e,null,2))}function Z$(t,e){let r=(0,ef.join)(t,".cursor","rules"),n=(0,ef.join)(r,"claude-mem-context.mdc"),i=`${n}.tmp`;(0,ti.mkdirSync)(r,{recursive:!0});let s=`--- +`);for(let c of a){let u=c.trim().match(/^(\d+)\s+(\S+)\s+(.*)$/);if(!u)continue;let l=parseInt(u[1],10),d=u[2],p=u[3];if(!Number.isInteger(l)||l<=0||i.has(l))continue;if(Ok.some(m=>p.includes(m)))r.push(l),_.debug("SYSTEM","Found orphaned process (aggressive)",{pid:l,command:p.substring(0,80)});else{let m=wee(d);m>=LD&&(r.push(l),_.debug("SYSTEM","Found orphaned process (age-gated)",{pid:l,ageMinutes:m,command:p.substring(0,80)}))}}}}catch(s){_.error("SYSTEM","Failed to enumerate orphaned processes during aggressive cleanup",{},s);return}if(r.length!==0){if(_.info("SYSTEM","Aggressive startup cleanup: killing orphaned processes",{platform:t?"Windows":"Unix",count:r.length,pids:r}),t){for(let s of r)if(!(!Number.isInteger(s)||s<=0))try{(0,Ns.execSync)(`taskkill /PID ${s} /T /F`,{timeout:Ir.POWERSHELL_COMMAND,stdio:"ignore",windowsHide:!0})}catch(o){_.debug("SYSTEM","Failed to kill process, may have already exited",{pid:s},o)}}else for(let s of r)try{process.kill(s,"SIGKILL")}catch(o){_.debug("SYSTEM","Process already exited",{pid:s},o)}_.info("SYSTEM","Aggressive startup cleanup complete",{count:r.length})}}var kee=".chroma-cleaned-v10.3";function ZD(t){let e=t??Pk,r=Ki.default.join(e,kee),n=Ki.default.join(e,"chroma");if((0,Ht.existsSync)(r)){_.debug("SYSTEM","Chroma migration marker exists, skipping wipe");return}_.warn("SYSTEM","Running one-time chroma data wipe (upgrade from pre-v10.3)",{chromaDir:n}),(0,Ht.existsSync)(n)&&((0,Ht.rmSync)(n,{recursive:!0,force:!0}),_.info("SYSTEM","Chroma data directory removed",{chromaDir:n})),(0,Ht.mkdirSync)(e,{recursive:!0}),(0,Ht.writeFileSync)(r,new Date().toISOString()),_.info("SYSTEM","Chroma migration marker written",{markerPath:r})}function Nk(t,e,r={}){let n=process.platform==="win32";yt().assertCanSpawn("worker daemon");let i=Wi({...process.env,CLAUDE_MEM_WORKER_PORT:String(e),...r});if(n){let a=xee();if(!a){_.error("SYSTEM","Failed to locate Bun runtime for Windows worker spawn");return}let c=`Start-Process -FilePath '${a.replace(/'/g,"''")}' -ArgumentList @('${t.replace(/'/g,"''")}','--daemon') -WindowStyle Hidden`,u=Buffer.from(c,"utf16le").toString("base64");try{return(0,Ns.execSync)(`powershell -NoProfile -EncodedCommand ${u}`,{stdio:"ignore",windowsHide:!0,env:i}),0}catch(l){_.error("SYSTEM","Failed to spawn worker daemon on Windows",{runtimePath:a},l);return}}let s="/usr/bin/setsid";if((0,Ht.existsSync)(s)){let a=(0,Ns.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,Ns.spawn)(process.execPath,[t,"--daemon"],{detached:!0,stdio:"ignore",env:i});if(o.pid!==void 0)return o.unref(),o.pid}function BD(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 GD(){try{if(!(0,Ht.existsSync)(As))return;let t=new Date;(0,Ht.utimesSync)(As,t,t)}catch{}}function WD(){return wk({logAlive:!1})}var VD=Pe(require("net"),1);te();It();async function KD(t,e,r="GET"){let n=await fetch(`http://127.0.0.1:${t}${e}`,{method:r}),i="";try{i=await n.text()}catch{}return{ok:n.ok,statusCode:n.status,body:i}}async function mp(t){if(process.platform==="win32")try{return(await fetch(`http://127.0.0.1:${t}/api/health`)).ok}catch{return!1}return new Promise(e=>{let r=VD.default.createServer();r.once("error",n=>{n.code==="EADDRINUSE"?e(!0):e(!1)}),r.once("listening",()=>{r.close(()=>e(!1))}),r.listen(t,"127.0.0.1")})}async function JD(t,e,r,n){let i=Date.now();for(;Date.now()-isetTimeout(s,500))}return!1}function Yc(t,e=3e4){return JD(t,"/api/health",e,"Service not ready yet, will retry")}function Mk(t,e=3e4){return JD(t,"/api/readiness",e,"Worker not ready yet, will retry")}async function Dk(t,e=1e4){let r=Date.now();for(;Date.now()-rsetTimeout(n,500))}return!1}async function jk(t){try{let e=await KD(t,"/api/admin/shutdown","POST");return e.ok?!0:(_.warn("SYSTEM","Shutdown request returned error",{status:e.statusCode}),!1)}catch(e){return e instanceof Error&&e.message?.includes("ECONNREFUSED")?(_.debug("SYSTEM","Worker already stopped",{},e),!1):(_.error("SYSTEM","Shutdown request failed unexpectedly",{},e),!1)}}te();async function XD(t){_.info("SYSTEM","Shutdown initiated"),t.server&&(await Tee(t.server),_.info("SYSTEM","HTTP server closed")),await t.sessionManager.shutdownAll(),t.mcpClient&&(await t.mcpClient.close(),_.info("SYSTEM","MCP client closed")),t.chromaMcpManager&&(_.info("SHUTDOWN","Stopping Chroma MCP connection..."),await t.chromaMcpManager.stop(),_.info("SHUTDOWN","Chroma MCP connection stopped")),t.dbManager&&await t.dbManager.close(),await RD(),_.info("SYSTEM","Worker shutdown complete")}async function Tee(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)),_.info("SYSTEM","Waited for Windows port cleanup"))}var aF=Pe(Kv(),1),H$=Pe(require("fs"),1),Qp=Pe(require("path"),1);var V6=["search","context","summarize","import","export"],K6=["workflow","search_params","examples","all"];te();var U$=Pe(Kv(),1),tF=Pe(eF(),1),rF=Pe(require("path"),1);It();te();function F$(t){let e=[];e.push(U$.default.json({limit:"50mb"})),e.push((0,tF.default)({origin:(i,s)=>{!i||i.startsWith("http://localhost:")||i.startsWith("http://127.0.0.1:")?s(null,!0):s(new Error("CORS not allowed"))},methods:["GET","HEAD","POST","PUT","PATCH","DELETE"],allowedHeaders:["Content-Type","Authorization","X-Requested-With"],credentials:!1})),e.push((i,s,o)=>{let c=[".html",".js",".css",".svg",".png",".jpg",".jpeg",".webp",".woff",".woff2",".ttf",".eot"].some(m=>i.path.endsWith(m)),u=i.path==="/api/logs";if(i.path.startsWith("/health")||i.path==="/"||c||u)return o();let l=Date.now(),d=`${i.method}-${Date.now()}`,p=t(i.method,i.path,i.body);_.debug("HTTP",`\u2192 ${i.method} ${i.path}`,{requestId:d},p);let f=s.send.bind(s);s.send=function(m){let h=Date.now()-l;return _.debug("HTTP",`\u2190 ${s.statusCode} ${i.path}`,{requestId:d,duration:`${h}ms`}),f(m)},o()});let r=gn(),n=rF.default.join(r,"plugin","ui");return e.push(U$.default.static(n)),e}function Yp(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")){_.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 q$(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=${_.formatTool(n,i)}`}return e.includes("/summarize")?"requesting summary":""}te();var Sn=class extends Error{constructor(r,n=500,i,s){super(r);this.statusCode=n;this.code=i;this.details=s;this.name="AppError"}};function nF(t,e,r,n){let i={error:t,message:e};return r&&(i.code=r),n&&(i.details=n),i}var iF=(t,e,r,n)=>{let i=t instanceof Sn?t.statusCode:500;_.error("HTTP",`Error handling ${e.method} ${e.path}`,{statusCode:i,error:t.message,code:t instanceof Sn?t.code:void 0},t);let s=nF(t.name||"Error",t.message,t instanceof Sn?t.code:void 0,t instanceof Sn?t.details:void 0);r.status(i).json(s)};function sF(t,e){e.status(404).json(nF("NotFound",`Cannot ${t.method} ${t.path}`))}var oF="12.0.0",Jv=class{app;server=null;options;startTime=Date.now();constructor(e){this.options=e,this.app=(0,aF.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,()=>{_.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,_.info("SYSTEM","HTTP server closed"))}registerRoutes(e){e.setupRoutes(this.app)}finalizeRoutes(){this.app.use(sF),this.app.use(iF)}setupMiddleware(){F$(q$).forEach(r=>this.app.use(r))}setupCoreRoutes(){this.app.get("/api/health",(e,r)=>{r.status(200).json({status:"ok",version:oF,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:oF})}),this.app.get("/api/instructions",async(e,r)=>{let n=e.query.topic||"all",i=e.query.operation;if(n&&!K6.includes(n))return r.status(400).json({error:"Invalid topic"});try{let s;if(i){if(!V6.includes(i))return r.status(400).json({error:"Invalid operation"});let o=Qp.default.resolve(__dirname,"../skills/mem-search/operations"),a=Qp.default.resolve(o,`${i}.md`);if(!a.startsWith(o+Qp.default.sep))return r.status(400).json({error:"Invalid request"});s=await H$.promises.readFile(a,"utf-8")}else{let o=Qp.default.join(__dirname,"../skills/mem-search/SKILL.md"),a=await H$.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",Yp,async(e,r)=>{r.json({status:"restarting"}),process.platform==="win32"&&process.env.CLAUDE_MEM_MANAGED==="true"&&process.send?(_.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",Yp,async(e,r)=>{r.json({status:"shutting_down"}),process.platform==="win32"&&process.env.CLAUDE_MEM_MANAGED==="true"&&process.send?(_.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",Yp,(e,r)=>{let o=yt().getRegistry().getAll().map(m=>({id:m.id,pid:m.pid,type:m.type,status:An(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=>vk.has(m)||gk.some(h=>m.startsWith(h))),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 Ct=Pe(require("path"),1),tf=require("os"),Jt=require("fs"),lF=require("child_process"),dF=require("util");te();fr();It();var ti=require("fs"),ef=require("path");te();function cF(t){try{return(0,ti.existsSync)(t)?JSON.parse((0,ti.readFileSync)(t,"utf-8")):{}}catch(e){return _.error("CONFIG","Failed to read Cursor registry, using empty registry",{file:t,error:e instanceof Error?e.message:String(e)}),{}}}function uF(t,e){let r=(0,ef.join)(t,"..");(0,ti.mkdirSync)(r,{recursive:!0}),(0,ti.writeFileSync)(t,JSON.stringify(e,null,2))}function Z$(t,e){let r=(0,ef.join)(t,".cursor","rules"),n=(0,ef.join)(r,"claude-mem-context.mdc"),i=`${n}.tmp`;(0,ti.mkdirSync)(r,{recursive:!0});let s=`--- alwaysApply: true description: "Claude-mem context from past sessions (auto-updated)" --- @@ -1639,7 +1639,7 @@ ${e}`,o=Y$(i,s),a=`${t}.tmp`;try{(0,Ni.writeFileSync)(a,o),(0,Ni.renameSync)(a,t `&&u++;if(u>=e||m===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),f;if(i<=a)f=l.length;else{let m=c.length/Math.max(u,1);f=Math.round(i/m)}return{lines:p.join(` `),totalEstimate:f}}finally{(0,Ln.closeSync)(r)}}var H_=class extends Gr{getLogFilePath(){let e=ye.get("CLAUDE_MEM_DATA_DIR"),r=(0,q_.join)(e,"logs"),n=new Date().toISOString().split("T")[0];return(0,q_.join)(r,`claude-mem-${n}.log`)}getLogsDir(){let e=ye.get("CLAUDE_MEM_DATA_DIR");return(0,q_.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,Ln.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}=Cxe(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,Ln.existsSync)(n)){r.json({success:!0,message:"Log file does not exist",path:n});return}(0,Ln.writeFileSync)(n,"","utf-8"),_.info("SYSTEM","Log file cleared via UI",{path:n}),r.json({success:!0,message:"Log file cleared",path:n})})};te();var Z_=class extends Gr{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);_.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(f=>{_.error("CHROMA","ChromaDB sync failed",{id:p.id},f)}),n.json({success:!0,id:p.id,title:d.title,project:a,message:`Memory saved as observation #${p.id}`})})};var gwe={},cwe=120*1e3;function VR(){return WR.default.join(ye.get("CLAUDE_MEM_DATA_DIR"),".worker-start-attempted")}function uwe(){if(process.platform!=="win32")return!1;let t=VR();if(!(0,Di.existsSync)(t))return!1;try{let e=(0,Di.statSync)(t).mtimeMs;return Date.now()-e{this.resolveInitialization=e}),this.dbManager=new ey,this.sessionManager=new iy(this.dbManager),this.sseBroadcaster=new sy,this.sdkAgent=new Dy(this.dbManager,this.sessionManager),this.geminiAgent=new jy(this.dbManager,this.sessionManager),this.openRouterAgent=new Uy(this.dbManager,this.sessionManager),this.paginationHelper=new Fy(this.dbManager),this.settingsManager=new qy(this.dbManager),this.sessionEventBroadcaster=new Gy(this.sseBroadcaster,this),this.sessionManager.setOnSessionDeleted(()=>{this.broadcastProcessingStatus()}),this.mcpClient=new qc({name:"worker-search-proxy",version:pwe},{capabilities:{}}),this.server=new Jv({getInitializationComplete:()=>this.initializationCompleteFlag,getMcpReady:()=>this.mcpReady,onShutdown:()=>this.shutdown(),onRestart:()=>this.shutdown(),workerPath:__filename,getAiStatus:()=>{let e="claude";return rl()&&La()?e="openrouter":tl()&&za()&&(e="gemini"),{provider:e,authMethod:Mg(),lastInteraction:this.lastAiInteraction?{timestamp:this.lastAiInteraction.timestamp,success:this.lastAiInteraction.success,...this.lastAiInteraction.error&&{error:this.lastAiInteraction.error}}:null}}}),this.registerRoutes(),this.registerSignalHandlers()}registerSignalHandlers(){OD(async()=>{this.isShuttingDown=!0,await this.shutdown()})}registerRoutes(){this.server.app.get("/api/context/inject",async(e,r,n)=>{if(!this.initializationCompleteFlag||!this.searchRoutes){_.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){_.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 I_(this.sseBroadcaster,this.dbManager,this.sessionManager)),this.server.registerRoutes(new P_(this.sessionManager,this.dbManager,this.sdkAgent,this.geminiAgent,this.openRouterAgent,this.sessionEventBroadcaster,this)),this.server.registerRoutes(new A_(this.paginationHelper,this.dbManager,this.sessionManager,this.sseBroadcaster,this,this.startTime)),this.server.registerRoutes(new F_(this.settingsManager)),this.server.registerRoutes(new H_),this.server.registerRoutes(new Z_(this.dbManager,"claude-mem"))}async start(){let e=Rr(),r=nk();await ID(),await this.server.listen(e,r),qD({pid:process.pid,port:e,startedAt:new Date().toISOString()}),yt().registerProcess("worker",{pid:process.pid,type:"worker",startedAt:new Date().toISOString()}),_.info("SYSTEM","Worker started",{host:r,port:e,pid:process.pid}),this.initializeBackground().catch(n=>{_.error("SYSTEM","Background initialization failed",{},n)})}async initializeBackground(){try{await HD();let{ModeManager:e}=await Promise.resolve().then(()=>(sn(),CF)),{SettingsDefaultsManager:r}=await Promise.resolve().then(()=>(tr(),fM)),{USER_SETTINGS_PATH:n}=await Promise.resolve().then(()=>(It(),SM)),i=r.loadFromFile(n);(i.CLAUDE_MEM_MODE==="local"||!i.CLAUDE_MEM_MODE)&&ZD(),i.CLAUDE_MEM_CHROMA_ENABLED!=="false"?(this.chromaMcpManager=Cs.getInstance(),_.info("SYSTEM","ChromaMcpManager initialized (lazy - connects on first use)")):_.info("SYSTEM","Chroma disabled via CLAUDE_MEM_CHROMA_ENABLED=false, skipping ChromaMcpManager");let o=i.CLAUDE_MEM_MODE;e.getInstance().loadMode(o),_.info("SYSTEM",`Mode loaded: ${o}`),await this.dbManager.initialize();let{PendingMessageStore:a}=await Promise.resolve().then(()=>(Oa(),$u)),u=new a(this.dbManager.getSessionStore().db,3).resetStaleProcessingMessages(0);u>0&&_.info("SYSTEM",`Reset ${u} stale processing messages to pending`);let l=new Zy,d=new By,p=new Hy(this.dbManager.getSessionSearch(),this.dbManager.getSessionStore(),this.dbManager.getChromaSync(),l,d);this.searchRoutes=new z_(p),this.server.registerRoutes(this.searchRoutes),_.info("WORKER","SearchManager initialized and search routes registered"),this.initializationCompleteFlag=!0,this.resolveInitialization(),_.info("SYSTEM","Core initialization complete (DB + search ready)"),await this.startTranscriptWatcher(i),this.chromaMcpManager&&Jc.backfillAllProjects().then(()=>{_.info("CHROMA_SYNC","Backfill check complete for all projects")}).catch(S=>{_.error("CHROMA_SYNC","Backfill failed (non-blocking)",{},S)});let f=WR.default.join(__dirname,"mcp-server.cjs");this.mcpReady=(0,Di.existsSync)(f),yt().assertCanSpawn("mcp server");let m=new Bc({command:"node",args:[f],env:Wi(process.env)}),h=3e5,g=this.mcpClient.connect(m),v,y=new Promise((S,x)=>{v=setTimeout(()=>x(new Error("MCP connection timeout after 5 minutes")),h)});try{await Promise.race([g,y])}catch(S){clearTimeout(v),_.warn("WORKER","MCP loopback self-check failed, cleaning up subprocess",{error:S instanceof Error?S.message:String(S)});try{await m.close()}catch{}_.info("WORKER","Bundled MCP server remains available for external stdio clients",{path:f});return}clearTimeout(v);let b=m._process;b?.pid&&(yt().registerProcess("mcp-server",{pid:b.pid,type:"mcp",startedAt:new Date().toISOString()},b),b.once("exit",()=>{yt().unregisterProcess("mcp-server")})),_.success("WORKER","MCP loopback self-check connected"),this.stopOrphanReaper=RF(()=>{let S=new Set;for(let[x]of this.sessionManager.sessions)S.add(x);return S}),_.info("SYSTEM","Started orphan reaper (runs every 30 seconds)"),this.staleSessionReaperInterval=setInterval(async()=>{try{let S=await this.sessionManager.reapStaleSessions();S>0&&_.info("SYSTEM",`Reaped ${S} stale sessions`)}catch(S){_.error("SYSTEM","Stale session reaper error",{error:S instanceof Error?S.message:String(S)})}},120*1e3),this.processPendingQueues(50).then(S=>{S.sessionsStarted>0&&_.info("SYSTEM",`Auto-recovered ${S.sessionsStarted} sessions with pending work`,{totalPending:S.totalPendingSessions,started:S.sessionsStarted,sessionIds:S.startedSessionIds})}).catch(S=>{_.error("SYSTEM","Auto-recovery of pending queues failed",{},S)})}catch(e){throw _.error("SYSTEM","Background initialization failed",{},e),e}}async startTranscriptWatcher(e){if(!(e.CLAUDE_MEM_TRANSCRIPTS_ENABLED!=="false")){_.info("TRANSCRIPT","Transcript watcher disabled via CLAUDE_MEM_TRANSCRIPTS_ENABLED=false");return}let n=e.CLAUDE_MEM_TRANSCRIPTS_CONFIG_PATH||Vy,i=Xs(n);try{(0,Di.existsSync)(i)||(_8(n),_.info("TRANSCRIPT","Created default transcript watch config",{configPath:i}));let s=y8(n),o=Xs(s.stateFile??Ky);this.transcriptWatcher=new k_(s,o),await this.transcriptWatcher.start(),_.info("TRANSCRIPT","Transcript watcher started",{configPath:i,statePath:o,watches:s.watches.length})}catch(s){this.transcriptWatcher?.stop(),this.transcriptWatcher=null,_.error("TRANSCRIPT","Failed to start transcript watcher (continuing without Codex ingestion)",{configPath:i},s)}}getActiveAgent(){return rl()&&La()?this.openRouterAgent:tl()&&za()?this.geminiAgent:this.sdkAgent}startSessionProcessor(e,r){if(!e)return;let n=e.sessionDbId,i=this.getActiveAgent(),s=i.constructor.name;e.abortController.signal.aborted&&(_.debug("SYSTEM","Replacing aborted AbortController before starting generator",{sessionId:e.sessionDbId}),e.abortController=new AbortController);let o=!1,a=!1;_.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(d=>u.includes(d))){o=!0,this.lastAiInteraction={timestamp:Date.now(),success:!1,provider:s,error:u},_.error("SDK","Unrecoverable generator error - will NOT restart",{sessionId:e.sessionDbId,project:e.project,errorMessage:u});return}if(this.isSessionTerminatedError(c))return _.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&&(_.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),_.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=Ao(e.sessionDbId);if(c&&c.process.exitCode===null&&await No(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){_.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}_.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(za())try{await this.geminiAgent.startSession(e,this);return}catch(o){_.warn("SDK","Fallback Gemini failed, trying OpenRouter",{sessionId:n,error:o instanceof Error?o.message:String(o)})}if(La())try{await this.openRouterAgent.startSession(e,this);return}catch(o){_.warn("SDK","Fallback OpenRouter failed",{sessionId:n,error:o instanceof Error?o.message:String(o)})}let s=this.sessionManager.getPendingMessageStore().markAllSessionMessagesAbandoned(n);s>0&&_.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);_.info("SYSTEM","Session terminated",{sessionId:e,reason:r,abandonedMessages:i}),this.sessionManager.removeSessionImmediate(e)}async processPendingQueues(e=10){let{PendingMessageStore:r}=await Promise.resolve().then(()=>(Oa(),$u)),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,Ln.existsSync)(n)){r.json({success:!0,message:"Log file does not exist",path:n});return}(0,Ln.writeFileSync)(n,"","utf-8"),_.info("SYSTEM","Log file cleared via UI",{path:n}),r.json({success:!0,message:"Log file cleared",path:n})})};te();var Z_=class extends Gr{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);_.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(f=>{_.error("CHROMA","ChromaDB sync failed",{id:p.id},f)}),n.json({success:!0,id:p.id,title:d.title,project:a,message:`Memory saved as observation #${p.id}`})})};var gwe={},cwe=120*1e3;function VR(){return WR.default.join(ye.get("CLAUDE_MEM_DATA_DIR"),".worker-start-attempted")}function uwe(){if(process.platform!=="win32")return!1;let t=VR();if(!(0,Di.existsSync)(t))return!1;try{let e=(0,Di.statSync)(t).mtimeMs;return Date.now()-e{this.resolveInitialization=e}),this.dbManager=new ey,this.sessionManager=new iy(this.dbManager),this.sseBroadcaster=new sy,this.sdkAgent=new Dy(this.dbManager,this.sessionManager),this.geminiAgent=new jy(this.dbManager,this.sessionManager),this.openRouterAgent=new Uy(this.dbManager,this.sessionManager),this.paginationHelper=new Fy(this.dbManager),this.settingsManager=new qy(this.dbManager),this.sessionEventBroadcaster=new Gy(this.sseBroadcaster,this),this.sessionManager.setOnSessionDeleted(()=>{this.broadcastProcessingStatus()}),this.mcpClient=new qc({name:"worker-search-proxy",version:pwe},{capabilities:{}}),this.server=new Jv({getInitializationComplete:()=>this.initializationCompleteFlag,getMcpReady:()=>this.mcpReady,onShutdown:()=>this.shutdown(),onRestart:()=>this.shutdown(),workerPath:__filename,getAiStatus:()=>{let e="claude";return rl()&&La()?e="openrouter":tl()&&za()&&(e="gemini"),{provider:e,authMethod:Mg(),lastInteraction:this.lastAiInteraction?{timestamp:this.lastAiInteraction.timestamp,success:this.lastAiInteraction.success,...this.lastAiInteraction.error&&{error:this.lastAiInteraction.error}}:null}}}),this.registerRoutes(),this.registerSignalHandlers()}registerSignalHandlers(){OD(async()=>{this.isShuttingDown=!0,await this.shutdown()})}registerRoutes(){this.server.app.get("/api/context/inject",async(e,r,n)=>{if(!this.initializationCompleteFlag||!this.searchRoutes){_.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){_.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 I_(this.sseBroadcaster,this.dbManager,this.sessionManager)),this.server.registerRoutes(new P_(this.sessionManager,this.dbManager,this.sdkAgent,this.geminiAgent,this.openRouterAgent,this.sessionEventBroadcaster,this)),this.server.registerRoutes(new A_(this.paginationHelper,this.dbManager,this.sessionManager,this.sseBroadcaster,this,this.startTime)),this.server.registerRoutes(new F_(this.settingsManager)),this.server.registerRoutes(new H_),this.server.registerRoutes(new Z_(this.dbManager,"claude-mem"))}async start(){let e=Rr(),r=nk();await ID(),await this.server.listen(e,r),qD({pid:process.pid,port:e,startedAt:new Date().toISOString()}),yt().registerProcess("worker",{pid:process.pid,type:"worker",startedAt:new Date().toISOString()}),_.info("SYSTEM","Worker started",{host:r,port:e,pid:process.pid}),this.initializeBackground().catch(n=>{_.error("SYSTEM","Background initialization failed",{},n)})}async initializeBackground(){try{await HD();let{ModeManager:e}=await Promise.resolve().then(()=>(sn(),CF)),{SettingsDefaultsManager:r}=await Promise.resolve().then(()=>(tr(),fM)),{USER_SETTINGS_PATH:n}=await Promise.resolve().then(()=>(It(),SM)),i=r.loadFromFile(n);(i.CLAUDE_MEM_MODE==="local"||!i.CLAUDE_MEM_MODE)&&ZD(),i.CLAUDE_MEM_CHROMA_ENABLED!=="false"?(this.chromaMcpManager=Cs.getInstance(),_.info("SYSTEM","ChromaMcpManager initialized (lazy - connects on first use)")):_.info("SYSTEM","Chroma disabled via CLAUDE_MEM_CHROMA_ENABLED=false, skipping ChromaMcpManager");let o=i.CLAUDE_MEM_MODE;e.getInstance().loadMode(o),_.info("SYSTEM",`Mode loaded: ${o}`),await this.dbManager.initialize();let{PendingMessageStore:a}=await Promise.resolve().then(()=>(Oa(),$u)),u=new a(this.dbManager.getSessionStore().db,3).resetStaleProcessingMessages(0);u>0&&_.info("SYSTEM",`Reset ${u} stale processing messages to pending`);let l=new Zy,d=new By,p=new Hy(this.dbManager.getSessionSearch(),this.dbManager.getSessionStore(),this.dbManager.getChromaSync(),l,d);this.searchRoutes=new z_(p),this.server.registerRoutes(this.searchRoutes),_.info("WORKER","SearchManager initialized and search routes registered"),this.initializationCompleteFlag=!0,this.resolveInitialization(),_.info("SYSTEM","Core initialization complete (DB + search ready)"),await this.startTranscriptWatcher(i),this.chromaMcpManager&&Jc.backfillAllProjects().then(()=>{_.info("CHROMA_SYNC","Backfill check complete for all projects")}).catch(S=>{_.error("CHROMA_SYNC","Backfill failed (non-blocking)",{},S)});let f=WR.default.join(__dirname,"mcp-server.cjs");this.mcpReady=(0,Di.existsSync)(f),yt().assertCanSpawn("mcp server");let m=new Bc({command:"node",args:[f],env:Wi(process.env)}),h=3e5,g=this.mcpClient.connect(m),v,y=new Promise((S,x)=>{v=setTimeout(()=>x(new Error("MCP connection timeout after 5 minutes")),h)});try{await Promise.race([g,y])}catch(S){clearTimeout(v),_.warn("WORKER","MCP loopback self-check failed, cleaning up subprocess",{error:S instanceof Error?S.message:String(S)});try{await m.close()}catch{}_.info("WORKER","Bundled MCP server remains available for external stdio clients",{path:f});return}clearTimeout(v);let b=m._process;b?.pid&&(yt().registerProcess("mcp-server",{pid:b.pid,type:"mcp",startedAt:new Date().toISOString()},b),b.once("exit",()=>{yt().unregisterProcess("mcp-server")})),_.success("WORKER","MCP loopback self-check connected"),this.stopOrphanReaper=RF(()=>{let S=new Set;for(let[x]of this.sessionManager.sessions)S.add(x);return S}),_.info("SYSTEM","Started orphan reaper (runs every 30 seconds)"),this.staleSessionReaperInterval=setInterval(async()=>{try{let S=await this.sessionManager.reapStaleSessions();S>0&&_.info("SYSTEM",`Reaped ${S} stale sessions`)}catch(S){_.error("SYSTEM","Stale session reaper error",{error:S instanceof Error?S.message:String(S)})}},120*1e3),this.processPendingQueues(50).then(S=>{S.sessionsStarted>0&&_.info("SYSTEM",`Auto-recovered ${S.sessionsStarted} sessions with pending work`,{totalPending:S.totalPendingSessions,started:S.sessionsStarted,sessionIds:S.startedSessionIds})}).catch(S=>{_.error("SYSTEM","Auto-recovery of pending queues failed",{},S)})}catch(e){throw _.error("SYSTEM","Background initialization failed",{},e),e}}async startTranscriptWatcher(e){if(!(e.CLAUDE_MEM_TRANSCRIPTS_ENABLED!=="false")){_.info("TRANSCRIPT","Transcript watcher disabled via CLAUDE_MEM_TRANSCRIPTS_ENABLED=false");return}let n=e.CLAUDE_MEM_TRANSCRIPTS_CONFIG_PATH||Vy,i=Xs(n);try{(0,Di.existsSync)(i)||(_8(n),_.info("TRANSCRIPT","Created default transcript watch config",{configPath:i}));let s=y8(n),o=Xs(s.stateFile??Ky);this.transcriptWatcher=new k_(s,o),await this.transcriptWatcher.start(),_.info("TRANSCRIPT","Transcript watcher started",{configPath:i,statePath:o,watches:s.watches.length})}catch(s){this.transcriptWatcher?.stop(),this.transcriptWatcher=null,_.error("TRANSCRIPT","Failed to start transcript watcher (continuing without Codex ingestion)",{configPath:i},s)}}getActiveAgent(){return rl()&&La()?this.openRouterAgent:tl()&&za()?this.geminiAgent:this.sdkAgent}startSessionProcessor(e,r){if(!e)return;let n=e.sessionDbId,i=this.getActiveAgent(),s=i.constructor.name;e.abortController.signal.aborted&&(_.debug("SYSTEM","Replacing aborted AbortController before starting generator",{sessionId:e.sessionDbId}),e.abortController=new AbortController);let o=!1,a=!1;_.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(d=>u.includes(d))){o=!0,this.lastAiInteraction={timestamp:Date.now(),success:!1,provider:s,error:u},_.error("SDK","Unrecoverable generator error - will NOT restart",{sessionId:e.sessionDbId,project:e.project,errorMessage:u});return}if(this.isSessionTerminatedError(c))return _.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&&(_.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),_.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=Ao(e.sessionDbId);if(c&&c.process.exitCode===null&&await No(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){_.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}_.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(za())try{await this.geminiAgent.startSession(e,this);return}catch(o){_.warn("SDK","Fallback Gemini failed, trying OpenRouter",{sessionId:n,error:o instanceof Error?o.message:String(o)})}if(La())try{await this.openRouterAgent.startSession(e,this);return}catch(o){_.warn("SDK","Fallback OpenRouter failed",{sessionId:n,error:o instanceof Error?o.message:String(o)})}let s=this.sessionManager.getPendingMessageStore().markAllSessionMessagesAbandoned(n);s>0&&_.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);_.info("SYSTEM","Session terminated",{sessionId:e,reason:r,abandonedMessages:i}),this.sessionManager.removeSessionImmediate(e)}async processPendingQueues(e=10){let{PendingMessageStore:r}=await Promise.resolve().then(()=>(Oa(),$u)),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(f=>f.id),d=l.map(()=>"?").join(",");i.db.prepare(` @@ -1791,7 +1791,7 @@ ${f}`}let a=s.lineStart;for(let u=s.lineStart-1;u>=0;u--){let l=o[u].trim();if(l ${c}`}var x3=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"]),Cwe=new Set(["node_modules",".git","dist","build",".next","__pycache__",".venv","venv","env",".env","target","vendor",".cache",".turbo","coverage",".nyc_output",".claude",".smart-file-read"]),Pwe=512*1024;async function*w3(t,e,r=20,n){if(r<=0)return;let i;try{i=await(0,bl.readdir)(t,{withFileTypes:!0})}catch{return}for(let s of i){if(s.name.startsWith(".")&&s.name!=="."||Cwe.has(s.name))continue;let o=(0,vm.join)(t,s.name);if(s.isDirectory())yield*w3(o,e,r-1,n);else if(s.isFile()){let a=s.name.slice(s.name.lastIndexOf("."));(x3.has(a)||n&&n.has(a))&&(yield o)}}}async function Awe(t){try{let e=await(0,bl.stat)(t);if(e.size>Pwe||e.size===0)return null;let r=await(0,bl.readFile)(t,"utf-8");return r.slice(0,1e3).includes("\0")?null:r}catch{return null}}async function E3(t,e,r={}){let n=r.maxResults||20,i=e.toLowerCase(),s=i.split(/[\s_\-./]+/).filter(y=>y.length>0),o=r.projectRoot||t,a=gm(o),c=new Set;for(let y of Object.values(a.grammars))for(let b of y.extensions)x3.has(b)||c.add(b);let u=[];for await(let y of w3(t,t,20,c.size>0?c:void 0)){if(r.filePattern&&!(0,vm.relative)(t,y).toLowerCase().includes(r.filePattern.toLowerCase()))continue;let b=await Awe(y);b&&u.push({absolutePath:y,relativePath:(0,vm.relative)(t,y),content:b})}let l=_3(u,o),d=[],p=[],f=0;for(let[y,b]of l){f+=Nwe(b);let x=V_(y.toLowerCase(),s)>0,w=[],E=(T,I)=>{for(let P of T){let N=0,L="",G=V_(P.name.toLowerCase(),s);G>0&&(N+=G*3,L="name match"),P.signature.toLowerCase().includes(i)&&(N+=2,L=L?`${L} + signature`:"signature match"),P.jsdoc&&P.jsdoc.toLowerCase().includes(i)&&(N+=1,L=L?`${L} + jsdoc`:"jsdoc match"),N>0&&(x=!0,w.push({filePath:y,symbolName:I?`${I}.${P.name}`:P.name,kind:P.kind,signature:P.signature,jsdoc:P.jsdoc,lineStart:P.lineStart,lineEnd:P.lineEnd,matchReason:L})),P.children&&E(P.children,P.name)}};E(b.symbols),x&&(d.push(b),p.push(...w))}p.sort((y,b)=>{let S=V_(y.symbolName.toLowerCase(),s);return V_(b.symbolName.toLowerCase(),s)-S});let m=p.slice(0,n),h=new Set(m.map(y=>y.filePath)),g=d.filter(y=>h.has(y.filePath)).slice(0,n),v=g.reduce((y,b)=>y+b.foldedTokenEstimate,0);return{foldedFiles:g,matchingSymbols:m,totalFilesScanned:u.length,totalSymbolsFound:f,tokenEstimate:v}}function V_(t,e){let r=0;for(let n of e)if(t===n)r+=10;else if(t.includes(n))r+=5;else{let i=0,s=0;for(let o of n){let a=t.indexOf(o,i);a!==-1&&(s++,i=a+1)}s===n.length&&(r+=1)}return r}function Nwe(t){let e=t.symbols.length;for(let r of t.symbols)r.children&&(e+=r.children.length);return e}function k3(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 i=n.jsdoc.split(` `).find(s=>s.replace(/^[\s*/]+/,"").trim().length>0);i&&r.push(` \u{1F4AC} ${i.replace(/^[\s*/]+/,"").trim()}`)}r.push("")}r.push("\u2500\u2500 Folded File Views \u2500\u2500"),r.push("");for(let n of t.foldedFiles)r.push(_l(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 tO=require("node:fs/promises"),K_=require("node:path"),Mwe="11.0.1";console.log=(...t)=>{_.error("CONSOLE","Intercepted console output (MCP protocol protection)",void 0,{args:t})};var T3={search:"/api/search",timeline:"/api/timeline"};async function $3(t,e){_.debug("SYSTEM","\u2192 Worker API",void 0,{endpoint:t,params:e});try{let r=new URLSearchParams;for(let[o,a]of Object.entries(e))a!=null&&r.append(o,String(a));let n=`${t}?${r}`,i=await Qe(n);if(!i.ok){let o=await i.text();throw new Error(`Worker API error (${i.status}): ${o}`)}let s=await i.json();return _.debug("SYSTEM","\u2190 Worker API success",void 0,{endpoint:t}),s}catch(r){return _.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 Dwe(t,e){_.debug("HTTP","Worker API request (POST)",void 0,{endpoint:t});try{let r=await Qe(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!r.ok){let i=await r.text();throw new Error(`Worker API error (${r.status}): ${i}`)}let n=await r.json();return _.debug("HTTP","Worker API success (POST)",void 0,{endpoint:t}),{content:[{type:"text",text:JSON.stringify(n,null,2)}]}}catch(r){return _.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 jwe(){try{return(await Qe("/api/health")).ok}catch(t){return _.debug("SYSTEM","Worker health check failed",{},t),!1}}async function zwe(){if(await jwe())return!0;_.warn("SYSTEM","Worker not available, attempting auto-start for MCP client");try{let t=Rr();return await G_(t)}catch(t){return _.error("SYSTEM","Worker auto-start failed",void 0,t),!1}}var R3=[{name:"__IMPORTANT",description:`3-LAYER WORKFLOW (ALWAYS FOLLOW): +`)}var tO=require("node:fs/promises"),K_=require("node:path"),Mwe="12.0.0";console.log=(...t)=>{_.error("CONSOLE","Intercepted console output (MCP protocol protection)",void 0,{args:t})};var T3={search:"/api/search",timeline:"/api/timeline"};async function $3(t,e){_.debug("SYSTEM","\u2192 Worker API",void 0,{endpoint:t,params:e});try{let r=new URLSearchParams;for(let[o,a]of Object.entries(e))a!=null&&r.append(o,String(a));let n=`${t}?${r}`,i=await Qe(n);if(!i.ok){let o=await i.text();throw new Error(`Worker API error (${i.status}): ${o}`)}let s=await i.json();return _.debug("SYSTEM","\u2190 Worker API success",void 0,{endpoint:t}),s}catch(r){return _.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 Dwe(t,e){_.debug("HTTP","Worker API request (POST)",void 0,{endpoint:t});try{let r=await Qe(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!r.ok){let i=await r.text();throw new Error(`Worker API error (${r.status}): ${i}`)}let n=await r.json();return _.debug("HTTP","Worker API success (POST)",void 0,{endpoint:t}),{content:[{type:"text",text:JSON.stringify(n,null,2)}]}}catch(r){return _.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 jwe(){try{return(await Qe("/api/health")).ok}catch(t){return _.debug("SYSTEM","Worker health check failed",{},t),!1}}async function zwe(){if(await jwe())return!0;_.warn("SYSTEM","Worker not available, attempting auto-start for MCP client");try{let t=Rr();return await G_(t)}catch(t){return _.error("SYSTEM","Worker auto-start failed",void 0,t),!1}}var R3=[{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 91db5cfd..31e63e3a 100755 --- a/plugin/scripts/worker-service.cjs +++ b/plugin/scripts/worker-service.cjs @@ -1032,7 +1032,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);_.info("CHROMA_SYNC","Backfilling user prompts",{project:r,missing:v.length,existing:n.prompts.size,total:y.count});let b=[];for(let S of v)b.push(this.formatUserPromptDoc(S));for(let S=0;Ss.trim()).find(s=>s.length>0)||null}catch{return null}}function $Q(t={}){let e=t.platform??process.platform,r=t.execPath??process.execPath;if(e!=="win32"||aD(r))return r;let n=t.env??process.env,i=t.homeDirectory??(0,ek.homedir)(),s=t.pathExists??Ht.existsSync,o=t.lookupInPath??TQ,a=[n.BUN,n.BUN_PATH,Wi.default.join(i,".bun","bin","bun.exe"),Wi.default.join(i,".bun","bin","bun"),n.USERPROFILE?Wi.default.join(n.USERPROFILE,".bun","bin","bun.exe"):void 0,n.LOCALAPPDATA?Wi.default.join(n.LOCALAPPDATA,"bun","bun.exe"):void 0,n.LOCALAPPDATA?Wi.default.join(n.LOCALAPPDATA,"bun","bin","bun.exe"):void 0];for(let c of a){let u=c?.trim();if(u&&(aD(u)&&s(u)||u.toLowerCase()==="bun"))return u}return o("bun",e)}function uD(t){(0,Ht.mkdirSync)(tk,{recursive:!0}),(0,Ht.writeFileSync)(Rs,JSON.stringify(t,null,2))}function rk(){if(!(0,Ht.existsSync)(Rs))return null;try{return JSON.parse((0,Ht.readFileSync)(Rs,"utf-8"))}catch(t){return _.warn("SYSTEM","Failed to parse PID file",{path:Rs},t),null}}function Hc(){if((0,Ht.existsSync)(Rs))try{(0,Ht.unlinkSync)(Rs)}catch(t){_.warn("SYSTEM","Failed to remove PID file",{path:Rs},t)}}function Cs(t){return process.platform==="win32"?Math.round(t*2):t}function IQ(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 QE=["worker-service.cjs","chroma-mcp"],RQ=["mcp-server.cjs"];async function lD(){let t=process.platform==="win32",e=process.pid,r=[],n=[...QE,...RQ],i=new Set([e]);process.ppid&&process.ppid>0&&i.add(process.ppid);try{if(t){let o=`powershell -NoProfile -NonInteractive -Command "Get-CimInstance Win32_Process -Filter '(${n.map(d=>`CommandLine LIKE '%${d}%'`).join(" OR ")}) AND ProcessId != ${e}' | Select-Object ProcessId, CommandLine, CreationDate | ConvertTo-Json"`,{stdout:a}=await sD(o,{timeout:$r.POWERSHELL_COMMAND,windowsHide:!0});if(!a.trim()||a.trim()==="null"){_.debug("SYSTEM","No orphaned claude-mem processes found (Windows)");return}let c=JSON.parse(a),u=Array.isArray(c)?c:[c],l=Date.now();for(let d of u){let p=d.ProcessId;if(!Number.isInteger(p)||p<=0||i.has(p))continue;let f=d.CommandLine||"";if(QE.some(h=>f.includes(h)))r.push(p),_.debug("SYSTEM","Found orphaned process (aggressive)",{pid:p,commandLine:f.substring(0,80)});else{let h=d.CreationDate?.match(/\/Date\((\d+)\)\//);if(h){let g=parseInt(h[1],10),v=(l-g)/(1e3*60);v>=oD&&(r.push(p),_.debug("SYSTEM","Found orphaned process (age-gated)",{pid:p,ageMinutes:Math.round(v)}))}}}}else{let s=n.join("|"),{stdout:o}=await sD(`ps -eo pid,etime,command | grep -E "${s}" | grep -v grep || true`);if(!o.trim()){_.debug("SYSTEM","No orphaned claude-mem processes found (Unix)");return}let a=o.trim().split(` -`);for(let c of a){let u=c.trim().match(/^(\d+)\s+(\S+)\s+(.*)$/);if(!u)continue;let l=parseInt(u[1],10),d=u[2],p=u[3];if(!Number.isInteger(l)||l<=0||i.has(l))continue;if(QE.some(m=>p.includes(m)))r.push(l),_.debug("SYSTEM","Found orphaned process (aggressive)",{pid:l,command:p.substring(0,80)});else{let m=IQ(d);m>=oD&&(r.push(l),_.debug("SYSTEM","Found orphaned process (age-gated)",{pid:l,ageMinutes:m,command:p.substring(0,80)}))}}}}catch(s){_.error("SYSTEM","Failed to enumerate orphaned processes during aggressive cleanup",{},s);return}if(r.length!==0){if(_.info("SYSTEM","Aggressive startup cleanup: killing orphaned processes",{platform:t?"Windows":"Unix",count:r.length,pids:r}),t){for(let s of r)if(!(!Number.isInteger(s)||s<=0))try{(0,Os.execSync)(`taskkill /PID ${s} /T /F`,{timeout:$r.POWERSHELL_COMMAND,stdio:"ignore",windowsHide:!0})}catch(o){_.debug("SYSTEM","Failed to kill process, may have already exited",{pid:s},o)}}else for(let s of r)try{process.kill(s,"SIGKILL")}catch(o){_.debug("SYSTEM","Process already exited",{pid:s},o)}_.info("SYSTEM","Aggressive startup cleanup complete",{count:r.length})}}var OQ=".chroma-cleaned-v10.3";function dD(t){let e=t??tk,r=Wi.default.join(e,OQ),n=Wi.default.join(e,"chroma");if((0,Ht.existsSync)(r)){_.debug("SYSTEM","Chroma migration marker exists, skipping wipe");return}_.warn("SYSTEM","Running one-time chroma data wipe (upgrade from pre-v10.3)",{chromaDir:n}),(0,Ht.existsSync)(n)&&((0,Ht.rmSync)(n,{recursive:!0,force:!0}),_.info("SYSTEM","Chroma data directory removed",{chromaDir:n})),(0,Ht.mkdirSync)(e,{recursive:!0}),(0,Ht.writeFileSync)(r,new Date().toISOString()),_.info("SYSTEM","Chroma migration marker written",{markerPath:r})}function nk(t,e,r={}){let n=process.platform==="win32";yt().assertCanSpawn("worker daemon");let i=Bi({...process.env,CLAUDE_MEM_WORKER_PORT:String(e),...r});if(n){let a=$Q();if(!a){_.error("SYSTEM","Failed to locate Bun runtime for Windows worker spawn");return}let c=`Start-Process -FilePath '${a.replace(/'/g,"''")}' -ArgumentList @('${t.replace(/'/g,"''")}','--daemon') -WindowStyle Hidden`,u=Buffer.from(c,"utf16le").toString("base64");try{return(0,Os.execSync)(`powershell -NoProfile -EncodedCommand ${u}`,{stdio:"ignore",windowsHide:!0,env:i}),0}catch(l){_.error("SYSTEM","Failed to spawn worker daemon on Windows",{runtimePath:a},l);return}}let s="/usr/bin/setsid";if((0,Ht.existsSync)(s)){let a=(0,Os.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,Os.spawn)(process.execPath,[t,"--daemon"],{detached:!0,stdio:"ignore",env:i});if(o.pid!==void 0)return o.unref(),o.pid}function pD(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 fD(){try{if(!(0,Ht.existsSync)(Rs))return;let t=new Date;(0,Ht.utimesSync)(Rs,t,t)}catch{}}function mD(){return WE({logAlive:!1})}var hD=Pe(require("net"),1);re();It();async function gD(t,e,r="GET"){let n=await fetch(`http://127.0.0.1:${t}${e}`,{method:r}),i="";try{i=await n.text()}catch{}return{ok:n.ok,statusCode:n.status,body:i}}async function Qd(t){if(process.platform==="win32")try{return(await fetch(`http://127.0.0.1:${t}/api/health`)).ok}catch{return!1}return new Promise(e=>{let r=hD.default.createServer();r.once("error",n=>{n.code==="EADDRINUSE"?e(!0):e(!1)}),r.once("listening",()=>{r.close(()=>e(!1))}),r.listen(t,"127.0.0.1")})}async function vD(t,e,r,n){let i=Date.now();for(;Date.now()-isetTimeout(s,500))}return!1}function Zc(t,e=3e4){return vD(t,"/api/health",e,"Service not ready yet, will retry")}function ik(t,e=3e4){return vD(t,"/api/readiness",e,"Worker not ready yet, will retry")}async function sk(t,e=1e4){let r=Date.now();for(;Date.now()-rsetTimeout(n,500))}return!1}async function ok(t){try{let e=await gD(t,"/api/admin/shutdown","POST");return e.ok?!0:(_.warn("SYSTEM","Shutdown request returned error",{status:e.statusCode}),!1)}catch(e){return e instanceof Error&&e.message?.includes("ECONNREFUSED")?(_.debug("SYSTEM","Worker already stopped",{},e),!1):(_.error("SYSTEM","Shutdown request failed unexpectedly",{},e),!1)}}re();async function yD(t){_.info("SYSTEM","Shutdown initiated"),t.server&&(await CQ(t.server),_.info("SYSTEM","HTTP server closed")),await t.sessionManager.shutdownAll(),t.mcpClient&&(await t.mcpClient.close(),_.info("SYSTEM","MCP client closed")),t.chromaMcpManager&&(_.info("SHUTDOWN","Stopping Chroma MCP connection..."),await t.chromaMcpManager.stop(),_.info("SHUTDOWN","Chroma MCP connection stopped")),t.dbManager&&await t.dbManager.close(),await JM(),_.info("SYSTEM","Worker shutdown complete")}async function CQ(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)),_.info("SYSTEM","Waited for Windows port cleanup"))}var I6=Pe(Tv(),1),p$=Pe(require("fs"),1),zp=Pe(require("path"),1);var h6=["search","context","summarize","import","export"],g6=["workflow","search_params","examples","all"];re();var u$=Pe(Tv(),1),x6=Pe(S6(),1),w6=Pe(require("path"),1);It();re();function l$(t){let e=[];e.push(u$.default.json({limit:"50mb"})),e.push((0,x6.default)({origin:(i,s)=>{!i||i.startsWith("http://localhost:")||i.startsWith("http://127.0.0.1:")?s(null,!0):s(new Error("CORS not allowed"))},methods:["GET","HEAD","POST","PUT","PATCH","DELETE"],allowedHeaders:["Content-Type","Authorization","X-Requested-With"],credentials:!1})),e.push((i,s,o)=>{let c=[".html",".js",".css",".svg",".png",".jpg",".jpeg",".webp",".woff",".woff2",".ttf",".eot"].some(m=>i.path.endsWith(m)),u=i.path==="/api/logs";if(i.path.startsWith("/health")||i.path==="/"||c||u)return o();let l=Date.now(),d=`${i.method}-${Date.now()}`,p=t(i.method,i.path,i.body);_.debug("HTTP",`\u2192 ${i.method} ${i.path}`,{requestId:d},p);let f=s.send.bind(s);s.send=function(m){let h=Date.now()-l;return _.debug("HTTP",`\u2190 ${s.statusCode} ${i.path}`,{requestId:d,duration:`${h}ms`}),f(m)},o()});let r=fn(),n=w6.default.join(r,"plugin","ui");return e.push(u$.default.static(n)),e}function jp(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")){_.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 d$(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=${_.formatTool(n,i)}`}return e.includes("/summarize")?"requesting summary":""}re();var yn=class extends Error{constructor(r,n=500,i,s){super(r);this.statusCode=n;this.code=i;this.details=s;this.name="AppError"}};function E6(t,e,r,n){let i={error:t,message:e};return r&&(i.code=r),n&&(i.details=n),i}var k6=(t,e,r,n)=>{let i=t instanceof yn?t.statusCode:500;_.error("HTTP",`Error handling ${e.method} ${e.path}`,{statusCode:i,error:t.message,code:t instanceof yn?t.code:void 0},t);let s=E6(t.name||"Error",t.message,t instanceof yn?t.code:void 0,t instanceof yn?t.details:void 0);r.status(i).json(s)};function T6(t,e){e.status(404).json(E6("NotFound",`Cannot ${t.method} ${t.path}`))}var $6="11.0.1",$v=class{app;server=null;options;startTime=Date.now();constructor(e){this.options=e,this.app=(0,I6.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,()=>{_.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,_.info("SYSTEM","HTTP server closed"))}registerRoutes(e){e.setupRoutes(this.app)}finalizeRoutes(){this.app.use(T6),this.app.use(k6)}setupMiddleware(){l$(d$).forEach(r=>this.app.use(r))}setupCoreRoutes(){this.app.get("/api/health",(e,r)=>{r.status(200).json({status:"ok",version:$6,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:$6})}),this.app.get("/api/instructions",async(e,r)=>{let n=e.query.topic||"all",i=e.query.operation;if(n&&!g6.includes(n))return r.status(400).json({error:"Invalid topic"});try{let s;if(i){if(!h6.includes(i))return r.status(400).json({error:"Invalid operation"});let o=zp.default.resolve(__dirname,"../skills/mem-search/operations"),a=zp.default.resolve(o,`${i}.md`);if(!a.startsWith(o+zp.default.sep))return r.status(400).json({error:"Invalid request"});s=await p$.promises.readFile(a,"utf-8")}else{let o=zp.default.join(__dirname,"../skills/mem-search/SKILL.md"),a=await p$.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",jp,async(e,r)=>{r.json({status:"restarting"}),process.platform==="win32"&&process.env.CLAUDE_MEM_MANAGED==="true"&&process.send?(_.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",jp,async(e,r)=>{r.json({status:"shutting_down"}),process.platform==="win32"&&process.env.CLAUDE_MEM_MANAGED==="true"&&process.send?(_.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",jp,(e,r)=>{let o=yt().getRegistry().getAll().map(m=>({id:m.id,pid:m.pid,type:m.type,status:Cn(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=>FE.has(m)||UE.some(h=>m.startsWith(h))),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 Ct=Pe(require("path"),1),Up=require("os"),Jt=require("fs"),C6=require("child_process"),P6=require("util");re();Ir();It();var Yn=require("fs"),Lp=require("path");re();function R6(t){try{return(0,Yn.existsSync)(t)?JSON.parse((0,Yn.readFileSync)(t,"utf-8")):{}}catch(e){return _.error("CONFIG","Failed to read Cursor registry, using empty registry",{file:t,error:e instanceof Error?e.message:String(e)}),{}}}function O6(t,e){let r=(0,Lp.join)(t,"..");(0,Yn.mkdirSync)(r,{recursive:!0}),(0,Yn.writeFileSync)(t,JSON.stringify(e,null,2))}function f$(t,e){let r=(0,Lp.join)(t,".cursor","rules"),n=(0,Lp.join)(r,"claude-mem-context.mdc"),i=`${n}.tmp`;(0,Yn.mkdirSync)(r,{recursive:!0});let s=`--- +`);for(let c of a){let u=c.trim().match(/^(\d+)\s+(\S+)\s+(.*)$/);if(!u)continue;let l=parseInt(u[1],10),d=u[2],p=u[3];if(!Number.isInteger(l)||l<=0||i.has(l))continue;if(QE.some(m=>p.includes(m)))r.push(l),_.debug("SYSTEM","Found orphaned process (aggressive)",{pid:l,command:p.substring(0,80)});else{let m=IQ(d);m>=oD&&(r.push(l),_.debug("SYSTEM","Found orphaned process (age-gated)",{pid:l,ageMinutes:m,command:p.substring(0,80)}))}}}}catch(s){_.error("SYSTEM","Failed to enumerate orphaned processes during aggressive cleanup",{},s);return}if(r.length!==0){if(_.info("SYSTEM","Aggressive startup cleanup: killing orphaned processes",{platform:t?"Windows":"Unix",count:r.length,pids:r}),t){for(let s of r)if(!(!Number.isInteger(s)||s<=0))try{(0,Os.execSync)(`taskkill /PID ${s} /T /F`,{timeout:$r.POWERSHELL_COMMAND,stdio:"ignore",windowsHide:!0})}catch(o){_.debug("SYSTEM","Failed to kill process, may have already exited",{pid:s},o)}}else for(let s of r)try{process.kill(s,"SIGKILL")}catch(o){_.debug("SYSTEM","Process already exited",{pid:s},o)}_.info("SYSTEM","Aggressive startup cleanup complete",{count:r.length})}}var OQ=".chroma-cleaned-v10.3";function dD(t){let e=t??tk,r=Wi.default.join(e,OQ),n=Wi.default.join(e,"chroma");if((0,Ht.existsSync)(r)){_.debug("SYSTEM","Chroma migration marker exists, skipping wipe");return}_.warn("SYSTEM","Running one-time chroma data wipe (upgrade from pre-v10.3)",{chromaDir:n}),(0,Ht.existsSync)(n)&&((0,Ht.rmSync)(n,{recursive:!0,force:!0}),_.info("SYSTEM","Chroma data directory removed",{chromaDir:n})),(0,Ht.mkdirSync)(e,{recursive:!0}),(0,Ht.writeFileSync)(r,new Date().toISOString()),_.info("SYSTEM","Chroma migration marker written",{markerPath:r})}function nk(t,e,r={}){let n=process.platform==="win32";yt().assertCanSpawn("worker daemon");let i=Bi({...process.env,CLAUDE_MEM_WORKER_PORT:String(e),...r});if(n){let a=$Q();if(!a){_.error("SYSTEM","Failed to locate Bun runtime for Windows worker spawn");return}let c=`Start-Process -FilePath '${a.replace(/'/g,"''")}' -ArgumentList @('${t.replace(/'/g,"''")}','--daemon') -WindowStyle Hidden`,u=Buffer.from(c,"utf16le").toString("base64");try{return(0,Os.execSync)(`powershell -NoProfile -EncodedCommand ${u}`,{stdio:"ignore",windowsHide:!0,env:i}),0}catch(l){_.error("SYSTEM","Failed to spawn worker daemon on Windows",{runtimePath:a},l);return}}let s="/usr/bin/setsid";if((0,Ht.existsSync)(s)){let a=(0,Os.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,Os.spawn)(process.execPath,[t,"--daemon"],{detached:!0,stdio:"ignore",env:i});if(o.pid!==void 0)return o.unref(),o.pid}function pD(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 fD(){try{if(!(0,Ht.existsSync)(Rs))return;let t=new Date;(0,Ht.utimesSync)(Rs,t,t)}catch{}}function mD(){return WE({logAlive:!1})}var hD=Pe(require("net"),1);re();It();async function gD(t,e,r="GET"){let n=await fetch(`http://127.0.0.1:${t}${e}`,{method:r}),i="";try{i=await n.text()}catch{}return{ok:n.ok,statusCode:n.status,body:i}}async function Qd(t){if(process.platform==="win32")try{return(await fetch(`http://127.0.0.1:${t}/api/health`)).ok}catch{return!1}return new Promise(e=>{let r=hD.default.createServer();r.once("error",n=>{n.code==="EADDRINUSE"?e(!0):e(!1)}),r.once("listening",()=>{r.close(()=>e(!1))}),r.listen(t,"127.0.0.1")})}async function vD(t,e,r,n){let i=Date.now();for(;Date.now()-isetTimeout(s,500))}return!1}function Zc(t,e=3e4){return vD(t,"/api/health",e,"Service not ready yet, will retry")}function ik(t,e=3e4){return vD(t,"/api/readiness",e,"Worker not ready yet, will retry")}async function sk(t,e=1e4){let r=Date.now();for(;Date.now()-rsetTimeout(n,500))}return!1}async function ok(t){try{let e=await gD(t,"/api/admin/shutdown","POST");return e.ok?!0:(_.warn("SYSTEM","Shutdown request returned error",{status:e.statusCode}),!1)}catch(e){return e instanceof Error&&e.message?.includes("ECONNREFUSED")?(_.debug("SYSTEM","Worker already stopped",{},e),!1):(_.error("SYSTEM","Shutdown request failed unexpectedly",{},e),!1)}}re();async function yD(t){_.info("SYSTEM","Shutdown initiated"),t.server&&(await CQ(t.server),_.info("SYSTEM","HTTP server closed")),await t.sessionManager.shutdownAll(),t.mcpClient&&(await t.mcpClient.close(),_.info("SYSTEM","MCP client closed")),t.chromaMcpManager&&(_.info("SHUTDOWN","Stopping Chroma MCP connection..."),await t.chromaMcpManager.stop(),_.info("SHUTDOWN","Chroma MCP connection stopped")),t.dbManager&&await t.dbManager.close(),await JM(),_.info("SYSTEM","Worker shutdown complete")}async function CQ(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)),_.info("SYSTEM","Waited for Windows port cleanup"))}var I6=Pe(Tv(),1),p$=Pe(require("fs"),1),zp=Pe(require("path"),1);var h6=["search","context","summarize","import","export"],g6=["workflow","search_params","examples","all"];re();var u$=Pe(Tv(),1),x6=Pe(S6(),1),w6=Pe(require("path"),1);It();re();function l$(t){let e=[];e.push(u$.default.json({limit:"50mb"})),e.push((0,x6.default)({origin:(i,s)=>{!i||i.startsWith("http://localhost:")||i.startsWith("http://127.0.0.1:")?s(null,!0):s(new Error("CORS not allowed"))},methods:["GET","HEAD","POST","PUT","PATCH","DELETE"],allowedHeaders:["Content-Type","Authorization","X-Requested-With"],credentials:!1})),e.push((i,s,o)=>{let c=[".html",".js",".css",".svg",".png",".jpg",".jpeg",".webp",".woff",".woff2",".ttf",".eot"].some(m=>i.path.endsWith(m)),u=i.path==="/api/logs";if(i.path.startsWith("/health")||i.path==="/"||c||u)return o();let l=Date.now(),d=`${i.method}-${Date.now()}`,p=t(i.method,i.path,i.body);_.debug("HTTP",`\u2192 ${i.method} ${i.path}`,{requestId:d},p);let f=s.send.bind(s);s.send=function(m){let h=Date.now()-l;return _.debug("HTTP",`\u2190 ${s.statusCode} ${i.path}`,{requestId:d,duration:`${h}ms`}),f(m)},o()});let r=fn(),n=w6.default.join(r,"plugin","ui");return e.push(u$.default.static(n)),e}function jp(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")){_.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 d$(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=${_.formatTool(n,i)}`}return e.includes("/summarize")?"requesting summary":""}re();var yn=class extends Error{constructor(r,n=500,i,s){super(r);this.statusCode=n;this.code=i;this.details=s;this.name="AppError"}};function E6(t,e,r,n){let i={error:t,message:e};return r&&(i.code=r),n&&(i.details=n),i}var k6=(t,e,r,n)=>{let i=t instanceof yn?t.statusCode:500;_.error("HTTP",`Error handling ${e.method} ${e.path}`,{statusCode:i,error:t.message,code:t instanceof yn?t.code:void 0},t);let s=E6(t.name||"Error",t.message,t instanceof yn?t.code:void 0,t instanceof yn?t.details:void 0);r.status(i).json(s)};function T6(t,e){e.status(404).json(E6("NotFound",`Cannot ${t.method} ${t.path}`))}var $6="12.0.0",$v=class{app;server=null;options;startTime=Date.now();constructor(e){this.options=e,this.app=(0,I6.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,()=>{_.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,_.info("SYSTEM","HTTP server closed"))}registerRoutes(e){e.setupRoutes(this.app)}finalizeRoutes(){this.app.use(T6),this.app.use(k6)}setupMiddleware(){l$(d$).forEach(r=>this.app.use(r))}setupCoreRoutes(){this.app.get("/api/health",(e,r)=>{r.status(200).json({status:"ok",version:$6,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:$6})}),this.app.get("/api/instructions",async(e,r)=>{let n=e.query.topic||"all",i=e.query.operation;if(n&&!g6.includes(n))return r.status(400).json({error:"Invalid topic"});try{let s;if(i){if(!h6.includes(i))return r.status(400).json({error:"Invalid operation"});let o=zp.default.resolve(__dirname,"../skills/mem-search/operations"),a=zp.default.resolve(o,`${i}.md`);if(!a.startsWith(o+zp.default.sep))return r.status(400).json({error:"Invalid request"});s=await p$.promises.readFile(a,"utf-8")}else{let o=zp.default.join(__dirname,"../skills/mem-search/SKILL.md"),a=await p$.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",jp,async(e,r)=>{r.json({status:"restarting"}),process.platform==="win32"&&process.env.CLAUDE_MEM_MANAGED==="true"&&process.send?(_.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",jp,async(e,r)=>{r.json({status:"shutting_down"}),process.platform==="win32"&&process.env.CLAUDE_MEM_MANAGED==="true"&&process.send?(_.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",jp,(e,r)=>{let o=yt().getRegistry().getAll().map(m=>({id:m.id,pid:m.pid,type:m.type,status:Cn(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=>FE.has(m)||UE.some(h=>m.startsWith(h))),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 Ct=Pe(require("path"),1),Up=require("os"),Jt=require("fs"),C6=require("child_process"),P6=require("util");re();Ir();It();var Yn=require("fs"),Lp=require("path");re();function R6(t){try{return(0,Yn.existsSync)(t)?JSON.parse((0,Yn.readFileSync)(t,"utf-8")):{}}catch(e){return _.error("CONFIG","Failed to read Cursor registry, using empty registry",{file:t,error:e instanceof Error?e.message:String(e)}),{}}}function O6(t,e){let r=(0,Lp.join)(t,"..");(0,Yn.mkdirSync)(r,{recursive:!0}),(0,Yn.writeFileSync)(t,JSON.stringify(e,null,2))}function f$(t,e){let r=(0,Lp.join)(t,".cursor","rules"),n=(0,Lp.join)(r,"claude-mem-context.mdc"),i=`${n}.tmp`;(0,Yn.mkdirSync)(r,{recursive:!0});let s=`--- alwaysApply: true description: "Claude-mem context from past sessions (auto-updated)" --- @@ -1641,7 +1641,7 @@ ${e}`,o=S$(i,s),a=`${t}.tmp`;try{(0,Pi.writeFileSync)(a,o),(0,Pi.renameSync)(a,t `&&u++;if(u>=e||m===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),f;if(i<=a)f=l.length;else{let m=c.length/Math.max(u,1);f=Math.round(i/m)}return{lines:p.join(` `),totalEstimate:f}}finally{(0,jn.closeSync)(r)}}var b_=class extends Zr{getLogFilePath(){let e=ve.get("CLAUDE_MEM_DATA_DIR"),r=(0,__.join)(e,"logs"),n=new Date().toISOString().split("T")[0];return(0,__.join)(r,`claude-mem-${n}.log`)}getLogsDir(){let e=ve.get("CLAUDE_MEM_DATA_DIR");return(0,__.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,jn.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}=DSe(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,jn.existsSync)(n)){r.json({success:!0,message:"Log file does not exist",path:n});return}(0,jn.writeFileSync)(n,"","utf-8"),_.info("SYSTEM","Log file cleared via UI",{path:n}),r.json({success:!0,message:"Log file cleared",path:n})})};re();var S_=class extends Zr{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);_.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(f=>{_.error("CHROMA","ChromaDB sync failed",{id:p.id},f)}),n.json({success:!0,id:p.id,title:d.title,project:a,message:`Memory saved as observation #${p.id}`})})};var Sxe={},fxe=120*1e3;function vR(){return gR.default.join(ve.get("CLAUDE_MEM_DATA_DIR"),".worker-start-attempted")}function mxe(){if(process.platform!=="win32")return!1;let t=vR();if(!(0,Ni.existsSync)(t))return!1;try{let e=(0,Ni.statSync)(t).mtimeMs;return Date.now()-e{this.resolveInitialization=e}),this.dbManager=new Cv,this.sessionManager=new Mv(this.dbManager),this.sseBroadcaster=new Dv,this.sdkAgent=new fy(this.dbManager,this.sessionManager),this.geminiAgent=new my(this.dbManager,this.sessionManager),this.openRouterAgent=new vy(this.dbManager,this.sessionManager),this.paginationHelper=new yy(this.dbManager),this.settingsManager=new _y(this.dbManager),this.sessionEventBroadcaster=new wy(this.sseBroadcaster,this),this.sessionManager.setOnSessionDeleted(()=>{this.broadcastProcessingStatus()}),this.mcpClient=new Nc({name:"worker-search-proxy",version:vxe},{capabilities:{}}),this.server=new $v({getInitializationComplete:()=>this.initializationCompleteFlag,getMcpReady:()=>this.mcpReady,onShutdown:()=>this.shutdown(),onRestart:()=>this.shutdown(),workerPath:__filename,getAiStatus:()=>{let e="claude";return Vu()&&Aa()?e="openrouter":Wu()&&Pa()&&(e="gemini"),{provider:e,authMethod:dg(),lastInteraction:this.lastAiInteraction?{timestamp:this.lastAiInteraction.timestamp,success:this.lastAiInteraction.success,...this.lastAiInteraction.error&&{error:this.lastAiInteraction.error}}:null}}}),this.registerRoutes(),this.registerSignalHandlers()}registerSignalHandlers(){XM(async()=>{this.isShuttingDown=!0,await this.shutdown()})}registerRoutes(){this.server.app.get("/api/context/inject",async(e,r,n)=>{if(!this.initializationCompleteFlag||!this.searchRoutes){_.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){_.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 s_(this.sseBroadcaster,this.dbManager,this.sessionManager)),this.server.registerRoutes(new u_(this.sessionManager,this.dbManager,this.sdkAgent,this.geminiAgent,this.openRouterAgent,this.sessionEventBroadcaster,this)),this.server.registerRoutes(new l_(this.paginationHelper,this.dbManager,this.sessionManager,this.sseBroadcaster,this,this.startTime)),this.server.registerRoutes(new y_(this.settingsManager)),this.server.registerRoutes(new b_),this.server.registerRoutes(new S_(this.dbManager,"claude-mem"))}async start(){let e=Yr(),r=DE();await KM(),await this.server.listen(e,r),uD({pid:process.pid,port:e,startedAt:new Date().toISOString()}),yt().registerProcess("worker",{pid:process.pid,type:"worker",startedAt:new Date().toISOString()}),_.info("SYSTEM","Worker started",{host:r,port:e,pid:process.pid}),this.initializeBackground().catch(n=>{_.error("SYSTEM","Background initialization failed",{},n)})}async initializeBackground(){try{await lD();let{ModeManager:e}=await Promise.resolve().then(()=>(tn(),Y6)),{SettingsDefaultsManager:r}=await Promise.resolve().then(()=>(tr(),EM)),{USER_SETTINGS_PATH:n}=await Promise.resolve().then(()=>(It(),PM)),i=r.loadFromFile(n);(i.CLAUDE_MEM_MODE==="local"||!i.CLAUDE_MEM_MODE)&&dD(),i.CLAUDE_MEM_CHROMA_ENABLED!=="false"?(this.chromaMcpManager=$s.getInstance(),_.info("SYSTEM","ChromaMcpManager initialized (lazy - connects on first use)")):_.info("SYSTEM","Chroma disabled via CLAUDE_MEM_CHROMA_ENABLED=false, skipping ChromaMcpManager");let o=i.CLAUDE_MEM_MODE;e.getInstance().loadMode(o),_.info("SYSTEM",`Mode loaded: ${o}`),await this.dbManager.initialize();let{PendingMessageStore:a}=await Promise.resolve().then(()=>(Ea(),_u)),u=new a(this.dbManager.getSessionStore().db,3).resetStaleProcessingMessages(0);u>0&&_.info("SYSTEM",`Reset ${u} stale processing messages to pending`);let l=new Sy,d=new xy,p=new by(this.dbManager.getSessionSearch(),this.dbManager.getSessionStore(),this.dbManager.getChromaSync(),l,d);this.searchRoutes=new h_(p),this.server.registerRoutes(this.searchRoutes),_.info("WORKER","SearchManager initialized and search routes registered"),this.initializationCompleteFlag=!0,this.resolveInitialization(),_.info("SYSTEM","Core initialization complete (DB + search ready)"),await this.startTranscriptWatcher(i),this.chromaMcpManager&&qc.backfillAllProjects().then(()=>{_.info("CHROMA_SYNC","Backfill check complete for all projects")}).catch(S=>{_.error("CHROMA_SYNC","Backfill failed (non-blocking)",{},S)});let f=gR.default.join(__dirname,"mcp-server.cjs");this.mcpReady=(0,Ni.existsSync)(f),yt().assertCanSpawn("mcp server");let m=new jc({command:"node",args:[f],env:Bi(process.env)}),h=3e5,g=this.mcpClient.connect(m),v,y=new Promise((S,x)=>{v=setTimeout(()=>x(new Error("MCP connection timeout after 5 minutes")),h)});try{await Promise.race([g,y])}catch(S){clearTimeout(v),_.warn("WORKER","MCP loopback self-check failed, cleaning up subprocess",{error:S instanceof Error?S.message:String(S)});try{await m.close()}catch{}_.info("WORKER","Bundled MCP server remains available for external stdio clients",{path:f});return}clearTimeout(v);let b=m._process;b?.pid&&(yt().registerProcess("mcp-server",{pid:b.pid,type:"mcp",startedAt:new Date().toISOString()},b),b.once("exit",()=>{yt().unregisterProcess("mcp-server")})),_.success("WORKER","MCP loopback self-check connected"),this.stopOrphanReaper=J6(()=>{let S=new Set;for(let[x]of this.sessionManager.sessions)S.add(x);return S}),_.info("SYSTEM","Started orphan reaper (runs every 30 seconds)"),this.staleSessionReaperInterval=setInterval(async()=>{try{let S=await this.sessionManager.reapStaleSessions();S>0&&_.info("SYSTEM",`Reaped ${S} stale sessions`)}catch(S){_.error("SYSTEM","Stale session reaper error",{error:S instanceof Error?S.message:String(S)})}},120*1e3),this.processPendingQueues(50).then(S=>{S.sessionsStarted>0&&_.info("SYSTEM",`Auto-recovered ${S.sessionsStarted} sessions with pending work`,{totalPending:S.totalPendingSessions,started:S.sessionsStarted,sessionIds:S.startedSessionIds})}).catch(S=>{_.error("SYSTEM","Auto-recovery of pending queues failed",{},S)})}catch(e){throw _.error("SYSTEM","Background initialization failed",{},e),e}}async startTranscriptWatcher(e){if(!(e.CLAUDE_MEM_TRANSCRIPTS_ENABLED!=="false")){_.info("TRANSCRIPT","Transcript watcher disabled via CLAUDE_MEM_TRANSCRIPTS_ENABLED=false");return}let n=e.CLAUDE_MEM_TRANSCRIPTS_CONFIG_PATH||ky,i=Ws(n);try{(0,Ni.existsSync)(i)||(U9(n),_.info("TRANSCRIPT","Created default transcript watch config",{configPath:i}));let s=L9(n),o=Ws(s.stateFile??Ty);this.transcriptWatcher=new r_(s,o),await this.transcriptWatcher.start(),_.info("TRANSCRIPT","Transcript watcher started",{configPath:i,statePath:o,watches:s.watches.length})}catch(s){this.transcriptWatcher?.stop(),this.transcriptWatcher=null,_.error("TRANSCRIPT","Failed to start transcript watcher (continuing without Codex ingestion)",{configPath:i},s)}}getActiveAgent(){return Vu()&&Aa()?this.openRouterAgent:Wu()&&Pa()?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&&(_.debug("SYSTEM","Replacing aborted AbortController before starting generator",{sessionId:e.sessionDbId}),e.abortController=new AbortController);let o=!1,a=!1;_.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(d=>u.includes(d))){o=!0,this.lastAiInteraction={timestamp:Date.now(),success:!1,provider:s,error:u},_.error("SDK","Unrecoverable generator error - will NOT restart",{sessionId:e.sessionDbId,project:e.project,errorMessage:u});return}if(this.isSessionTerminatedError(c))return _.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&&(_.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),_.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=To(e.sessionDbId);if(c&&c.process.exitCode===null&&await $o(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){_.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}_.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(Pa())try{await this.geminiAgent.startSession(e,this);return}catch(o){_.warn("SDK","Fallback Gemini failed, trying OpenRouter",{sessionId:n,error:o instanceof Error?o.message:String(o)})}if(Aa())try{await this.openRouterAgent.startSession(e,this);return}catch(o){_.warn("SDK","Fallback OpenRouter failed",{sessionId:n,error:o instanceof Error?o.message:String(o)})}let s=this.sessionManager.getPendingMessageStore().markAllSessionMessagesAbandoned(n);s>0&&_.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);_.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(()=>(Ea(),_u)),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,jn.existsSync)(n)){r.json({success:!0,message:"Log file does not exist",path:n});return}(0,jn.writeFileSync)(n,"","utf-8"),_.info("SYSTEM","Log file cleared via UI",{path:n}),r.json({success:!0,message:"Log file cleared",path:n})})};re();var S_=class extends Zr{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);_.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(f=>{_.error("CHROMA","ChromaDB sync failed",{id:p.id},f)}),n.json({success:!0,id:p.id,title:d.title,project:a,message:`Memory saved as observation #${p.id}`})})};var Sxe={},fxe=120*1e3;function vR(){return gR.default.join(ve.get("CLAUDE_MEM_DATA_DIR"),".worker-start-attempted")}function mxe(){if(process.platform!=="win32")return!1;let t=vR();if(!(0,Ni.existsSync)(t))return!1;try{let e=(0,Ni.statSync)(t).mtimeMs;return Date.now()-e{this.resolveInitialization=e}),this.dbManager=new Cv,this.sessionManager=new Mv(this.dbManager),this.sseBroadcaster=new Dv,this.sdkAgent=new fy(this.dbManager,this.sessionManager),this.geminiAgent=new my(this.dbManager,this.sessionManager),this.openRouterAgent=new vy(this.dbManager,this.sessionManager),this.paginationHelper=new yy(this.dbManager),this.settingsManager=new _y(this.dbManager),this.sessionEventBroadcaster=new wy(this.sseBroadcaster,this),this.sessionManager.setOnSessionDeleted(()=>{this.broadcastProcessingStatus()}),this.mcpClient=new Nc({name:"worker-search-proxy",version:vxe},{capabilities:{}}),this.server=new $v({getInitializationComplete:()=>this.initializationCompleteFlag,getMcpReady:()=>this.mcpReady,onShutdown:()=>this.shutdown(),onRestart:()=>this.shutdown(),workerPath:__filename,getAiStatus:()=>{let e="claude";return Vu()&&Aa()?e="openrouter":Wu()&&Pa()&&(e="gemini"),{provider:e,authMethod:dg(),lastInteraction:this.lastAiInteraction?{timestamp:this.lastAiInteraction.timestamp,success:this.lastAiInteraction.success,...this.lastAiInteraction.error&&{error:this.lastAiInteraction.error}}:null}}}),this.registerRoutes(),this.registerSignalHandlers()}registerSignalHandlers(){XM(async()=>{this.isShuttingDown=!0,await this.shutdown()})}registerRoutes(){this.server.app.get("/api/context/inject",async(e,r,n)=>{if(!this.initializationCompleteFlag||!this.searchRoutes){_.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){_.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 s_(this.sseBroadcaster,this.dbManager,this.sessionManager)),this.server.registerRoutes(new u_(this.sessionManager,this.dbManager,this.sdkAgent,this.geminiAgent,this.openRouterAgent,this.sessionEventBroadcaster,this)),this.server.registerRoutes(new l_(this.paginationHelper,this.dbManager,this.sessionManager,this.sseBroadcaster,this,this.startTime)),this.server.registerRoutes(new y_(this.settingsManager)),this.server.registerRoutes(new b_),this.server.registerRoutes(new S_(this.dbManager,"claude-mem"))}async start(){let e=Yr(),r=DE();await KM(),await this.server.listen(e,r),uD({pid:process.pid,port:e,startedAt:new Date().toISOString()}),yt().registerProcess("worker",{pid:process.pid,type:"worker",startedAt:new Date().toISOString()}),_.info("SYSTEM","Worker started",{host:r,port:e,pid:process.pid}),this.initializeBackground().catch(n=>{_.error("SYSTEM","Background initialization failed",{},n)})}async initializeBackground(){try{await lD();let{ModeManager:e}=await Promise.resolve().then(()=>(tn(),Y6)),{SettingsDefaultsManager:r}=await Promise.resolve().then(()=>(tr(),EM)),{USER_SETTINGS_PATH:n}=await Promise.resolve().then(()=>(It(),PM)),i=r.loadFromFile(n);(i.CLAUDE_MEM_MODE==="local"||!i.CLAUDE_MEM_MODE)&&dD(),i.CLAUDE_MEM_CHROMA_ENABLED!=="false"?(this.chromaMcpManager=$s.getInstance(),_.info("SYSTEM","ChromaMcpManager initialized (lazy - connects on first use)")):_.info("SYSTEM","Chroma disabled via CLAUDE_MEM_CHROMA_ENABLED=false, skipping ChromaMcpManager");let o=i.CLAUDE_MEM_MODE;e.getInstance().loadMode(o),_.info("SYSTEM",`Mode loaded: ${o}`),await this.dbManager.initialize();let{PendingMessageStore:a}=await Promise.resolve().then(()=>(Ea(),_u)),u=new a(this.dbManager.getSessionStore().db,3).resetStaleProcessingMessages(0);u>0&&_.info("SYSTEM",`Reset ${u} stale processing messages to pending`);let l=new Sy,d=new xy,p=new by(this.dbManager.getSessionSearch(),this.dbManager.getSessionStore(),this.dbManager.getChromaSync(),l,d);this.searchRoutes=new h_(p),this.server.registerRoutes(this.searchRoutes),_.info("WORKER","SearchManager initialized and search routes registered"),this.initializationCompleteFlag=!0,this.resolveInitialization(),_.info("SYSTEM","Core initialization complete (DB + search ready)"),await this.startTranscriptWatcher(i),this.chromaMcpManager&&qc.backfillAllProjects().then(()=>{_.info("CHROMA_SYNC","Backfill check complete for all projects")}).catch(S=>{_.error("CHROMA_SYNC","Backfill failed (non-blocking)",{},S)});let f=gR.default.join(__dirname,"mcp-server.cjs");this.mcpReady=(0,Ni.existsSync)(f),yt().assertCanSpawn("mcp server");let m=new jc({command:"node",args:[f],env:Bi(process.env)}),h=3e5,g=this.mcpClient.connect(m),v,y=new Promise((S,x)=>{v=setTimeout(()=>x(new Error("MCP connection timeout after 5 minutes")),h)});try{await Promise.race([g,y])}catch(S){clearTimeout(v),_.warn("WORKER","MCP loopback self-check failed, cleaning up subprocess",{error:S instanceof Error?S.message:String(S)});try{await m.close()}catch{}_.info("WORKER","Bundled MCP server remains available for external stdio clients",{path:f});return}clearTimeout(v);let b=m._process;b?.pid&&(yt().registerProcess("mcp-server",{pid:b.pid,type:"mcp",startedAt:new Date().toISOString()},b),b.once("exit",()=>{yt().unregisterProcess("mcp-server")})),_.success("WORKER","MCP loopback self-check connected"),this.stopOrphanReaper=J6(()=>{let S=new Set;for(let[x]of this.sessionManager.sessions)S.add(x);return S}),_.info("SYSTEM","Started orphan reaper (runs every 30 seconds)"),this.staleSessionReaperInterval=setInterval(async()=>{try{let S=await this.sessionManager.reapStaleSessions();S>0&&_.info("SYSTEM",`Reaped ${S} stale sessions`)}catch(S){_.error("SYSTEM","Stale session reaper error",{error:S instanceof Error?S.message:String(S)})}},120*1e3),this.processPendingQueues(50).then(S=>{S.sessionsStarted>0&&_.info("SYSTEM",`Auto-recovered ${S.sessionsStarted} sessions with pending work`,{totalPending:S.totalPendingSessions,started:S.sessionsStarted,sessionIds:S.startedSessionIds})}).catch(S=>{_.error("SYSTEM","Auto-recovery of pending queues failed",{},S)})}catch(e){throw _.error("SYSTEM","Background initialization failed",{},e),e}}async startTranscriptWatcher(e){if(!(e.CLAUDE_MEM_TRANSCRIPTS_ENABLED!=="false")){_.info("TRANSCRIPT","Transcript watcher disabled via CLAUDE_MEM_TRANSCRIPTS_ENABLED=false");return}let n=e.CLAUDE_MEM_TRANSCRIPTS_CONFIG_PATH||ky,i=Ws(n);try{(0,Ni.existsSync)(i)||(U9(n),_.info("TRANSCRIPT","Created default transcript watch config",{configPath:i}));let s=L9(n),o=Ws(s.stateFile??Ty);this.transcriptWatcher=new r_(s,o),await this.transcriptWatcher.start(),_.info("TRANSCRIPT","Transcript watcher started",{configPath:i,statePath:o,watches:s.watches.length})}catch(s){this.transcriptWatcher?.stop(),this.transcriptWatcher=null,_.error("TRANSCRIPT","Failed to start transcript watcher (continuing without Codex ingestion)",{configPath:i},s)}}getActiveAgent(){return Vu()&&Aa()?this.openRouterAgent:Wu()&&Pa()?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&&(_.debug("SYSTEM","Replacing aborted AbortController before starting generator",{sessionId:e.sessionDbId}),e.abortController=new AbortController);let o=!1,a=!1;_.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(d=>u.includes(d))){o=!0,this.lastAiInteraction={timestamp:Date.now(),success:!1,provider:s,error:u},_.error("SDK","Unrecoverable generator error - will NOT restart",{sessionId:e.sessionDbId,project:e.project,errorMessage:u});return}if(this.isSessionTerminatedError(c))return _.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&&(_.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),_.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=To(e.sessionDbId);if(c&&c.process.exitCode===null&&await $o(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){_.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}_.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(Pa())try{await this.geminiAgent.startSession(e,this);return}catch(o){_.warn("SDK","Fallback Gemini failed, trying OpenRouter",{sessionId:n,error:o instanceof Error?o.message:String(o)})}if(Aa())try{await this.openRouterAgent.startSession(e,this);return}catch(o){_.warn("SDK","Fallback OpenRouter failed",{sessionId:n,error:o instanceof Error?o.message:String(o)})}let s=this.sessionManager.getPendingMessageStore().markAllSessionMessagesAbandoned(n);s>0&&_.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);_.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(()=>(Ea(),_u)),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(f=>f.id),d=l.map(()=>"?").join(",");i.db.prepare(`