From efcc557e4f7ebe7b0a91d0f342fc54367c6f2dd1 Mon Sep 17 00:00:00 2001 From: Alex Newman Date: Sun, 7 Dec 2025 21:16:42 -0500 Subject: [PATCH] Refactor WorkerService to allow searchRoutes to be nullable - Changed searchRoutes property to be of type SearchRoutes | null. - Initialized searchRoutes to null instead of using a temporary type assertion. - Removed conditional setup for searchRoutes in setupRoutes method, as it will be handled after database initialization. --- plugin/scripts/worker-service.cjs | 4 ++-- src/services/worker-service.ts | 7 ++----- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/plugin/scripts/worker-service.cjs b/plugin/scripts/worker-service.cjs index 834352e0..c814b23d 100755 --- a/plugin/scripts/worker-service.cjs +++ b/plugin/scripts/worker-service.cjs @@ -993,7 +993,7 @@ MEMORY PROCESSING CONTINUED `);return{content:[{type:"text",text:l}]}}catch(r){return{content:[{type:"text",text:`Search failed: ${r.message}`}],isError:!0}}}async getRecentContext(e){try{let r=e.project||(0,gw.basename)(process.cwd()),t=e.limit||3,s=this.sessionStore.getRecentSessionsWithStatus(r,t);if(s.length===0)return{content:[{type:"text",text:`# Recent Session Context No previous sessions found for project "${r}".`}]};let i=[];i.push("# Recent Session Context"),i.push(""),i.push(`Showing last ${s.length} session(s) for **${r}**:`),i.push("");for(let n of s)if(n.sdk_session_id){if(i.push("---"),i.push(""),n.has_summary){let o=this.sessionStore.getSummaryForSession(n.sdk_session_id);if(o){let l=o.prompt_number?` (Prompt #${o.prompt_number})`:"";if(i.push(`**Summary${l}**`),i.push(""),o.request&&i.push(`**Request:** ${o.request}`),o.completed&&i.push(`**Completed:** ${o.completed}`),o.learned&&i.push(`**Learned:** ${o.learned}`),o.next_steps&&i.push(`**Next Steps:** ${o.next_steps}`),o.files_read)try{let u=JSON.parse(o.files_read);Array.isArray(u)&&u.length>0&&i.push(`**Files Read:** ${u.join(", ")}`)}catch{o.files_read.trim()&&i.push(`**Files Read:** ${o.files_read}`)}if(o.files_edited)try{let u=JSON.parse(o.files_edited);Array.isArray(u)&&u.length>0&&i.push(`**Files Edited:** ${u.join(", ")}`)}catch{o.files_edited.trim()&&i.push(`**Files Edited:** ${o.files_edited}`)}let c=new Date(o.created_at).toLocaleString();i.push(`**Date:** ${c}`)}}else if(n.status==="active"){i.push("**In Progress**"),i.push(""),n.user_prompt&&i.push(`**Request:** ${n.user_prompt}`);let o=this.sessionStore.getObservationsForSession(n.sdk_session_id);if(o.length>0){i.push(""),i.push(`**Observations (${o.length}):**`);for(let c of o)i.push(`- ${c.title}`)}else i.push(""),i.push("*No observations yet*");i.push(""),i.push("**Status:** Active - summary pending");let l=new Date(n.started_at).toLocaleString();i.push(`**Date:** ${l}`)}else{i.push(`**${n.status.charAt(0).toUpperCase()+n.status.slice(1)}**`),i.push(""),n.user_prompt&&i.push(`**Request:** ${n.user_prompt}`),i.push(""),i.push(`**Status:** ${n.status} - no summary available`);let o=new Date(n.started_at).toLocaleString();i.push(`**Date:** ${o}`)}i.push("")}return{content:[{type:"text",text:i.join(` -`)}]}}catch(r){return{content:[{type:"text",text:`Failed to get recent context: ${r.message}`}],isError:!0}}}async getContextTimeline(e){try{let{anchor:r,depth_before:t=10,depth_after:s=10,project:i}=e,n,o=r,l;if(typeof r=="number"){let g=this.sessionStore.getObservationById(r);if(!g)return{content:[{type:"text",text:`Observation #${r} not found`}],isError:!0};n=g.created_at_epoch,l=this.sessionStore.getTimelineAroundObservation(r,n,t,s,i)}else if(typeof r=="string")if(r.startsWith("S")||r.startsWith("#S")){let g=r.replace(/^#?S/,""),b=parseInt(g,10),w=this.sessionStore.getSessionSummariesByIds([b]);if(w.length===0)return{content:[{type:"text",text:`Session #${b} not found`}],isError:!0};n=w[0].created_at_epoch,o=`S${b}`,l=this.sessionStore.getTimelineAroundTimestamp(n,t,s,i)}else{let g=new Date(r);if(isNaN(g.getTime()))return{content:[{type:"text",text:`Invalid timestamp: ${r}`}],isError:!0};n=g.getTime(),l=this.sessionStore.getTimelineAroundTimestamp(n,t,s,i)}else return{content:[{type:"text",text:'Invalid anchor: must be observation ID (number), session ID (e.g., "S123"), or ISO timestamp'}],isError:!0};let c=[...(l.observations||[]).map(g=>({type:"observation",data:g,epoch:g.created_at_epoch})),...(l.sessions||[]).map(g=>({type:"session",data:g,epoch:g.created_at_epoch})),...(l.prompts||[]).map(g=>({type:"prompt",data:g,epoch:g.created_at_epoch}))];c.sort((g,b)=>g.epoch-b.epoch);let u=this.timelineService.filterByDepth(c,o,n,t,s);if(!u||u.length===0)return{content:[{type:"text",text:`No context found around ${new Date(n).toLocaleString()} (${t} records before, ${s} records after)`}]};let p=g=>new Date(g).toLocaleString("en-US",{month:"short",day:"numeric",year:"numeric"}),f=g=>new Date(g).toLocaleString("en-US",{hour:"numeric",minute:"2-digit",hour12:!0}),d=g=>new Date(g).toLocaleString("en-US",{month:"short",day:"numeric",hour:"numeric",minute:"2-digit",hour12:!0}),v=g=>g?Math.ceil(g.length/4):0,h=[];h.push(`# Timeline around anchor: ${o}`),h.push(`**Window:** ${t} records before \u2192 ${s} records after | **Items:** ${u?.length??0}`),h.push(""),h.push("**Legend:** \u{1F3AF} session-request | \u{1F534} bugfix | \u{1F7E3} feature | \u{1F504} refactor | \u2705 change | \u{1F535} discovery | \u{1F9E0} decision"),h.push("");let m=new Map;for(let g of u){let b=p(g.epoch);m.has(b)||m.set(b,[]),m.get(b).push(g)}let y=Array.from(m.entries()).sort((g,b)=>{let w=new Date(g[0]).getTime(),P=new Date(b[0]).getTime();return w-P});for(let[g,b]of y){h.push(`### ${g}`),h.push("");let w=null,P="",T=!1;for(let k of b){let D=typeof o=="number"&&k.type==="observation"&&k.data.id===o||typeof o=="string"&&o.startsWith("S")&&k.type==="session"&&`S${k.data.id}`===o;if(k.type==="session"){T&&(h.push(""),T=!1,w=null,P="");let A=k.data,$=A.request||"Session summary",N=`claude-mem://session-summary/${A.id}`,C=D?" \u2190 **ANCHOR**":"";h.push(`**\u{1F3AF} #S${A.id}** ${$} (${d(k.epoch)}) [\u2192](${N})${C}`),h.push("")}else if(k.type==="prompt"){T&&(h.push(""),T=!1,w=null,P="");let A=k.data,$=A.prompt_text.length>100?A.prompt_text.substring(0,100)+"...":A.prompt_text;h.push(`**\u{1F4AC} User Prompt #${A.prompt_number}** (${d(k.epoch)})`),h.push(`> ${$}`),h.push("")}else if(k.type==="observation"){let A=k.data,$="General";$!==w&&(T&&h.push(""),h.push(`**${$}**`),h.push("| ID | Time | T | Title | Tokens |"),h.push("|----|------|---|-------|--------|"),w=$,T=!0,P="");let N="\u2022";switch(A.type){case"bugfix":N="\u{1F534}";break;case"feature":N="\u{1F7E3}";break;case"refactor":N="\u{1F504}";break;case"change":N="\u2705";break;case"discovery":N="\u{1F535}";break;case"decision":N="\u{1F9E0}";break}let C=f(k.epoch),O=A.title||"Untitled",j=v(A.narrative),H=C!==P?C:"\u2033";P=C;let V=D?" \u2190 **ANCHOR**":"";h.push(`| #${A.id} | ${H} | ${N} | ${O}${V} | ~${j} |`)}}T&&h.push("")}return{content:[{type:"text",text:h.join(` +`)}]}}catch(r){return{content:[{type:"text",text:`Failed to get recent context: ${r.message}`}],isError:!0}}}async getContextTimeline(e){try{let{anchor:r,depth_before:t=10,depth_after:s=10,project:i}=e,n,o=r,l;if(typeof r=="number"){let g=this.sessionStore.getObservationById(r);if(!g)return{content:[{type:"text",text:`Observation #${r} not found`}],isError:!0};n=g.created_at_epoch,l=this.sessionStore.getTimelineAroundObservation(r,n,t,s,i)}else if(typeof r=="string")if(r.startsWith("S")||r.startsWith("#S")){let g=r.replace(/^#?S/,""),b=parseInt(g,10),w=this.sessionStore.getSessionSummariesByIds([b]);if(w.length===0)return{content:[{type:"text",text:`Session #${b} not found`}],isError:!0};n=w[0].created_at_epoch,o=`S${b}`,l=this.sessionStore.getTimelineAroundTimestamp(n,t,s,i)}else{let g=new Date(r);if(isNaN(g.getTime()))return{content:[{type:"text",text:`Invalid timestamp: ${r}`}],isError:!0};n=g.getTime(),l=this.sessionStore.getTimelineAroundTimestamp(n,t,s,i)}else return{content:[{type:"text",text:'Invalid anchor: must be observation ID (number), session ID (e.g., "S123"), or ISO timestamp'}],isError:!0};let c=[...l.observations.map(g=>({type:"observation",data:g,epoch:g.created_at_epoch})),...l.sessions.map(g=>({type:"session",data:g,epoch:g.created_at_epoch})),...l.prompts.map(g=>({type:"prompt",data:g,epoch:g.created_at_epoch}))];c.sort((g,b)=>g.epoch-b.epoch);let u=this.timelineService.filterByDepth(c,o,n,t,s);if(!u||u.length===0)return{content:[{type:"text",text:`No context found around ${new Date(n).toLocaleString()} (${t} records before, ${s} records after)`}]};let p=g=>new Date(g).toLocaleString("en-US",{month:"short",day:"numeric",year:"numeric"}),f=g=>new Date(g).toLocaleString("en-US",{hour:"numeric",minute:"2-digit",hour12:!0}),d=g=>new Date(g).toLocaleString("en-US",{month:"short",day:"numeric",hour:"numeric",minute:"2-digit",hour12:!0}),v=g=>g?Math.ceil(g.length/4):0,h=[];h.push(`# Timeline around anchor: ${o}`),h.push(`**Window:** ${t} records before \u2192 ${s} records after | **Items:** ${u?.length??0}`),h.push(""),h.push("**Legend:** \u{1F3AF} session-request | \u{1F534} bugfix | \u{1F7E3} feature | \u{1F504} refactor | \u2705 change | \u{1F535} discovery | \u{1F9E0} decision"),h.push("");let m=new Map;for(let g of u){let b=p(g.epoch);m.has(b)||m.set(b,[]),m.get(b).push(g)}let y=Array.from(m.entries()).sort((g,b)=>{let w=new Date(g[0]).getTime(),P=new Date(b[0]).getTime();return w-P});for(let[g,b]of y){h.push(`### ${g}`),h.push("");let w=null,P="",T=!1;for(let k of b){let D=typeof o=="number"&&k.type==="observation"&&k.data.id===o||typeof o=="string"&&o.startsWith("S")&&k.type==="session"&&`S${k.data.id}`===o;if(k.type==="session"){T&&(h.push(""),T=!1,w=null,P="");let A=k.data,$=A.request||"Session summary",N=`claude-mem://session-summary/${A.id}`,C=D?" \u2190 **ANCHOR**":"";h.push(`**\u{1F3AF} #S${A.id}** ${$} (${d(k.epoch)}) [\u2192](${N})${C}`),h.push("")}else if(k.type==="prompt"){T&&(h.push(""),T=!1,w=null,P="");let A=k.data,$=A.prompt_text.length>100?A.prompt_text.substring(0,100)+"...":A.prompt_text;h.push(`**\u{1F4AC} User Prompt #${A.prompt_number}** (${d(k.epoch)})`),h.push(`> ${$}`),h.push("")}else if(k.type==="observation"){let A=k.data,$="General";$!==w&&(T&&h.push(""),h.push(`**${$}**`),h.push("| ID | Time | T | Title | Tokens |"),h.push("|----|------|---|-------|--------|"),w=$,T=!0,P="");let N="\u2022";switch(A.type){case"bugfix":N="\u{1F534}";break;case"feature":N="\u{1F7E3}";break;case"refactor":N="\u{1F504}";break;case"change":N="\u2705";break;case"discovery":N="\u{1F535}";break;case"decision":N="\u{1F9E0}";break}let C=f(k.epoch),O=A.title||"Untitled",j=v(A.narrative),H=C!==P?C:"\u2033";P=C;let V=D?" \u2190 **ANCHOR**":"";h.push(`| #${A.id} | ${H} | ${N} | ${O}${V} | ~${j} |`)}}T&&h.push("")}return{content:[{type:"text",text:h.join(` `)}]}}catch(r){return{content:[{type:"text",text:`Timeline query failed: ${r.message}`}],isError:!0}}}async getTimelineByQuery(e){try{let{query:r,mode:t="auto",depth_before:s=10,depth_after:i=10,limit:n=5,project:o}=e,l=[];if(this.chromaSync)try{ie("[search-server] Using hybrid semantic search for timeline query");let c=await this.queryChroma(r,100);if(ie(`[search-server] Chroma returned ${c.ids.length} semantic matches`),c.ids.length>0){let u=Date.now()-7776e6,p=c.ids.filter((f,d)=>{let v=c.metadatas[d];return v&&v.created_at_epoch>u});ie(`[search-server] ${p.length} results within 90-day window`),p.length>0&&(l=this.sessionStore.getObservationsByIds(p,{orderBy:"date_desc",limit:t==="auto"?1:n}),ie(`[search-server] Hydrated ${l.length} observations from SQLite`))}}catch(c){ie("[search-server] Chroma query failed - no results (FTS5 fallback removed):",c.message)}if(l.length===0)return{content:[{type:"text",text:`No observations found matching "${r}". Try a different search query.`}]};if(t==="interactive"){let c=[];c.push("# Timeline Anchor Search Results"),c.push(""),c.push(`Found ${l.length} observation(s) matching "${r}"`),c.push(""),c.push("To get timeline context around any of these observations, use the `get_context_timeline` tool with the observation ID as the anchor."),c.push(""),c.push(`**Top ${l.length} matches:**`),c.push("");for(let u=0;u({type:"observation",data:w,epoch:w.created_at_epoch})),...(u.sessions||[]).map(w=>({type:"session",data:w,epoch:w.created_at_epoch})),...(u.prompts||[]).map(w=>({type:"prompt",data:w,epoch:w.created_at_epoch}))];p.sort((w,P)=>w.epoch-P.epoch);let f=this.timelineService.filterByDepth(p,c.id,0,s,i);if(!f||f.length===0)return{content:[{type:"text",text:`Found observation #${c.id} matching "${r}", but no timeline context available (${s} records before, ${i} records after).`}]};let d=w=>new Date(w).toLocaleString("en-US",{month:"short",day:"numeric",year:"numeric"}),v=w=>new Date(w).toLocaleString("en-US",{hour:"numeric",minute:"2-digit",hour12:!0}),h=w=>new Date(w).toLocaleString("en-US",{month:"short",day:"numeric",hour:"numeric",minute:"2-digit",hour12:!0}),m=w=>w?Math.ceil(w.length/4):0,y=[];y.push(`# Timeline for query: "${r}"`),y.push(`**Anchor:** Observation #${c.id} - ${c.title||"Untitled"}`),y.push(`**Window:** ${s} records before \u2192 ${i} records after | **Items:** ${f?.length??0}`),y.push(""),y.push("**Legend:** \u{1F3AF} session-request | \u{1F534} bugfix | \u{1F7E3} feature | \u{1F504} refactor | \u2705 change | \u{1F535} discovery | \u{1F9E0} decision"),y.push("");let g=new Map;for(let w of f){let P=d(w.epoch);g.has(P)||g.set(P,[]),g.get(P).push(w)}let b=Array.from(g.entries()).sort((w,P)=>{let T=new Date(w[0]).getTime(),k=new Date(P[0]).getTime();return T-k});for(let[w,P]of b){y.push(`### ${w}`),y.push("");let T=null,k="",D=!1;for(let A of P){let $=A.type==="observation"&&A.data.id===c.id;if(A.type==="session"){D&&(y.push(""),D=!1,T=null,k="");let N=A.data,C=N.request||"Session summary",O=`claude-mem://session-summary/${N.id}`;y.push(`**\u{1F3AF} #S${N.id}** ${C} (${h(A.epoch)}) [\u2192](${O})`),y.push("")}else if(A.type==="prompt"){D&&(y.push(""),D=!1,T=null,k="");let N=A.data,C=N.prompt_text.length>100?N.prompt_text.substring(0,100)+"...":N.prompt_text;y.push(`**\u{1F4AC} User Prompt #${N.prompt_number}** (${h(A.epoch)})`),y.push(`> ${C}`),y.push("")}else if(A.type==="observation"){let N=A.data,C="General";C!==T&&(D&&y.push(""),y.push(`**${C}**`),y.push("| ID | Time | T | Title | Tokens |"),y.push("|----|------|---|-------|--------|"),T=C,D=!0,k="");let O="\u2022";switch(N.type){case"bugfix":O="\u{1F534}";break;case"feature":O="\u{1F7E3}";break;case"refactor":O="\u{1F504}";break;case"change":O="\u2705";break;case"discovery":O="\u{1F535}";break;case"decision":O="\u{1F9E0}";break}let j=v(A.epoch),F=N.title||"Untitled",H=m(N.narrative),Q=j!==k?j:"\u2033";k=j;let K=$?" \u2190 **ANCHOR**":"";y.push(`| #${N.id} | ${Q} | ${O} | ${F}${K} | ~${H} |`)}}D&&y.push("")}return{content:[{type:"text",text:y.join(` `)}]}}}catch(r){return{content:[{type:"text",text:`Timeline query failed: ${r.message}`}],isError:!0}}}};var _l=class{formatSearchTips(){return` @@ -1037,7 +1037,7 @@ Other tips: WHERE project IS NOT NULL GROUP BY project ORDER BY MAX(created_at_epoch) DESC - `).all().map(n=>n.project);r.json({projects:i})}catch(t){U.failure("WORKER","Get projects failed",{},t),r.status(500).json({error:t.message})}}handleGetProcessingStatus(e,r){let t=this.sessionManager.isAnySessionProcessing(),s=this.sessionManager.getTotalActiveWork();r.json({isProcessing:t,queueDepth:s})}handleSetProcessing(e,r){try{this.workerService.broadcastProcessingStatus();let t=this.sessionManager.isAnySessionProcessing(),s=this.sessionManager.getTotalQueueDepth(),i=this.sessionManager.getActiveSessionCount();U.debug("WORKER","Processing status broadcast",{isProcessing:t,queueDepth:s,activeSessions:i}),r.json({status:"ok",isProcessing:t})}catch(t){U.failure("WORKER","Failed to broadcast processing status",{},t),r.status(500).json({error:t.message})}}parsePaginationParams(e){let r=parseInt(e.query.offset,10)||0,t=Math.min(parseInt(e.query.limit,10)||20,100),s=e.query.project;return{offset:r,limit:t,project:s}}};_t();var Ol=class{constructor(e){this.searchManager=e}setupRoutes(e){e.get("/api/search",this.handleUnifiedSearch.bind(this)),e.get("/api/timeline",this.handleUnifiedTimeline.bind(this)),e.get("/api/decisions",this.handleDecisions.bind(this)),e.get("/api/changes",this.handleChanges.bind(this)),e.get("/api/how-it-works",this.handleHowItWorks.bind(this)),e.get("/api/search/observations",this.handleSearchObservations.bind(this)),e.get("/api/search/sessions",this.handleSearchSessions.bind(this)),e.get("/api/search/prompts",this.handleSearchPrompts.bind(this)),e.get("/api/search/by-concept",this.handleSearchByConcept.bind(this)),e.get("/api/search/by-file",this.handleSearchByFile.bind(this)),e.get("/api/search/by-type",this.handleSearchByType.bind(this)),e.get("/api/context/recent",this.handleGetRecentContext.bind(this)),e.get("/api/context/timeline",this.handleGetContextTimeline.bind(this)),e.get("/api/context/preview",this.handleContextPreview.bind(this)),e.get("/api/context/inject",this.handleContextInject.bind(this)),e.get("/api/timeline/by-query",this.handleGetTimelineByQuery.bind(this)),e.get("/api/search/help",this.handleSearchHelp.bind(this))}async handleUnifiedSearch(e,r){try{let t=await this.searchManager.search(e.query);r.json(t.content)}catch(t){U.failure("WORKER","Unified search failed",{},t),r.status(500).json({error:t.message})}}async handleUnifiedTimeline(e,r){try{let t=await this.searchManager.timeline(e.query);r.json(t.content)}catch(t){U.failure("WORKER","Unified timeline failed",{},t),r.status(500).json({error:t.message})}}async handleDecisions(e,r){try{let t=await this.searchManager.decisions(e.query);r.json(t.content)}catch(t){U.failure("WORKER","Decisions search failed",{},t),r.status(500).json({error:t.message})}}async handleChanges(e,r){try{let t=await this.searchManager.changes(e.query);r.json(t.content)}catch(t){U.failure("WORKER","Changes search failed",{},t),r.status(500).json({error:t.message})}}async handleHowItWorks(e,r){try{let t=await this.searchManager.howItWorks(e.query);r.json(t.content)}catch(t){U.failure("WORKER","How it works search failed",{},t),r.status(500).json({error:t.message})}}async handleSearchObservations(e,r){try{let t=await this.searchManager.searchObservations(e.query);r.json(t.content)}catch(t){U.failure("WORKER","Search failed",{},t),r.status(500).json({error:t.message})}}async handleSearchSessions(e,r){try{let t=await this.searchManager.searchSessions(e.query);r.json(t.content)}catch(t){U.failure("WORKER","Search failed",{},t),r.status(500).json({error:t.message})}}async handleSearchPrompts(e,r){try{let t=await this.searchManager.searchUserPrompts(e.query);r.json(t.content)}catch(t){U.failure("WORKER","Search failed",{},t),r.status(500).json({error:t.message})}}async handleSearchByConcept(e,r){try{let t=await this.searchManager.findByConcept(e.query);r.json(t.content)}catch(t){U.failure("WORKER","Search failed",{},t),r.status(500).json({error:t.message})}}async handleSearchByFile(e,r){try{let t=await this.searchManager.findByFile(e.query);r.json(t.content)}catch(t){U.failure("WORKER","Search failed",{},t),r.status(500).json({error:t.message})}}async handleSearchByType(e,r){try{let t=await this.searchManager.findByType(e.query);r.json(t.content)}catch(t){U.failure("WORKER","Search failed",{},t),r.status(500).json({error:t.message})}}async handleGetRecentContext(e,r){try{let t=await this.searchManager.getRecentContext(e.query);r.json(t.content)}catch(t){U.failure("WORKER","Search failed",{},t),r.status(500).json({error:t.message})}}async handleGetContextTimeline(e,r){try{let t=await this.searchManager.getContextTimeline(e.query);r.json(t.content)}catch(t){U.failure("WORKER","Search failed",{},t),r.status(500).json({error:t.message})}}async handleContextPreview(e,r){try{let t=e.query.project;if(!t){r.status(400).json({error:"Project parameter is required"});return}let{generateContext:s}=await Promise.resolve().then(()=>(bf(),yf)),i=`/preview/${t}`,n=await s({session_id:"preview-"+Date.now(),cwd:i},!0);r.setHeader("Content-Type","text/plain; charset=utf-8"),r.send(n)}catch(t){U.failure("WORKER","Context preview generation failed",{},t),r.status(500).json({error:"Failed to generate context preview",message:t.message})}}async handleContextInject(e,r){try{let t=e.query.project,s=e.query.colors==="true";if(!t){r.status(400).json({error:"Project parameter is required"});return}let{generateContext:i}=await Promise.resolve().then(()=>(bf(),yf)),n=`/context/${t}`,o=await i({session_id:"context-inject-"+Date.now(),cwd:n},s);r.setHeader("Content-Type","text/plain; charset=utf-8"),r.send(o)}catch(t){U.failure("WORKER","Context injection failed",{},t),r.status(500).json({error:"Failed to generate context",message:t.message})}}async handleGetTimelineByQuery(e,r){try{let t=await this.searchManager.getTimelineByQuery(e.query);r.json(t.content)}catch(t){U.failure("WORKER","Search failed",{},t),r.status(500).json({error:t.message})}}handleSearchHelp(e,r){r.json({title:"Claude-Mem Search API",description:"HTTP API for searching persistent memory",endpoints:[{path:"/api/search/observations",method:"GET",description:"Search observations using full-text search",parameters:{query:"Search query (required)",format:'Response format: "index" or "full" (default: "full")',limit:"Number of results (default: 20)",project:"Filter by project name (optional)"}},{path:"/api/search/sessions",method:"GET",description:"Search session summaries using full-text search",parameters:{query:"Search query (required)",format:'Response format: "index" or "full" (default: "full")',limit:"Number of results (default: 20)"}},{path:"/api/search/prompts",method:"GET",description:"Search user prompts using full-text search",parameters:{query:"Search query (required)",format:'Response format: "index" or "full" (default: "full")',limit:"Number of results (default: 20)",project:"Filter by project name (optional)"}},{path:"/api/search/by-concept",method:"GET",description:"Find observations by concept tag",parameters:{concept:"Concept tag (required): discovery, decision, bugfix, feature, refactor",format:'Response format: "index" or "full" (default: "full")',limit:"Number of results (default: 10)",project:"Filter by project name (optional)"}},{path:"/api/search/by-file",method:"GET",description:"Find observations and sessions by file path",parameters:{filePath:"File path or partial path (required)",format:'Response format: "index" or "full" (default: "full")',limit:"Number of results per type (default: 10)",project:"Filter by project name (optional)"}},{path:"/api/search/by-type",method:"GET",description:"Find observations by type",parameters:{type:"Observation type (required): discovery, decision, bugfix, feature, refactor",format:'Response format: "index" or "full" (default: "full")',limit:"Number of results (default: 10)",project:"Filter by project name (optional)"}},{path:"/api/context/recent",method:"GET",description:"Get recent session context including summaries and observations",parameters:{project:"Project name (default: current directory)",limit:"Number of recent sessions (default: 3)"}},{path:"/api/context/timeline",method:"GET",description:"Get unified timeline around a specific point in time",parameters:{anchor:'Anchor point: observation ID, session ID (e.g., "S123"), or ISO timestamp (required)',depth_before:"Number of records before anchor (default: 10)",depth_after:"Number of records after anchor (default: 10)",project:"Filter by project name (optional)"}},{path:"/api/timeline/by-query",method:"GET",description:"Search for best match, then get timeline around it",parameters:{query:"Search query (required)",mode:'Search mode: "auto", "observations", or "sessions" (default: "auto")',depth_before:"Number of records before match (default: 10)",depth_after:"Number of records after match (default: 10)",project:"Filter by project name (optional)"}},{path:"/api/search/help",method:"GET",description:"Get this help documentation"}],examples:['curl "http://localhost:37777/api/search/observations?query=authentication&format=index&limit=5"','curl "http://localhost:37777/api/search/by-type?type=bugfix&limit=10"','curl "http://localhost:37777/api/context/recent?project=claude-mem&limit=3"','curl "http://localhost:37777/api/context/timeline?anchor=123&depth_before=5&depth_after=5"']})}};var Hn=vt(require("path"),1),Vt=require("fs"),_f=require("os");Ia();_t();var xf=require("child_process"),qs=require("fs"),jw=require("os"),Xi=require("path");_t();var Qi=(0,Xi.join)((0,jw.homedir)(),".claude","plugins","marketplaces","thedotmack");function yr(a){return(0,xf.execSync)(`git ${a}`,{cwd:Qi,encoding:"utf-8",timeout:3e4}).trim()}function $w(a,e=6e4){return(0,xf.execSync)(a,{cwd:Qi,encoding:"utf-8",timeout:e}).trim()}function Cl(){let a=(0,Xi.join)(Qi,".git");if(!(0,qs.existsSync)(a))return{branch:null,isBeta:!1,isGitRepo:!1,isDirty:!1,canSwitch:!1,error:"Installed plugin is not a git repository"};try{let e=yr("rev-parse --abbrev-ref HEAD"),t=yr("status --porcelain").length>0,s=e.startsWith("beta");return{branch:e,isBeta:s,isGitRepo:!0,isDirty:t,canSwitch:!0}}catch(e){return U.error("BRANCH","Failed to get branch info",{},e),{branch:null,isBeta:!1,isGitRepo:!0,isDirty:!1,canSwitch:!1,error:e.message}}}async function Mw(a){let e=Cl();if(!e.isGitRepo)return{success:!1,error:"Installed plugin is not a git repository. Please reinstall."};if(e.branch===a)return{success:!0,branch:a,message:`Already on branch ${a}`};try{U.info("BRANCH","Starting branch switch",{from:e.branch,to:a}),U.debug("BRANCH","Discarding local changes"),yr("checkout -- ."),yr("clean -fd"),U.debug("BRANCH","Fetching from origin"),yr("fetch origin"),U.debug("BRANCH","Checking out branch",{branch:a});try{yr(`checkout ${a}`)}catch{yr(`checkout -b ${a} origin/${a}`)}U.debug("BRANCH","Pulling latest"),yr(`pull origin ${a}`);let r=(0,Xi.join)(Qi,".install-version");return(0,qs.existsSync)(r)&&(0,qs.unlinkSync)(r),U.debug("BRANCH","Running npm install"),$w("npm install",12e4),U.success("BRANCH","Branch switch complete",{branch:a}),{success:!0,branch:a,message:`Switched to ${a}. Worker will restart automatically.`}}catch(r){U.error("BRANCH","Branch switch failed",{targetBranch:a},r);try{e.branch&&yr(`checkout ${e.branch}`)}catch{}return{success:!1,error:`Branch switch failed: ${r.message}`}}}async function Lw(){let a=Cl();if(!a.isGitRepo||!a.branch)return{success:!1,error:"Cannot pull updates: not a git repository"};try{U.info("BRANCH","Pulling updates",{branch:a.branch}),yr("checkout -- ."),yr("fetch origin"),yr(`pull origin ${a.branch}`);let e=(0,Xi.join)(Qi,".install-version");return(0,qs.existsSync)(e)&&(0,qs.unlinkSync)(e),$w("npm install",12e4),U.success("BRANCH","Updates pulled",{branch:a.branch}),{success:!0,branch:a.branch,message:`Updated ${a.branch}. Worker will restart automatically.`}}catch(e){return U.error("BRANCH","Pull failed",{},e),{success:!1,error:`Pull failed: ${e.message}`}}}gf();var kl=class{constructor(e){this.settingsManager=e}setupRoutes(e){e.get("/api/settings",this.handleGetSettings.bind(this)),e.post("/api/settings",this.handleUpdateSettings.bind(this)),e.get("/api/mcp/status",this.handleGetMcpStatus.bind(this)),e.post("/api/mcp/toggle",this.handleToggleMcp.bind(this)),e.get("/api/branch/status",this.handleGetBranchStatus.bind(this)),e.post("/api/branch/switch",this.handleSwitchBranch.bind(this)),e.post("/api/branch/update",this.handleUpdateBranch.bind(this))}handleGetSettings(e,r){try{let t=Hn.default.join((0,_f.homedir)(),".claude-mem","settings.json");if(!(0,Vt.existsSync)(t)){r.json({CLAUDE_MEM_MODEL:"claude-haiku-4-5",CLAUDE_MEM_CONTEXT_OBSERVATIONS:"50",CLAUDE_MEM_WORKER_PORT:"37777",CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS:"true",CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS:"true",CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT:"true",CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT:"true",CLAUDE_MEM_CONTEXT_OBSERVATION_TYPES:Zi,CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS:Ki,CLAUDE_MEM_CONTEXT_FULL_COUNT:"5",CLAUDE_MEM_CONTEXT_FULL_FIELD:"narrative",CLAUDE_MEM_CONTEXT_SESSION_COUNT:"10",CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY:"true",CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE:"false"});return}let s=(0,Vt.readFileSync)(t,"utf-8"),n=JSON.parse(s).env||{};r.json({CLAUDE_MEM_MODEL:n.CLAUDE_MEM_MODEL||"claude-haiku-4-5",CLAUDE_MEM_CONTEXT_OBSERVATIONS:n.CLAUDE_MEM_CONTEXT_OBSERVATIONS||"50",CLAUDE_MEM_WORKER_PORT:n.CLAUDE_MEM_WORKER_PORT||"37777",CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS:n.CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS||"true",CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS:n.CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS||"true",CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT:n.CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT||"true",CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT:n.CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT||"true",CLAUDE_MEM_CONTEXT_OBSERVATION_TYPES:n.CLAUDE_MEM_CONTEXT_OBSERVATION_TYPES||Zi,CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS:n.CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS||Ki,CLAUDE_MEM_CONTEXT_FULL_COUNT:n.CLAUDE_MEM_CONTEXT_FULL_COUNT||"5",CLAUDE_MEM_CONTEXT_FULL_FIELD:n.CLAUDE_MEM_CONTEXT_FULL_FIELD||"narrative",CLAUDE_MEM_CONTEXT_SESSION_COUNT:n.CLAUDE_MEM_CONTEXT_SESSION_COUNT||"10",CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY:n.CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY||"true",CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE:n.CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE||"false"})}catch(t){U.failure("WORKER","Get settings failed",{},t),r.status(500).json({error:t.message})}}handleUpdateSettings(e,r){try{if(e.body.CLAUDE_MEM_CONTEXT_OBSERVATIONS){let o=parseInt(e.body.CLAUDE_MEM_CONTEXT_OBSERVATIONS,10);if(isNaN(o)||o<1||o>200){r.status(400).json({success:!1,error:"CLAUDE_MEM_CONTEXT_OBSERVATIONS must be between 1 and 200"});return}}if(e.body.CLAUDE_MEM_WORKER_PORT){let o=parseInt(e.body.CLAUDE_MEM_WORKER_PORT,10);if(isNaN(o)||o<1024||o>65535){r.status(400).json({success:!1,error:"CLAUDE_MEM_WORKER_PORT must be between 1024 and 65535"});return}}let t=this.validateContextSettings(e.body);if(!t.valid){r.status(400).json({success:!1,error:t.error});return}let s=Hn.default.join((0,_f.homedir)(),".claude-mem","settings.json"),i={env:{}};if((0,Vt.existsSync)(s)){let o=(0,Vt.readFileSync)(s,"utf-8");i=JSON.parse(o),i.env||(i.env={})}let n=["CLAUDE_MEM_MODEL","CLAUDE_MEM_CONTEXT_OBSERVATIONS","CLAUDE_MEM_WORKER_PORT","CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS","CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS","CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT","CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT","CLAUDE_MEM_CONTEXT_OBSERVATION_TYPES","CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS","CLAUDE_MEM_CONTEXT_FULL_COUNT","CLAUDE_MEM_CONTEXT_FULL_FIELD","CLAUDE_MEM_CONTEXT_SESSION_COUNT","CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY","CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE"];for(let o of n)e.body[o]!==void 0&&(i.env[o]=e.body[o]);(0,Vt.writeFileSync)(s,JSON.stringify(i,null,2),"utf-8"),U.info("WORKER","Settings updated"),r.json({success:!0,message:"Settings updated successfully"})}catch(t){U.failure("WORKER","Update settings failed",{},t),r.status(500).json({success:!1,error:String(t)})}}handleGetMcpStatus(e,r){try{let t=this.isMcpEnabled();r.json({enabled:t})}catch(t){U.failure("WORKER","Get MCP status failed",{},t),r.status(500).json({error:t.message})}}handleToggleMcp(e,r){try{let{enabled:t}=e.body;if(typeof t!="boolean"){r.status(400).json({error:"enabled must be a boolean"});return}this.toggleMcp(t),r.json({success:!0,enabled:this.isMcpEnabled()})}catch(t){U.failure("WORKER","Toggle MCP failed",{},t),r.status(500).json({success:!1,error:t.message})}}handleGetBranchStatus(e,r){try{let t=Cl();r.json(t)}catch(t){U.failure("WORKER","Failed to get branch status",{},t),r.status(500).json({error:t.message})}}async handleSwitchBranch(e,r){try{let{branch:t}=e.body;if(!t){r.status(400).json({success:!1,error:"Missing branch parameter"});return}let s=["main","beta/7.0"];if(!s.includes(t)){r.status(400).json({success:!1,error:`Invalid branch. Allowed: ${s.join(", ")}`});return}U.info("WORKER","Branch switch requested",{branch:t});let i=await Mw(t);i.success&&setTimeout(()=>{U.info("WORKER","Restarting worker after branch switch"),process.exit(0)},1e3),r.json(i)}catch(t){U.failure("WORKER","Branch switch failed",{},t),r.status(500).json({success:!1,error:t.message})}}async handleUpdateBranch(e,r){try{U.info("WORKER","Branch update requested");let t=await Lw();t.success&&setTimeout(()=>{U.info("WORKER","Restarting worker after branch update"),process.exit(0)},1e3),r.json(t)}catch(t){U.failure("WORKER","Branch update failed",{},t),r.status(500).json({success:!1,error:t.message})}}validateContextSettings(e){let r=["CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS","CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS","CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT","CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT","CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY","CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE"];for(let t of r)if(e[t]&&!["true","false"].includes(e[t]))return{valid:!1,error:`${t} must be "true" or "false"`};if(e.CLAUDE_MEM_CONTEXT_FULL_COUNT){let t=parseInt(e.CLAUDE_MEM_CONTEXT_FULL_COUNT,10);if(isNaN(t)||t<0||t>20)return{valid:!1,error:"CLAUDE_MEM_CONTEXT_FULL_COUNT must be between 0 and 20"}}if(e.CLAUDE_MEM_CONTEXT_SESSION_COUNT){let t=parseInt(e.CLAUDE_MEM_CONTEXT_SESSION_COUNT,10);if(isNaN(t)||t<1||t>50)return{valid:!1,error:"CLAUDE_MEM_CONTEXT_SESSION_COUNT must be between 1 and 50"}}if(e.CLAUDE_MEM_CONTEXT_FULL_FIELD&&!["narrative","facts"].includes(e.CLAUDE_MEM_CONTEXT_FULL_FIELD))return{valid:!1,error:'CLAUDE_MEM_CONTEXT_FULL_FIELD must be "narrative" or "facts"'};if(e.CLAUDE_MEM_CONTEXT_OBSERVATION_TYPES){let t=e.CLAUDE_MEM_CONTEXT_OBSERVATION_TYPES.split(",").map(s=>s.trim());for(let s of t)if(s&&!zn.includes(s))return{valid:!1,error:`Invalid observation type: ${s}. Valid types: ${zn.join(", ")}`}}if(e.CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS){let t=e.CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS.split(",").map(s=>s.trim());for(let s of t)if(s&&!Bn.includes(s))return{valid:!1,error:`Invalid observation concept: ${s}. Valid concepts: ${Bn.join(", ")}`}}return{valid:!0}}isMcpEnabled(){let e=zr(),r=Hn.default.join(e,"plugin",".mcp.json");return(0,Vt.existsSync)(r)}toggleMcp(e){try{let r=zr(),t=Hn.default.join(r,"plugin",".mcp.json"),s=Hn.default.join(r,"plugin",".mcp.json.disabled");e&&(0,Vt.existsSync)(s)?((0,Vt.renameSync)(s,t),U.info("WORKER","MCP search server enabled")):!e&&(0,Vt.existsSync)(t)?((0,Vt.renameSync)(t,s),U.info("WORKER","MCP search server disabled")):U.debug("WORKER","MCP toggle no-op (already in desired state)",{enabled:e})}catch(r){throw U.failure("WORKER","Failed to toggle MCP",{enabled:e},r),r}}};var Il=class{app;server=null;startTime=Date.now();mcpClient;dbManager;sessionManager;sseBroadcaster;sdkAgent;paginationHelper;settingsManager;viewerRoutes;sessionRoutes;dataRoutes;searchRoutes;settingsRoutes;constructor(){this.app=(0,qw.default)(),this.dbManager=new Jc,this.sessionManager=new Yc(this.dbManager),this.sseBroadcaster=new el,this.sdkAgent=new vl(this.dbManager,this.sessionManager),this.paginationHelper=new yl(this.dbManager),this.settingsManager=new bl(this.dbManager),this.sessionManager.setOnSessionDeleted(()=>{this.broadcastProcessingStatus()}),this.mcpClient=new wn({name:"worker-search-proxy",version:"1.0.0"},{capabilities:{}}),this.viewerRoutes=new Sl(this.sseBroadcaster,this.dbManager,this.sessionManager),this.sessionRoutes=new wl(this.sessionManager,this.dbManager,this.sdkAgent,this.sseBroadcaster,this),this.dataRoutes=new Tl(this.paginationHelper,this.dbManager,this.sessionManager,this.sseBroadcaster,this,this.startTime),this.searchRoutes=null,this.settingsRoutes=new kl(this.settingsManager),this.setupMiddleware(),this.setupRoutes()}setupMiddleware(){Tw(this.summarizeRequestBody.bind(this)).forEach(r=>this.app.use(r))}setupRoutes(){this.app.get("/api/health",(e,r)=>{r.status(200).json({status:"ok"})}),this.viewerRoutes.setupRoutes(this.app),this.sessionRoutes.setupRoutes(this.app),this.dataRoutes.setupRoutes(this.app),this.searchRoutes&&this.searchRoutes.setupRoutes(this.app),this.settingsRoutes.setupRoutes(this.app)}async cleanupOrphanedProcesses(){try{let{execSync:e}=await import("child_process");try{let r=e("pgrep -fl uvx",{encoding:"utf-8",stdio:"pipe",windowsHide:!0}).trim();if(r){let t=r.split(` + `).all().map(n=>n.project);r.json({projects:i})}catch(t){U.failure("WORKER","Get projects failed",{},t),r.status(500).json({error:t.message})}}handleGetProcessingStatus(e,r){let t=this.sessionManager.isAnySessionProcessing(),s=this.sessionManager.getTotalActiveWork();r.json({isProcessing:t,queueDepth:s})}handleSetProcessing(e,r){try{this.workerService.broadcastProcessingStatus();let t=this.sessionManager.isAnySessionProcessing(),s=this.sessionManager.getTotalQueueDepth(),i=this.sessionManager.getActiveSessionCount();U.debug("WORKER","Processing status broadcast",{isProcessing:t,queueDepth:s,activeSessions:i}),r.json({status:"ok",isProcessing:t})}catch(t){U.failure("WORKER","Failed to broadcast processing status",{},t),r.status(500).json({error:t.message})}}parsePaginationParams(e){let r=parseInt(e.query.offset,10)||0,t=Math.min(parseInt(e.query.limit,10)||20,100),s=e.query.project;return{offset:r,limit:t,project:s}}};_t();var Ol=class{constructor(e){this.searchManager=e}setupRoutes(e){e.get("/api/search",this.handleUnifiedSearch.bind(this)),e.get("/api/timeline",this.handleUnifiedTimeline.bind(this)),e.get("/api/decisions",this.handleDecisions.bind(this)),e.get("/api/changes",this.handleChanges.bind(this)),e.get("/api/how-it-works",this.handleHowItWorks.bind(this)),e.get("/api/search/observations",this.handleSearchObservations.bind(this)),e.get("/api/search/sessions",this.handleSearchSessions.bind(this)),e.get("/api/search/prompts",this.handleSearchPrompts.bind(this)),e.get("/api/search/by-concept",this.handleSearchByConcept.bind(this)),e.get("/api/search/by-file",this.handleSearchByFile.bind(this)),e.get("/api/search/by-type",this.handleSearchByType.bind(this)),e.get("/api/context/recent",this.handleGetRecentContext.bind(this)),e.get("/api/context/timeline",this.handleGetContextTimeline.bind(this)),e.get("/api/context/preview",this.handleContextPreview.bind(this)),e.get("/api/context/inject",this.handleContextInject.bind(this)),e.get("/api/timeline/by-query",this.handleGetTimelineByQuery.bind(this)),e.get("/api/search/help",this.handleSearchHelp.bind(this))}async handleUnifiedSearch(e,r){try{let t=await this.searchManager.search(e.query);r.json(t.content)}catch(t){U.failure("WORKER","Unified search failed",{},t),r.status(500).json({error:t.message})}}async handleUnifiedTimeline(e,r){try{let t=await this.searchManager.timeline(e.query);r.json(t.content)}catch(t){U.failure("WORKER","Unified timeline failed",{},t),r.status(500).json({error:t.message})}}async handleDecisions(e,r){try{let t=await this.searchManager.decisions(e.query);r.json(t.content)}catch(t){U.failure("WORKER","Decisions search failed",{},t),r.status(500).json({error:t.message})}}async handleChanges(e,r){try{let t=await this.searchManager.changes(e.query);r.json(t.content)}catch(t){U.failure("WORKER","Changes search failed",{},t),r.status(500).json({error:t.message})}}async handleHowItWorks(e,r){try{let t=await this.searchManager.howItWorks(e.query);r.json(t.content)}catch(t){U.failure("WORKER","How it works search failed",{},t),r.status(500).json({error:t.message})}}async handleSearchObservations(e,r){try{let t=await this.searchManager.searchObservations(e.query);r.json(t.content)}catch(t){U.failure("WORKER","Search failed",{},t),r.status(500).json({error:t.message})}}async handleSearchSessions(e,r){try{let t=await this.searchManager.searchSessions(e.query);r.json(t.content)}catch(t){U.failure("WORKER","Search failed",{},t),r.status(500).json({error:t.message})}}async handleSearchPrompts(e,r){try{let t=await this.searchManager.searchUserPrompts(e.query);r.json(t.content)}catch(t){U.failure("WORKER","Search failed",{},t),r.status(500).json({error:t.message})}}async handleSearchByConcept(e,r){try{let t=await this.searchManager.findByConcept(e.query);r.json(t.content)}catch(t){U.failure("WORKER","Search failed",{},t),r.status(500).json({error:t.message})}}async handleSearchByFile(e,r){try{let t=await this.searchManager.findByFile(e.query);r.json(t.content)}catch(t){U.failure("WORKER","Search failed",{},t),r.status(500).json({error:t.message})}}async handleSearchByType(e,r){try{let t=await this.searchManager.findByType(e.query);r.json(t.content)}catch(t){U.failure("WORKER","Search failed",{},t),r.status(500).json({error:t.message})}}async handleGetRecentContext(e,r){try{let t=await this.searchManager.getRecentContext(e.query);r.json(t.content)}catch(t){U.failure("WORKER","Search failed",{},t),r.status(500).json({error:t.message})}}async handleGetContextTimeline(e,r){try{let t=await this.searchManager.getContextTimeline(e.query);r.json(t.content)}catch(t){U.failure("WORKER","Search failed",{},t),r.status(500).json({error:t.message})}}async handleContextPreview(e,r){try{let t=e.query.project;if(!t){r.status(400).json({error:"Project parameter is required"});return}let{generateContext:s}=await Promise.resolve().then(()=>(bf(),yf)),i=`/preview/${t}`,n=await s({session_id:"preview-"+Date.now(),cwd:i},!0);r.setHeader("Content-Type","text/plain; charset=utf-8"),r.send(n)}catch(t){U.failure("WORKER","Context preview generation failed",{},t),r.status(500).json({error:"Failed to generate context preview",message:t.message})}}async handleContextInject(e,r){try{let t=e.query.project,s=e.query.colors==="true";if(!t){r.status(400).json({error:"Project parameter is required"});return}let{generateContext:i}=await Promise.resolve().then(()=>(bf(),yf)),n=`/context/${t}`,o=await i({session_id:"context-inject-"+Date.now(),cwd:n},s);r.setHeader("Content-Type","text/plain; charset=utf-8"),r.send(o)}catch(t){U.failure("WORKER","Context injection failed",{},t),r.status(500).json({error:"Failed to generate context",message:t.message})}}async handleGetTimelineByQuery(e,r){try{let t=await this.searchManager.getTimelineByQuery(e.query);r.json(t.content)}catch(t){U.failure("WORKER","Search failed",{},t),r.status(500).json({error:t.message})}}handleSearchHelp(e,r){r.json({title:"Claude-Mem Search API",description:"HTTP API for searching persistent memory",endpoints:[{path:"/api/search/observations",method:"GET",description:"Search observations using full-text search",parameters:{query:"Search query (required)",format:'Response format: "index" or "full" (default: "full")',limit:"Number of results (default: 20)",project:"Filter by project name (optional)"}},{path:"/api/search/sessions",method:"GET",description:"Search session summaries using full-text search",parameters:{query:"Search query (required)",format:'Response format: "index" or "full" (default: "full")',limit:"Number of results (default: 20)"}},{path:"/api/search/prompts",method:"GET",description:"Search user prompts using full-text search",parameters:{query:"Search query (required)",format:'Response format: "index" or "full" (default: "full")',limit:"Number of results (default: 20)",project:"Filter by project name (optional)"}},{path:"/api/search/by-concept",method:"GET",description:"Find observations by concept tag",parameters:{concept:"Concept tag (required): discovery, decision, bugfix, feature, refactor",format:'Response format: "index" or "full" (default: "full")',limit:"Number of results (default: 10)",project:"Filter by project name (optional)"}},{path:"/api/search/by-file",method:"GET",description:"Find observations and sessions by file path",parameters:{filePath:"File path or partial path (required)",format:'Response format: "index" or "full" (default: "full")',limit:"Number of results per type (default: 10)",project:"Filter by project name (optional)"}},{path:"/api/search/by-type",method:"GET",description:"Find observations by type",parameters:{type:"Observation type (required): discovery, decision, bugfix, feature, refactor",format:'Response format: "index" or "full" (default: "full")',limit:"Number of results (default: 10)",project:"Filter by project name (optional)"}},{path:"/api/context/recent",method:"GET",description:"Get recent session context including summaries and observations",parameters:{project:"Project name (default: current directory)",limit:"Number of recent sessions (default: 3)"}},{path:"/api/context/timeline",method:"GET",description:"Get unified timeline around a specific point in time",parameters:{anchor:'Anchor point: observation ID, session ID (e.g., "S123"), or ISO timestamp (required)',depth_before:"Number of records before anchor (default: 10)",depth_after:"Number of records after anchor (default: 10)",project:"Filter by project name (optional)"}},{path:"/api/timeline/by-query",method:"GET",description:"Search for best match, then get timeline around it",parameters:{query:"Search query (required)",mode:'Search mode: "auto", "observations", or "sessions" (default: "auto")',depth_before:"Number of records before match (default: 10)",depth_after:"Number of records after match (default: 10)",project:"Filter by project name (optional)"}},{path:"/api/search/help",method:"GET",description:"Get this help documentation"}],examples:['curl "http://localhost:37777/api/search/observations?query=authentication&format=index&limit=5"','curl "http://localhost:37777/api/search/by-type?type=bugfix&limit=10"','curl "http://localhost:37777/api/context/recent?project=claude-mem&limit=3"','curl "http://localhost:37777/api/context/timeline?anchor=123&depth_before=5&depth_after=5"']})}};var Hn=vt(require("path"),1),Vt=require("fs"),_f=require("os");Ia();_t();var xf=require("child_process"),qs=require("fs"),jw=require("os"),Xi=require("path");_t();var Qi=(0,Xi.join)((0,jw.homedir)(),".claude","plugins","marketplaces","thedotmack");function yr(a){return(0,xf.execSync)(`git ${a}`,{cwd:Qi,encoding:"utf-8",timeout:3e4}).trim()}function $w(a,e=6e4){return(0,xf.execSync)(a,{cwd:Qi,encoding:"utf-8",timeout:e}).trim()}function Cl(){let a=(0,Xi.join)(Qi,".git");if(!(0,qs.existsSync)(a))return{branch:null,isBeta:!1,isGitRepo:!1,isDirty:!1,canSwitch:!1,error:"Installed plugin is not a git repository"};try{let e=yr("rev-parse --abbrev-ref HEAD"),t=yr("status --porcelain").length>0,s=e.startsWith("beta");return{branch:e,isBeta:s,isGitRepo:!0,isDirty:t,canSwitch:!0}}catch(e){return U.error("BRANCH","Failed to get branch info",{},e),{branch:null,isBeta:!1,isGitRepo:!0,isDirty:!1,canSwitch:!1,error:e.message}}}async function Mw(a){let e=Cl();if(!e.isGitRepo)return{success:!1,error:"Installed plugin is not a git repository. Please reinstall."};if(e.branch===a)return{success:!0,branch:a,message:`Already on branch ${a}`};try{U.info("BRANCH","Starting branch switch",{from:e.branch,to:a}),U.debug("BRANCH","Discarding local changes"),yr("checkout -- ."),yr("clean -fd"),U.debug("BRANCH","Fetching from origin"),yr("fetch origin"),U.debug("BRANCH","Checking out branch",{branch:a});try{yr(`checkout ${a}`)}catch{yr(`checkout -b ${a} origin/${a}`)}U.debug("BRANCH","Pulling latest"),yr(`pull origin ${a}`);let r=(0,Xi.join)(Qi,".install-version");return(0,qs.existsSync)(r)&&(0,qs.unlinkSync)(r),U.debug("BRANCH","Running npm install"),$w("npm install",12e4),U.success("BRANCH","Branch switch complete",{branch:a}),{success:!0,branch:a,message:`Switched to ${a}. Worker will restart automatically.`}}catch(r){U.error("BRANCH","Branch switch failed",{targetBranch:a},r);try{e.branch&&yr(`checkout ${e.branch}`)}catch{}return{success:!1,error:`Branch switch failed: ${r.message}`}}}async function Lw(){let a=Cl();if(!a.isGitRepo||!a.branch)return{success:!1,error:"Cannot pull updates: not a git repository"};try{U.info("BRANCH","Pulling updates",{branch:a.branch}),yr("checkout -- ."),yr("fetch origin"),yr(`pull origin ${a.branch}`);let e=(0,Xi.join)(Qi,".install-version");return(0,qs.existsSync)(e)&&(0,qs.unlinkSync)(e),$w("npm install",12e4),U.success("BRANCH","Updates pulled",{branch:a.branch}),{success:!0,branch:a.branch,message:`Updated ${a.branch}. Worker will restart automatically.`}}catch(e){return U.error("BRANCH","Pull failed",{},e),{success:!1,error:`Pull failed: ${e.message}`}}}gf();var kl=class{constructor(e){this.settingsManager=e}setupRoutes(e){e.get("/api/settings",this.handleGetSettings.bind(this)),e.post("/api/settings",this.handleUpdateSettings.bind(this)),e.get("/api/mcp/status",this.handleGetMcpStatus.bind(this)),e.post("/api/mcp/toggle",this.handleToggleMcp.bind(this)),e.get("/api/branch/status",this.handleGetBranchStatus.bind(this)),e.post("/api/branch/switch",this.handleSwitchBranch.bind(this)),e.post("/api/branch/update",this.handleUpdateBranch.bind(this))}handleGetSettings(e,r){try{let t=Hn.default.join((0,_f.homedir)(),".claude-mem","settings.json");if(!(0,Vt.existsSync)(t)){r.json({CLAUDE_MEM_MODEL:"claude-haiku-4-5",CLAUDE_MEM_CONTEXT_OBSERVATIONS:"50",CLAUDE_MEM_WORKER_PORT:"37777",CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS:"true",CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS:"true",CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT:"true",CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT:"true",CLAUDE_MEM_CONTEXT_OBSERVATION_TYPES:Zi,CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS:Ki,CLAUDE_MEM_CONTEXT_FULL_COUNT:"5",CLAUDE_MEM_CONTEXT_FULL_FIELD:"narrative",CLAUDE_MEM_CONTEXT_SESSION_COUNT:"10",CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY:"true",CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE:"false"});return}let s=(0,Vt.readFileSync)(t,"utf-8"),n=JSON.parse(s).env||{};r.json({CLAUDE_MEM_MODEL:n.CLAUDE_MEM_MODEL||"claude-haiku-4-5",CLAUDE_MEM_CONTEXT_OBSERVATIONS:n.CLAUDE_MEM_CONTEXT_OBSERVATIONS||"50",CLAUDE_MEM_WORKER_PORT:n.CLAUDE_MEM_WORKER_PORT||"37777",CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS:n.CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS||"true",CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS:n.CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS||"true",CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT:n.CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT||"true",CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT:n.CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT||"true",CLAUDE_MEM_CONTEXT_OBSERVATION_TYPES:n.CLAUDE_MEM_CONTEXT_OBSERVATION_TYPES||Zi,CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS:n.CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS||Ki,CLAUDE_MEM_CONTEXT_FULL_COUNT:n.CLAUDE_MEM_CONTEXT_FULL_COUNT||"5",CLAUDE_MEM_CONTEXT_FULL_FIELD:n.CLAUDE_MEM_CONTEXT_FULL_FIELD||"narrative",CLAUDE_MEM_CONTEXT_SESSION_COUNT:n.CLAUDE_MEM_CONTEXT_SESSION_COUNT||"10",CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY:n.CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY||"true",CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE:n.CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE||"false"})}catch(t){U.failure("WORKER","Get settings failed",{},t),r.status(500).json({error:t.message})}}handleUpdateSettings(e,r){try{if(e.body.CLAUDE_MEM_CONTEXT_OBSERVATIONS){let o=parseInt(e.body.CLAUDE_MEM_CONTEXT_OBSERVATIONS,10);if(isNaN(o)||o<1||o>200){r.status(400).json({success:!1,error:"CLAUDE_MEM_CONTEXT_OBSERVATIONS must be between 1 and 200"});return}}if(e.body.CLAUDE_MEM_WORKER_PORT){let o=parseInt(e.body.CLAUDE_MEM_WORKER_PORT,10);if(isNaN(o)||o<1024||o>65535){r.status(400).json({success:!1,error:"CLAUDE_MEM_WORKER_PORT must be between 1024 and 65535"});return}}let t=this.validateContextSettings(e.body);if(!t.valid){r.status(400).json({success:!1,error:t.error});return}let s=Hn.default.join((0,_f.homedir)(),".claude-mem","settings.json"),i={env:{}};if((0,Vt.existsSync)(s)){let o=(0,Vt.readFileSync)(s,"utf-8");i=JSON.parse(o),i.env||(i.env={})}let n=["CLAUDE_MEM_MODEL","CLAUDE_MEM_CONTEXT_OBSERVATIONS","CLAUDE_MEM_WORKER_PORT","CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS","CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS","CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT","CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT","CLAUDE_MEM_CONTEXT_OBSERVATION_TYPES","CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS","CLAUDE_MEM_CONTEXT_FULL_COUNT","CLAUDE_MEM_CONTEXT_FULL_FIELD","CLAUDE_MEM_CONTEXT_SESSION_COUNT","CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY","CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE"];for(let o of n)e.body[o]!==void 0&&(i.env[o]=e.body[o]);(0,Vt.writeFileSync)(s,JSON.stringify(i,null,2),"utf-8"),U.info("WORKER","Settings updated"),r.json({success:!0,message:"Settings updated successfully"})}catch(t){U.failure("WORKER","Update settings failed",{},t),r.status(500).json({success:!1,error:String(t)})}}handleGetMcpStatus(e,r){try{let t=this.isMcpEnabled();r.json({enabled:t})}catch(t){U.failure("WORKER","Get MCP status failed",{},t),r.status(500).json({error:t.message})}}handleToggleMcp(e,r){try{let{enabled:t}=e.body;if(typeof t!="boolean"){r.status(400).json({error:"enabled must be a boolean"});return}this.toggleMcp(t),r.json({success:!0,enabled:this.isMcpEnabled()})}catch(t){U.failure("WORKER","Toggle MCP failed",{},t),r.status(500).json({success:!1,error:t.message})}}handleGetBranchStatus(e,r){try{let t=Cl();r.json(t)}catch(t){U.failure("WORKER","Failed to get branch status",{},t),r.status(500).json({error:t.message})}}async handleSwitchBranch(e,r){try{let{branch:t}=e.body;if(!t){r.status(400).json({success:!1,error:"Missing branch parameter"});return}let s=["main","beta/7.0"];if(!s.includes(t)){r.status(400).json({success:!1,error:`Invalid branch. Allowed: ${s.join(", ")}`});return}U.info("WORKER","Branch switch requested",{branch:t});let i=await Mw(t);i.success&&setTimeout(()=>{U.info("WORKER","Restarting worker after branch switch"),process.exit(0)},1e3),r.json(i)}catch(t){U.failure("WORKER","Branch switch failed",{},t),r.status(500).json({success:!1,error:t.message})}}async handleUpdateBranch(e,r){try{U.info("WORKER","Branch update requested");let t=await Lw();t.success&&setTimeout(()=>{U.info("WORKER","Restarting worker after branch update"),process.exit(0)},1e3),r.json(t)}catch(t){U.failure("WORKER","Branch update failed",{},t),r.status(500).json({success:!1,error:t.message})}}validateContextSettings(e){let r=["CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS","CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS","CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT","CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT","CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY","CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE"];for(let t of r)if(e[t]&&!["true","false"].includes(e[t]))return{valid:!1,error:`${t} must be "true" or "false"`};if(e.CLAUDE_MEM_CONTEXT_FULL_COUNT){let t=parseInt(e.CLAUDE_MEM_CONTEXT_FULL_COUNT,10);if(isNaN(t)||t<0||t>20)return{valid:!1,error:"CLAUDE_MEM_CONTEXT_FULL_COUNT must be between 0 and 20"}}if(e.CLAUDE_MEM_CONTEXT_SESSION_COUNT){let t=parseInt(e.CLAUDE_MEM_CONTEXT_SESSION_COUNT,10);if(isNaN(t)||t<1||t>50)return{valid:!1,error:"CLAUDE_MEM_CONTEXT_SESSION_COUNT must be between 1 and 50"}}if(e.CLAUDE_MEM_CONTEXT_FULL_FIELD&&!["narrative","facts"].includes(e.CLAUDE_MEM_CONTEXT_FULL_FIELD))return{valid:!1,error:'CLAUDE_MEM_CONTEXT_FULL_FIELD must be "narrative" or "facts"'};if(e.CLAUDE_MEM_CONTEXT_OBSERVATION_TYPES){let t=e.CLAUDE_MEM_CONTEXT_OBSERVATION_TYPES.split(",").map(s=>s.trim());for(let s of t)if(s&&!zn.includes(s))return{valid:!1,error:`Invalid observation type: ${s}. Valid types: ${zn.join(", ")}`}}if(e.CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS){let t=e.CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS.split(",").map(s=>s.trim());for(let s of t)if(s&&!Bn.includes(s))return{valid:!1,error:`Invalid observation concept: ${s}. Valid concepts: ${Bn.join(", ")}`}}return{valid:!0}}isMcpEnabled(){let e=zr(),r=Hn.default.join(e,"plugin",".mcp.json");return(0,Vt.existsSync)(r)}toggleMcp(e){try{let r=zr(),t=Hn.default.join(r,"plugin",".mcp.json"),s=Hn.default.join(r,"plugin",".mcp.json.disabled");e&&(0,Vt.existsSync)(s)?((0,Vt.renameSync)(s,t),U.info("WORKER","MCP search server enabled")):!e&&(0,Vt.existsSync)(t)?((0,Vt.renameSync)(t,s),U.info("WORKER","MCP search server disabled")):U.debug("WORKER","MCP toggle no-op (already in desired state)",{enabled:e})}catch(r){throw U.failure("WORKER","Failed to toggle MCP",{enabled:e},r),r}}};var Il=class{app;server=null;startTime=Date.now();mcpClient;dbManager;sessionManager;sseBroadcaster;sdkAgent;paginationHelper;settingsManager;viewerRoutes;sessionRoutes;dataRoutes;searchRoutes;settingsRoutes;constructor(){this.app=(0,qw.default)(),this.dbManager=new Jc,this.sessionManager=new Yc(this.dbManager),this.sseBroadcaster=new el,this.sdkAgent=new vl(this.dbManager,this.sessionManager),this.paginationHelper=new yl(this.dbManager),this.settingsManager=new bl(this.dbManager),this.sessionManager.setOnSessionDeleted(()=>{this.broadcastProcessingStatus()}),this.mcpClient=new wn({name:"worker-search-proxy",version:"1.0.0"},{capabilities:{}}),this.viewerRoutes=new Sl(this.sseBroadcaster,this.dbManager,this.sessionManager),this.sessionRoutes=new wl(this.sessionManager,this.dbManager,this.sdkAgent,this.sseBroadcaster,this),this.dataRoutes=new Tl(this.paginationHelper,this.dbManager,this.sessionManager,this.sseBroadcaster,this,this.startTime),this.searchRoutes=null,this.settingsRoutes=new kl(this.settingsManager),this.setupMiddleware(),this.setupRoutes()}setupMiddleware(){Tw(this.summarizeRequestBody.bind(this)).forEach(r=>this.app.use(r))}setupRoutes(){this.app.get("/api/health",(e,r)=>{r.status(200).json({status:"ok"})}),this.viewerRoutes.setupRoutes(this.app),this.sessionRoutes.setupRoutes(this.app),this.dataRoutes.setupRoutes(this.app),this.settingsRoutes.setupRoutes(this.app)}async cleanupOrphanedProcesses(){try{let{execSync:e}=await import("child_process");try{let r=e("pgrep -fl uvx",{encoding:"utf-8",stdio:"pipe",windowsHide:!0}).trim();if(r){let t=r.split(` `).length;U.info("WORKER","Cleaning up orphaned MCP processes",{count:t}),e("pkill -f uvx",{stdio:"pipe",windowsHide:!0}),U.success("WORKER",`Cleaned up ${t} orphaned MCP server processes`)}}catch(r){if(r.status===1)U.debug("WORKER","No orphaned MCP processes to clean up");else throw r}}catch(e){U.warn("WORKER","Failed to cleanup orphaned processes (non-fatal)",{},e)}}async start(){let e=On();this.server=await new Promise((r,t)=>{let s=this.app.listen(e,()=>r(s));s.on("error",t)}),U.info("SYSTEM","Worker started",{port:e,pid:process.pid}),this.initializeBackground().catch(r=>{U.error("SYSTEM","Background initialization failed",{},r)})}async initializeBackground(){await this.cleanupOrphanedProcesses(),await this.dbManager.initialize();let e=new _l,r=new El,t=new xl(this.dbManager.getSessionSearch(),this.dbManager.getSessionStore(),this.dbManager.getChromaSync(),e,r);this.searchRoutes=new Ol(t),this.searchRoutes.setupRoutes(this.app),U.info("WORKER","SearchManager initialized and search routes registered");let s=Fw.default.join(__dirname,"..","..","plugin","scripts","mcp-server.cjs"),i=new Pn({command:"node",args:[s],env:process.env});await this.mcpClient.connect(i),U.success("WORKER","Connected to MCP server")}async shutdown(){if(await this.sessionManager.shutdownAll(),this.mcpClient)try{await this.mcpClient.close(),U.info("SYSTEM","MCP client closed")}catch(e){U.error("SYSTEM","Failed to close MCP client",{},e)}this.server&&await new Promise((e,r)=>{this.server.close(t=>t?r(t):e())}),await this.dbManager.close(),U.info("SYSTEM","Worker shutdown complete")}summarizeRequestBody(e,r,t){return Rw(e,r,t)}broadcastProcessingStatus(){let e=this.sessionManager.isAnySessionProcessing(),r=this.sessionManager.getTotalActiveWork(),t=this.sessionManager.getActiveSessionCount();U.info("WORKER","Broadcasting processing status",{isProcessing:e,queueDepth:r,activeSessions:t}),this.sseBroadcaster.broadcast({type:"processing_status",isProcessing:e,queueDepth:r})}};if(require.main===module||!module.parent){let a=new Il;process.on("SIGTERM",async()=>{U.info("SYSTEM","Received SIGTERM, shutting down gracefully"),await a.shutdown(),process.exit(0)}),process.on("SIGINT",async()=>{U.info("SYSTEM","Received SIGINT, shutting down gracefully"),await a.shutdown(),process.exit(0)}),a.start().catch(e=>{U.failure("SYSTEM","Worker failed to start",{},e),process.exit(1)})}0&&(module.exports={WorkerService}); /*! Bundled license information: diff --git a/src/services/worker-service.ts b/src/services/worker-service.ts index 25b61858..3ddf5b5c 100644 --- a/src/services/worker-service.ts +++ b/src/services/worker-service.ts @@ -51,7 +51,7 @@ export class WorkerService { private viewerRoutes: ViewerRoutes; private sessionRoutes: SessionRoutes; private dataRoutes: DataRoutes; - private searchRoutes: SearchRoutes; + private searchRoutes: SearchRoutes | null; private settingsRoutes: SettingsRoutes; constructor() { @@ -81,7 +81,7 @@ export class WorkerService { this.sessionRoutes = new SessionRoutes(this.sessionManager, this.dbManager, this.sdkAgent, this.sseBroadcaster, this); this.dataRoutes = new DataRoutes(this.paginationHelper, this.dbManager, this.sessionManager, this.sseBroadcaster, this, this.startTime); // SearchRoutes needs SearchManager which requires initialized DB - will be created in initializeBackground() - this.searchRoutes = null as any; // Temporary - will be set in initializeBackground() + this.searchRoutes = null; this.settingsRoutes = new SettingsRoutes(this.settingsManager); this.setupMiddleware(); @@ -109,9 +109,6 @@ export class WorkerService { this.sessionRoutes.setupRoutes(this.app); this.dataRoutes.setupRoutes(this.app); // searchRoutes is set up after database initialization in initializeBackground() - if (this.searchRoutes) { - this.searchRoutes.setupRoutes(this.app); - } this.settingsRoutes.setupRoutes(this.app); }