diff --git a/plugin/scripts/worker-service.cjs b/plugin/scripts/worker-service.cjs index 9c79b08e..35d07418 100755 --- a/plugin/scripts/worker-service.cjs +++ b/plugin/scripts/worker-service.cjs @@ -919,7 +919,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs. JOIN sdk_sessions s ON up.content_session_id = s.content_session_id WHERE s.project = ? `).get(r);y.info("CHROMA_SYNC","Backfilling user prompts",{project:r,missing:v.length,existing:n.prompts.size,total:x.count});let b=[];for(let _ of v)b.push(this.formatUserPromptDoc(_));for(let _=0;_s.trim()).find(s=>s.length>0)||null}catch{return null}}function NK(t={}){let e=t.platform??process.platform,r=t.execPath??process.execPath;if(e!=="win32"||CA(r))return r;let n=t.env??process.env,i=t.homeDirectory??(0,G0.homedir)(),s=t.pathExists??zt.existsSync,o=t.lookupInPath??AK,a=[n.BUN,n.BUN_PATH,yi.default.join(i,".bun","bin","bun.exe"),yi.default.join(i,".bun","bin","bun"),n.USERPROFILE?yi.default.join(n.USERPROFILE,".bun","bin","bun.exe"):void 0,n.LOCALAPPDATA?yi.default.join(n.LOCALAPPDATA,"bun","bun.exe"):void 0,n.LOCALAPPDATA?yi.default.join(n.LOCALAPPDATA,"bun","bin","bun.exe"):void 0];for(let c of a){let u=c?.trim();if(u&&(CA(u)&&s(u)||u.toLowerCase()==="bun"))return u}return o("bun",e)}function NA(t){(0,zt.mkdirSync)(W0,{recursive:!0}),(0,zt.writeFileSync)(_i,JSON.stringify(t,null,2))}function K0(){if(!(0,zt.existsSync)(_i))return null;try{return JSON.parse((0,zt.readFileSync)(_i,"utf-8"))}catch(t){return y.warn("SYSTEM","Failed to parse PID file",{path:_i},t),null}}function _o(){if((0,zt.existsSync)(_i))try{(0,zt.unlinkSync)(_i)}catch(t){y.warn("SYSTEM","Failed to remove PID file",{path:_i},t)}}function es(t){return process.platform==="win32"?Math.round(t*2):t}function MK(t){if(!t||t.trim()==="")return-1;let e=t.trim(),r=0,n=e.match(/^(\d+)-(\d+):(\d+):(\d+)$/);if(n)return r=parseInt(n[1],10)*24*60+parseInt(n[2],10)*60+parseInt(n[3],10),r;let i=e.match(/^(\d+):(\d+):(\d+)$/);if(i)return r=parseInt(i[1],10)*60+parseInt(i[2],10),r;let s=e.match(/^(\d+):(\d+)$/);return s?parseInt(s[1],10):-1}var V0=["worker-service.cjs","chroma-mcp"],DK=["mcp-server.cjs"];async function MA(){let t=process.platform==="win32",e=process.pid,r=[],n=[...V0,...DK];try{if(t){let s=`powershell -NoProfile -NonInteractive -Command "Get-CimInstance Win32_Process -Filter '(${n.map(l=>`CommandLine LIKE '%${l}%'`).join(" OR ")}) AND ProcessId != ${e}' | Select-Object ProcessId, CommandLine, CreationDate | ConvertTo-Json"`,{stdout:o}=await OA(s,{timeout:yr.POWERSHELL_COMMAND,windowsHide:!0});if(!o.trim()||o.trim()==="null"){y.debug("SYSTEM","No orphaned claude-mem processes found (Windows)");return}let a=JSON.parse(o),c=Array.isArray(a)?a:[a],u=Date.now();for(let l of c){let d=l.ProcessId;if(!Number.isInteger(d)||d<=0||d===e)continue;let p=l.CommandLine||"";if(V0.some(f=>p.includes(f)))r.push(d),y.debug("SYSTEM","Found orphaned process (aggressive)",{pid:d,commandLine:p.substring(0,80)});else{let f=l.CreationDate?.match(/\/Date\((\d+)\)\//);if(f){let g=parseInt(f[1],10),h=(u-g)/(1e3*60);h>=PA&&(r.push(d),y.debug("SYSTEM","Found orphaned process (age-gated)",{pid:d,ageMinutes:Math.round(h)}))}}}}else{let i=n.join("|"),{stdout:s}=await OA(`ps -eo pid,etime,command | grep -E "${i}" | grep -v grep || true`);if(!s.trim()){y.debug("SYSTEM","No orphaned claude-mem processes found (Unix)");return}let o=s.trim().split(` -`);for(let a of o){let c=a.trim().match(/^(\d+)\s+(\S+)\s+(.*)$/);if(!c)continue;let u=parseInt(c[1],10),l=c[2],d=c[3];if(!Number.isInteger(u)||u<=0||u===e)continue;if(V0.some(m=>d.includes(m)))r.push(u),y.debug("SYSTEM","Found orphaned process (aggressive)",{pid:u,command:d.substring(0,80)});else{let m=MK(l);m>=PA&&(r.push(u),y.debug("SYSTEM","Found orphaned process (age-gated)",{pid:u,ageMinutes:m,command:d.substring(0,80)}))}}}}catch(i){y.error("SYSTEM","Failed to enumerate orphaned processes during aggressive cleanup",{},i);return}if(r.length!==0){if(y.info("SYSTEM","Aggressive startup cleanup: killing orphaned processes",{platform:t?"Windows":"Unix",count:r.length,pids:r}),t){for(let i of r)if(!(!Number.isInteger(i)||i<=0))try{(0,Qi.execSync)(`taskkill /PID ${i} /T /F`,{timeout:yr.POWERSHELL_COMMAND,stdio:"ignore",windowsHide:!0})}catch(s){y.debug("SYSTEM","Failed to kill process, may have already exited",{pid:i},s)}}else for(let i of r)try{process.kill(i,"SIGKILL")}catch(s){y.debug("SYSTEM","Process already exited",{pid:i},s)}y.info("SYSTEM","Aggressive startup cleanup complete",{count:r.length})}}var jK=".chroma-cleaned-v10.3";function DA(t){let e=t??W0,r=yi.default.join(e,jK),n=yi.default.join(e,"chroma");if((0,zt.existsSync)(r)){y.debug("SYSTEM","Chroma migration marker exists, skipping wipe");return}y.warn("SYSTEM","Running one-time chroma data wipe (upgrade from pre-v10.3)",{chromaDir:n}),(0,zt.existsSync)(n)&&((0,zt.rmSync)(n,{recursive:!0,force:!0}),y.info("SYSTEM","Chroma data directory removed",{chromaDir:n})),(0,zt.mkdirSync)(e,{recursive:!0}),(0,zt.writeFileSync)(r,new Date().toISOString()),y.info("SYSTEM","Chroma migration marker written",{markerPath:r})}function J0(t,e,r={}){let n=process.platform==="win32";gt().assertCanSpawn("worker daemon");let i=vi({...process.env,CLAUDE_MEM_WORKER_PORT:String(e),...r});if(n){let a=NK();if(!a){y.error("SYSTEM","Failed to locate Bun runtime for Windows worker spawn");return}let c=a.replace(/'/g,"''"),u=t.replace(/'/g,"''"),l=`Start-Process -FilePath '${c}' -ArgumentList '${u}','--daemon' -WindowStyle Hidden`;try{return(0,Qi.execSync)(`powershell -NoProfile -Command "${l}"`,{stdio:"ignore",windowsHide:!0,env:i}),0}catch(d){y.error("SYSTEM","Failed to spawn worker daemon on Windows",{runtimePath:a},d);return}}let s="/usr/bin/setsid";if((0,zt.existsSync)(s)){let a=(0,Qi.spawn)(s,[process.execPath,t,"--daemon"],{detached:!0,stdio:"ignore",env:i});return a.pid===void 0?void 0:(a.unref(),a.pid)}let o=(0,Qi.spawn)(process.execPath,[t,"--daemon"],{detached:!0,stdio:"ignore",env:i});if(o.pid!==void 0)return o.unref(),o.pid}function jA(t){if(t===0)return!0;if(!Number.isInteger(t)||t<0)return!1;try{return process.kill(t,0),!0}catch(e){return e.code==="EPERM"}}function zA(t=15e3){try{let e=(0,zt.statSync)(_i);return Date.now()-e.mtimeMssetTimeout(s,500))}return!1}function bo(t,e=3e4){return HA(t,"/api/health",e,"Service not ready yet, will retry")}function ZA(t,e=3e4){return HA(t,"/api/readiness",e,"Worker not ready yet, will retry")}async function Bf(t,e=1e4){let r=Date.now();for(;Date.now()-rsetTimeout(n,500))}return!1}async function Vf(t){try{let e=await X0(t,"/api/admin/shutdown","POST");return e.ok?!0:(y.warn("SYSTEM","Shutdown request returned error",{status:e.statusCode}),!1)}catch(e){return e instanceof Error&&e.message?.includes("ECONNREFUSED")?(y.debug("SYSTEM","Worker already stopped",{},e),!1):(y.error("SYSTEM","Shutdown request failed unexpectedly",{},e),!1)}}function zK(){try{let t=qA.default.join(Ki,"package.json");return JSON.parse((0,FA.readFileSync)(t,"utf-8")).version}catch(t){let e=t.code;if(e==="ENOENT"||e==="EBUSY")return y.debug("SYSTEM","Could not read plugin version (shutdown race)",{code:e}),"unknown";throw t}}async function LK(t){try{let e=await X0(t,"/api/version");return e.ok?JSON.parse(e.body).version:null}catch{return y.debug("SYSTEM","Could not fetch worker version",{}),null}}async function BA(t){let e=zK(),r=await LK(t);return!r||e==="unknown"?{matches:!0,pluginVersion:e,workerVersion:r}:{matches:e===r,pluginVersion:e,workerVersion:r}}oe();async function VA(t){y.info("SYSTEM","Shutdown initiated"),t.server&&(await UK(t.server),y.info("SYSTEM","HTTP server closed")),await t.sessionManager.shutdownAll(),t.mcpClient&&(await t.mcpClient.close(),y.info("SYSTEM","MCP client closed")),t.chromaMcpManager&&(y.info("SHUTDOWN","Stopping Chroma MCP connection..."),await t.chromaMcpManager.stop(),y.info("SHUTDOWN","Chroma MCP connection stopped")),t.dbManager&&await t.dbManager.close(),await SA(),y.info("SYSTEM","Worker shutdown complete")}async function UK(t){t.closeAllConnections(),process.platform==="win32"&&await new Promise(e=>setTimeout(e,500)),await new Promise((e,r)=>{t.close(n=>n?r(n):e())}),process.platform==="win32"&&(await new Promise(e=>setTimeout(e,500)),y.info("SYSTEM","Waited for Windows port cleanup"))}var rU=Ge(Qh(),1),nk=Ge(require("fs"),1),Ad=Ge(require("path"),1);var HL=["search","context","summarize","import","export"],ZL=["workflow","search_params","examples","all"];oe();var ek=Ge(Qh(),1),JL=Ge(KL(),1),XL=Ge(require("path"),1);Dt();oe();function tk(t){let e=[];e.push(ek.default.json({limit:"50mb"})),e.push((0,JL.default)({origin:(i,s)=>{!i||i.startsWith("http://localhost:")||i.startsWith("http://127.0.0.1:")?s(null,!0):s(new Error("CORS not allowed"))},methods:["GET","HEAD","POST","PUT","PATCH","DELETE"],allowedHeaders:["Content-Type","Authorization","X-Requested-With"],credentials:!1})),e.push((i,s,o)=>{let c=[".html",".js",".css",".svg",".png",".jpg",".jpeg",".webp",".woff",".woff2",".ttf",".eot"].some(f=>i.path.endsWith(f)),u=i.path==="/api/logs";if(i.path.startsWith("/health")||i.path==="/"||c||u)return o();let l=Date.now(),d=`${i.method}-${Date.now()}`,p=t(i.method,i.path,i.body);y.info("HTTP",`\u2192 ${i.method} ${i.path}`,{requestId:d},p);let m=s.send.bind(s);s.send=function(f){let g=Date.now()-l;return y.info("HTTP",`\u2190 ${s.statusCode} ${i.path}`,{requestId:d,duration:`${g}ms`}),m(f)},o()});let r=Qr(),n=XL.default.join(r,"plugin","ui");return e.push(ek.default.static(n)),e}function Cd(t,e,r){let n=t.ip||t.connection.remoteAddress||"";if(!(n==="127.0.0.1"||n==="::1"||n==="::ffff:127.0.0.1"||n==="localhost")){y.warn("SECURITY","Admin endpoint access denied - not localhost",{endpoint:t.path,clientIp:n,method:t.method}),e.status(403).json({error:"Forbidden",message:"Admin endpoints are only accessible from localhost"});return}r()}function rk(t,e,r){if(!r||Object.keys(r).length===0||e.includes("/init"))return"";if(e.includes("/observations")){let n=r.tool_name||"?",i=r.tool_input;return`tool=${y.formatTool(n,i)}`}return e.includes("/summarize")?"requesting summary":""}oe();var Ec=class extends Error{constructor(r,n=500,i,s){super(r);this.statusCode=n;this.code=i;this.details=s;this.name="AppError"}};function YL(t,e,r,n){let i={error:t,message:e};return r&&(i.code=r),n&&(i.details=n),i}var QL=(t,e,r,n)=>{let i=t instanceof Ec?t.statusCode:500;y.error("HTTP",`Error handling ${e.method} ${e.path}`,{statusCode:i,error:t.message,code:t instanceof Ec?t.code:void 0},t);let s=YL(t.name||"Error",t.message,t instanceof Ec?t.code:void 0,t instanceof Ec?t.details:void 0);r.status(i).json(s)};function eU(t,e){e.status(404).json(YL("NotFound",`Cannot ${t.method} ${t.path}`))}var tU="10.5.5",eg=class{app;server=null;options;startTime=Date.now();constructor(e){this.options=e,this.app=(0,rU.default)(),this.setupMiddleware(),this.setupCoreRoutes()}getHttpServer(){return this.server}async listen(e,r){return new Promise((n,i)=>{this.server=this.app.listen(e,r,()=>{y.info("SYSTEM","HTTP server started",{host:r,port:e,pid:process.pid}),n()}),this.server.on("error",i)})}async close(){this.server&&(this.server.closeAllConnections(),process.platform==="win32"&&await new Promise(e=>setTimeout(e,500)),await new Promise((e,r)=>{this.server.close(n=>n?r(n):e())}),process.platform==="win32"&&await new Promise(e=>setTimeout(e,500)),this.server=null,y.info("SYSTEM","HTTP server closed"))}registerRoutes(e){e.setupRoutes(this.app)}finalizeRoutes(){this.app.use(eU),this.app.use(QL)}setupMiddleware(){tk(rk).forEach(r=>this.app.use(r))}setupCoreRoutes(){this.app.get("/api/health",(e,r)=>{r.status(200).json({status:"ok",version:tU,workerPath:this.options.workerPath,uptime:Date.now()-this.startTime,managed:process.env.CLAUDE_MEM_MANAGED==="true",hasIpc:typeof process.send=="function",platform:process.platform,pid:process.pid,initialized:this.options.getInitializationComplete(),mcpReady:this.options.getMcpReady(),ai:this.options.getAiStatus()})}),this.app.get("/api/readiness",(e,r)=>{this.options.getInitializationComplete()?r.status(200).json({status:"ready",mcpReady:this.options.getMcpReady()}):r.status(503).json({status:"initializing",message:"Worker is still initializing, please retry"})}),this.app.get("/api/version",(e,r)=>{r.status(200).json({version:tU})}),this.app.get("/api/instructions",async(e,r)=>{let n=e.query.topic||"all",i=e.query.operation;if(n&&!ZL.includes(n))return r.status(400).json({error:"Invalid topic"});try{let s;if(i){if(!HL.includes(i))return r.status(400).json({error:"Invalid operation"});let o=Ad.default.resolve(__dirname,"../skills/mem-search/operations"),a=Ad.default.resolve(o,`${i}.md`);if(!a.startsWith(o+Ad.default.sep))return r.status(400).json({error:"Invalid request"});s=await nk.promises.readFile(a,"utf-8")}else{let o=Ad.default.join(__dirname,"../skills/mem-search/SKILL.md"),a=await nk.promises.readFile(o,"utf-8");s=this.extractInstructionSection(a,n)}r.json({content:[{type:"text",text:s}]})}catch{r.status(404).json({error:"Instruction not found"})}}),this.app.post("/api/admin/restart",Cd,async(e,r)=>{r.json({status:"restarting"}),process.platform==="win32"&&process.env.CLAUDE_MEM_MANAGED==="true"&&process.send?(y.info("SYSTEM","Sending restart request to wrapper"),process.send({type:"restart"})):setTimeout(async()=>{try{await this.options.onRestart()}finally{process.exit(0)}},100)}),this.app.post("/api/admin/shutdown",Cd,async(e,r)=>{r.json({status:"shutting_down"}),process.platform==="win32"&&process.env.CLAUDE_MEM_MANAGED==="true"&&process.send?(y.info("SYSTEM","Sending shutdown request to wrapper"),process.send({type:"shutdown"})):setTimeout(async()=>{try{await this.options.onShutdown()}finally{process.exit(0)}},100)}),this.app.get("/api/admin/doctor",Cd,(e,r)=>{let o=gt().getRegistry().getAll().map(f=>({id:f.id,pid:f.pid,type:f.type,status:vn(f.pid)?"alive":"dead",startedAt:f.startedAt})),a=o.filter(f=>f.status==="dead").map(f=>f.pid),c=!Object.keys(process.env).some(f=>M0.has(f)||N0.some(g=>f.startsWith(g))),u=Date.now()-this.startTime,l=Math.floor(u/1e3),d=Math.floor(l/3600),p=Math.floor(l%3600/60),m=d>0?`${d}h ${p}m`:`${p}m`;r.json({supervisor:{running:!0,pid:process.pid,uptime:m},processes:o,health:{deadProcessPids:a,envClean:c}})})}extractInstructionSection(e,r){let n={workflow:this.extractBetween(e,"## The Workflow","## Search Parameters"),search_params:this.extractBetween(e,"## Search Parameters","## Examples"),examples:this.extractBetween(e,"## Examples","## Why This Workflow"),all:e};return n[r]||n.all}extractBetween(e,r,n){let i=e.indexOf(r),s=e.indexOf(n);return i===-1?e:s===-1?e.substring(i):e.substring(i,s).trim()}};var yt=Ge(require("path"),1),Md=require("os"),Kt=require("fs"),sU=require("child_process"),oU=require("util");oe();qr();Dt();var Mn=require("fs"),Nd=require("path");oe();function nU(t){try{return(0,Mn.existsSync)(t)?JSON.parse((0,Mn.readFileSync)(t,"utf-8")):{}}catch(e){return y.error("CONFIG","Failed to read Cursor registry, using empty registry",{file:t,error:e instanceof Error?e.message:String(e)}),{}}}function iU(t,e){let r=(0,Nd.join)(t,"..");(0,Mn.mkdirSync)(r,{recursive:!0}),(0,Mn.writeFileSync)(t,JSON.stringify(e,null,2))}function ik(t,e){let r=(0,Nd.join)(t,".cursor","rules"),n=(0,Nd.join)(r,"claude-mem-context.mdc"),i=`${n}.tmp`;(0,Mn.mkdirSync)(r,{recursive:!0});let s=`--- +`);for(let a of o){let c=a.trim().match(/^(\d+)\s+(\S+)\s+(.*)$/);if(!c)continue;let u=parseInt(c[1],10),l=c[2],d=c[3];if(!Number.isInteger(u)||u<=0||u===e)continue;if(V0.some(m=>d.includes(m)))r.push(u),y.debug("SYSTEM","Found orphaned process (aggressive)",{pid:u,command:d.substring(0,80)});else{let m=MK(l);m>=PA&&(r.push(u),y.debug("SYSTEM","Found orphaned process (age-gated)",{pid:u,ageMinutes:m,command:d.substring(0,80)}))}}}}catch(i){y.error("SYSTEM","Failed to enumerate orphaned processes during aggressive cleanup",{},i);return}if(r.length!==0){if(y.info("SYSTEM","Aggressive startup cleanup: killing orphaned processes",{platform:t?"Windows":"Unix",count:r.length,pids:r}),t){for(let i of r)if(!(!Number.isInteger(i)||i<=0))try{(0,Qi.execSync)(`taskkill /PID ${i} /T /F`,{timeout:yr.POWERSHELL_COMMAND,stdio:"ignore",windowsHide:!0})}catch(s){y.debug("SYSTEM","Failed to kill process, may have already exited",{pid:i},s)}}else for(let i of r)try{process.kill(i,"SIGKILL")}catch(s){y.debug("SYSTEM","Process already exited",{pid:i},s)}y.info("SYSTEM","Aggressive startup cleanup complete",{count:r.length})}}var jK=".chroma-cleaned-v10.3";function DA(t){let e=t??W0,r=yi.default.join(e,jK),n=yi.default.join(e,"chroma");if((0,zt.existsSync)(r)){y.debug("SYSTEM","Chroma migration marker exists, skipping wipe");return}y.warn("SYSTEM","Running one-time chroma data wipe (upgrade from pre-v10.3)",{chromaDir:n}),(0,zt.existsSync)(n)&&((0,zt.rmSync)(n,{recursive:!0,force:!0}),y.info("SYSTEM","Chroma data directory removed",{chromaDir:n})),(0,zt.mkdirSync)(e,{recursive:!0}),(0,zt.writeFileSync)(r,new Date().toISOString()),y.info("SYSTEM","Chroma migration marker written",{markerPath:r})}function J0(t,e,r={}){let n=process.platform==="win32";gt().assertCanSpawn("worker daemon");let i=vi({...process.env,CLAUDE_MEM_WORKER_PORT:String(e),...r});if(n){let a=NK();if(!a){y.error("SYSTEM","Failed to locate Bun runtime for Windows worker spawn");return}let c=a.replace(/'/g,"''"),u=t.replace(/'/g,"''"),l=`Start-Process -FilePath '${c}' -ArgumentList '${u}','--daemon' -WindowStyle Hidden`;try{return(0,Qi.execSync)(`powershell -NoProfile -Command "${l}"`,{stdio:"ignore",windowsHide:!0,env:i}),0}catch(d){y.error("SYSTEM","Failed to spawn worker daemon on Windows",{runtimePath:a},d);return}}let s="/usr/bin/setsid";if((0,zt.existsSync)(s)){let a=(0,Qi.spawn)(s,[process.execPath,t,"--daemon"],{detached:!0,stdio:"ignore",env:i});return a.pid===void 0?void 0:(a.unref(),a.pid)}let o=(0,Qi.spawn)(process.execPath,[t,"--daemon"],{detached:!0,stdio:"ignore",env:i});if(o.pid!==void 0)return o.unref(),o.pid}function jA(t){if(t===0)return!0;if(!Number.isInteger(t)||t<0)return!1;try{return process.kill(t,0),!0}catch(e){return e.code==="EPERM"}}function zA(t=15e3){try{let e=(0,zt.statSync)(_i);return Date.now()-e.mtimeMssetTimeout(s,500))}return!1}function bo(t,e=3e4){return HA(t,"/api/health",e,"Service not ready yet, will retry")}function ZA(t,e=3e4){return HA(t,"/api/readiness",e,"Worker not ready yet, will retry")}async function Bf(t,e=1e4){let r=Date.now();for(;Date.now()-rsetTimeout(n,500))}return!1}async function Vf(t){try{let e=await X0(t,"/api/admin/shutdown","POST");return e.ok?!0:(y.warn("SYSTEM","Shutdown request returned error",{status:e.statusCode}),!1)}catch(e){return e instanceof Error&&e.message?.includes("ECONNREFUSED")?(y.debug("SYSTEM","Worker already stopped",{},e),!1):(y.error("SYSTEM","Shutdown request failed unexpectedly",{},e),!1)}}function zK(){try{let t=qA.default.join(Ki,"package.json");return JSON.parse((0,FA.readFileSync)(t,"utf-8")).version}catch(t){let e=t.code;if(e==="ENOENT"||e==="EBUSY")return y.debug("SYSTEM","Could not read plugin version (shutdown race)",{code:e}),"unknown";throw t}}async function LK(t){try{let e=await X0(t,"/api/version");return e.ok?JSON.parse(e.body).version:null}catch{return y.debug("SYSTEM","Could not fetch worker version",{}),null}}async function BA(t){let e=zK(),r=await LK(t);return!r||e==="unknown"?{matches:!0,pluginVersion:e,workerVersion:r}:{matches:e===r,pluginVersion:e,workerVersion:r}}oe();async function VA(t){y.info("SYSTEM","Shutdown initiated"),t.server&&(await UK(t.server),y.info("SYSTEM","HTTP server closed")),await t.sessionManager.shutdownAll(),t.mcpClient&&(await t.mcpClient.close(),y.info("SYSTEM","MCP client closed")),t.chromaMcpManager&&(y.info("SHUTDOWN","Stopping Chroma MCP connection..."),await t.chromaMcpManager.stop(),y.info("SHUTDOWN","Chroma MCP connection stopped")),t.dbManager&&await t.dbManager.close(),await SA(),y.info("SYSTEM","Worker shutdown complete")}async function UK(t){t.closeAllConnections(),process.platform==="win32"&&await new Promise(e=>setTimeout(e,500)),await new Promise((e,r)=>{t.close(n=>n?r(n):e())}),process.platform==="win32"&&(await new Promise(e=>setTimeout(e,500)),y.info("SYSTEM","Waited for Windows port cleanup"))}var rU=Ge(Qh(),1),nk=Ge(require("fs"),1),Ad=Ge(require("path"),1);var HL=["search","context","summarize","import","export"],ZL=["workflow","search_params","examples","all"];oe();var ek=Ge(Qh(),1),JL=Ge(KL(),1),XL=Ge(require("path"),1);Dt();oe();function tk(t){let e=[];e.push(ek.default.json({limit:"50mb"})),e.push((0,JL.default)({origin:(i,s)=>{!i||i.startsWith("http://localhost:")||i.startsWith("http://127.0.0.1:")?s(null,!0):s(new Error("CORS not allowed"))},methods:["GET","HEAD","POST","PUT","PATCH","DELETE"],allowedHeaders:["Content-Type","Authorization","X-Requested-With"],credentials:!1})),e.push((i,s,o)=>{let c=[".html",".js",".css",".svg",".png",".jpg",".jpeg",".webp",".woff",".woff2",".ttf",".eot"].some(f=>i.path.endsWith(f)),u=i.path==="/api/logs";if(i.path.startsWith("/health")||i.path==="/"||c||u)return o();let l=Date.now(),d=`${i.method}-${Date.now()}`,p=t(i.method,i.path,i.body);y.debug("HTTP",`\u2192 ${i.method} ${i.path}`,{requestId:d},p);let m=s.send.bind(s);s.send=function(f){let g=Date.now()-l;return y.debug("HTTP",`\u2190 ${s.statusCode} ${i.path}`,{requestId:d,duration:`${g}ms`}),m(f)},o()});let r=Qr(),n=XL.default.join(r,"plugin","ui");return e.push(ek.default.static(n)),e}function Cd(t,e,r){let n=t.ip||t.connection.remoteAddress||"";if(!(n==="127.0.0.1"||n==="::1"||n==="::ffff:127.0.0.1"||n==="localhost")){y.warn("SECURITY","Admin endpoint access denied - not localhost",{endpoint:t.path,clientIp:n,method:t.method}),e.status(403).json({error:"Forbidden",message:"Admin endpoints are only accessible from localhost"});return}r()}function rk(t,e,r){if(!r||Object.keys(r).length===0||e.includes("/init"))return"";if(e.includes("/observations")){let n=r.tool_name||"?",i=r.tool_input;return`tool=${y.formatTool(n,i)}`}return e.includes("/summarize")?"requesting summary":""}oe();var Ec=class extends Error{constructor(r,n=500,i,s){super(r);this.statusCode=n;this.code=i;this.details=s;this.name="AppError"}};function YL(t,e,r,n){let i={error:t,message:e};return r&&(i.code=r),n&&(i.details=n),i}var QL=(t,e,r,n)=>{let i=t instanceof Ec?t.statusCode:500;y.error("HTTP",`Error handling ${e.method} ${e.path}`,{statusCode:i,error:t.message,code:t instanceof Ec?t.code:void 0},t);let s=YL(t.name||"Error",t.message,t instanceof Ec?t.code:void 0,t instanceof Ec?t.details:void 0);r.status(i).json(s)};function eU(t,e){e.status(404).json(YL("NotFound",`Cannot ${t.method} ${t.path}`))}var tU="10.5.5",eg=class{app;server=null;options;startTime=Date.now();constructor(e){this.options=e,this.app=(0,rU.default)(),this.setupMiddleware(),this.setupCoreRoutes()}getHttpServer(){return this.server}async listen(e,r){return new Promise((n,i)=>{this.server=this.app.listen(e,r,()=>{y.info("SYSTEM","HTTP server started",{host:r,port:e,pid:process.pid}),n()}),this.server.on("error",i)})}async close(){this.server&&(this.server.closeAllConnections(),process.platform==="win32"&&await new Promise(e=>setTimeout(e,500)),await new Promise((e,r)=>{this.server.close(n=>n?r(n):e())}),process.platform==="win32"&&await new Promise(e=>setTimeout(e,500)),this.server=null,y.info("SYSTEM","HTTP server closed"))}registerRoutes(e){e.setupRoutes(this.app)}finalizeRoutes(){this.app.use(eU),this.app.use(QL)}setupMiddleware(){tk(rk).forEach(r=>this.app.use(r))}setupCoreRoutes(){this.app.get("/api/health",(e,r)=>{r.status(200).json({status:"ok",version:tU,workerPath:this.options.workerPath,uptime:Date.now()-this.startTime,managed:process.env.CLAUDE_MEM_MANAGED==="true",hasIpc:typeof process.send=="function",platform:process.platform,pid:process.pid,initialized:this.options.getInitializationComplete(),mcpReady:this.options.getMcpReady(),ai:this.options.getAiStatus()})}),this.app.get("/api/readiness",(e,r)=>{this.options.getInitializationComplete()?r.status(200).json({status:"ready",mcpReady:this.options.getMcpReady()}):r.status(503).json({status:"initializing",message:"Worker is still initializing, please retry"})}),this.app.get("/api/version",(e,r)=>{r.status(200).json({version:tU})}),this.app.get("/api/instructions",async(e,r)=>{let n=e.query.topic||"all",i=e.query.operation;if(n&&!ZL.includes(n))return r.status(400).json({error:"Invalid topic"});try{let s;if(i){if(!HL.includes(i))return r.status(400).json({error:"Invalid operation"});let o=Ad.default.resolve(__dirname,"../skills/mem-search/operations"),a=Ad.default.resolve(o,`${i}.md`);if(!a.startsWith(o+Ad.default.sep))return r.status(400).json({error:"Invalid request"});s=await nk.promises.readFile(a,"utf-8")}else{let o=Ad.default.join(__dirname,"../skills/mem-search/SKILL.md"),a=await nk.promises.readFile(o,"utf-8");s=this.extractInstructionSection(a,n)}r.json({content:[{type:"text",text:s}]})}catch{r.status(404).json({error:"Instruction not found"})}}),this.app.post("/api/admin/restart",Cd,async(e,r)=>{r.json({status:"restarting"}),process.platform==="win32"&&process.env.CLAUDE_MEM_MANAGED==="true"&&process.send?(y.info("SYSTEM","Sending restart request to wrapper"),process.send({type:"restart"})):setTimeout(async()=>{try{await this.options.onRestart()}finally{process.exit(0)}},100)}),this.app.post("/api/admin/shutdown",Cd,async(e,r)=>{r.json({status:"shutting_down"}),process.platform==="win32"&&process.env.CLAUDE_MEM_MANAGED==="true"&&process.send?(y.info("SYSTEM","Sending shutdown request to wrapper"),process.send({type:"shutdown"})):setTimeout(async()=>{try{await this.options.onShutdown()}finally{process.exit(0)}},100)}),this.app.get("/api/admin/doctor",Cd,(e,r)=>{let o=gt().getRegistry().getAll().map(f=>({id:f.id,pid:f.pid,type:f.type,status:vn(f.pid)?"alive":"dead",startedAt:f.startedAt})),a=o.filter(f=>f.status==="dead").map(f=>f.pid),c=!Object.keys(process.env).some(f=>M0.has(f)||N0.some(g=>f.startsWith(g))),u=Date.now()-this.startTime,l=Math.floor(u/1e3),d=Math.floor(l/3600),p=Math.floor(l%3600/60),m=d>0?`${d}h ${p}m`:`${p}m`;r.json({supervisor:{running:!0,pid:process.pid,uptime:m},processes:o,health:{deadProcessPids:a,envClean:c}})})}extractInstructionSection(e,r){let n={workflow:this.extractBetween(e,"## The Workflow","## Search Parameters"),search_params:this.extractBetween(e,"## Search Parameters","## Examples"),examples:this.extractBetween(e,"## Examples","## Why This Workflow"),all:e};return n[r]||n.all}extractBetween(e,r,n){let i=e.indexOf(r),s=e.indexOf(n);return i===-1?e:s===-1?e.substring(i):e.substring(i,s).trim()}};var yt=Ge(require("path"),1),Md=require("os"),Kt=require("fs"),sU=require("child_process"),oU=require("util");oe();qr();Dt();var Mn=require("fs"),Nd=require("path");oe();function nU(t){try{return(0,Mn.existsSync)(t)?JSON.parse((0,Mn.readFileSync)(t,"utf-8")):{}}catch(e){return y.error("CONFIG","Failed to read Cursor registry, using empty registry",{file:t,error:e instanceof Error?e.message:String(e)}),{}}}function iU(t,e){let r=(0,Nd.join)(t,"..");(0,Mn.mkdirSync)(r,{recursive:!0}),(0,Mn.writeFileSync)(t,JSON.stringify(e,null,2))}function ik(t,e){let r=(0,Nd.join)(t,".cursor","rules"),n=(0,Nd.join)(r,"claude-mem-context.mdc"),i=`${n}.tmp`;(0,Mn.mkdirSync)(r,{recursive:!0});let s=`--- alwaysApply: true description: "Claude-mem context from past sessions (auto-updated)" ---