Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7fdfdd5d5e | |||
| e872c2da38 | |||
| 0b476e971a | |||
| f7b51a963e |
@@ -10,7 +10,7 @@
|
||||
"plugins": [
|
||||
{
|
||||
"name": "claude-mem",
|
||||
"version": "5.1.2",
|
||||
"version": "5.1.4",
|
||||
"source": "./plugin",
|
||||
"description": "Persistent memory system for Claude Code - context compression across sessions"
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ Claude-mem is a Claude Code plugin providing persistent memory across sessions.
|
||||
|
||||
**Your Role**: You are working on the plugin itself. When users interact with Claude Code with this plugin installed, your observations get captured and become their persistent memory.
|
||||
|
||||
**Current Version**: 5.1.2
|
||||
**Current Version**: 5.1.4
|
||||
|
||||
## Critical Architecture Knowledge
|
||||
|
||||
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "claude-mem",
|
||||
"version": "5.1.0",
|
||||
"version": "5.1.3",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "claude-mem",
|
||||
"version": "5.1.0",
|
||||
"version": "5.1.3",
|
||||
"license": "AGPL-3.0",
|
||||
"dependencies": {
|
||||
"@anthropic-ai/claude-agent-sdk": "^0.1.27",
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "claude-mem",
|
||||
"version": "5.1.2",
|
||||
"version": "5.1.4",
|
||||
"description": "Memory compression system for Claude Code - persist context across sessions",
|
||||
"keywords": [
|
||||
"claude",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "claude-mem",
|
||||
"version": "5.1.2",
|
||||
"version": "5.1.4",
|
||||
"description": "Persistent memory system for Claude Code - seamlessly preserve context across sessions",
|
||||
"author": {
|
||||
"name": "Alex Newman"
|
||||
|
||||
@@ -400,4 +400,4 @@ ${e.stack}`:e.message;if(Array.isArray(e))return`[${e.length} items]`;let s=Obje
|
||||
JOIN sdk_sessions s ON up.claude_session_id = s.claude_session_id
|
||||
WHERE up.created_at_epoch >= ? AND up.created_at_epoch <= ? ${o.replace("project","s.project")}
|
||||
ORDER BY up.created_at_epoch ASC
|
||||
`;try{let T=this.db.prepare(c).all(a,_,...i),g=this.db.prepare(m).all(a,_,...i),u=this.db.prepare(S).all(a,_,...i);return{observations:T,sessions:g.map(d=>({id:d.id,sdk_session_id:d.sdk_session_id,project:d.project,request:d.request,completed:d.completed,next_steps:d.next_steps,created_at:d.created_at,created_at_epoch:d.created_at_epoch})),prompts:u.map(d=>({id:d.id,claude_session_id:d.claude_session_id,project:d.project,prompt:d.prompt_text,created_at:d.created_at,created_at_epoch:d.created_at_epoch}))}}catch(T){return console.error("[SessionStore] Error querying timeline records:",T.message),{observations:[],sessions:[],prompts:[]}}}close(){this.db.close()}};function $(p,e,s){return p==="PreCompact"?e?{continue:!0,suppressOutput:!0}:{continue:!1,stopReason:s.reason||"Pre-compact operation failed",suppressOutput:!0}:p==="SessionStart"?e&&s.context?{continue:!0,suppressOutput:!0,hookSpecificOutput:{hookEventName:"SessionStart",additionalContext:s.context}}:{continue:!0,suppressOutput:!0}:p==="UserPromptSubmit"||p==="PostToolUse"?{continue:!0,suppressOutput:!0}:p==="Stop"?{continue:!0,suppressOutput:!0}:{continue:e,suppressOutput:!0,...s.reason&&!e?{stopReason:s.reason}:{}}}function f(p,e,s={}){let t=$(p,e,s);return JSON.stringify(t)}import y from"path";import{spawn as D}from"child_process";var W=parseInt(process.env.CLAUDE_MEM_WORKER_PORT||"37777",10);async function k(p=100){try{return(await fetch(`http://127.0.0.1:${W}/health`,{signal:AbortSignal.timeout(p)})).ok}catch{return!1}}async function G(p=1e4){let e=Date.now(),s=100;for(;Date.now()-e<p;){if(await k(1e3))return!0;await new Promise(t=>setTimeout(t,s))}return!1}async function x(){if(await k())return;let p=v(),e=y.join(p,"node_modules",".bin","pm2"),s=y.join(p,"ecosystem.config.cjs"),t=D(e,["list","--no-color"],{cwd:p,stdio:["ignore","pipe","ignore"]}),r="";if(t.stdout?.on("data",i=>{r+=i.toString()}),await new Promise((i,a)=>{t.on("error",_=>a(_)),t.on("close",_=>{i()})}),!(r.includes("claude-mem-worker")&&r.includes("online"))){let i=D(e,["start",s],{cwd:p,stdio:"ignore"});await new Promise((a,_)=>{i.on("error",c=>_(c)),i.on("close",c=>{c!==0&&c!==null?_(new Error(`PM2 start command failed with exit code ${c}`)):a()})})}if(!await G(1e4))throw new Error("Worker failed to become healthy after starting")}var Y=new Set(["ListMcpResourcesTool"]);async function K(p){if(!p)throw new Error("saveHook requires input");let{session_id:e,tool_name:s,tool_input:t,tool_output:r}=p;if(Y.has(s)){console.log(f("PostToolUse",!0));return}await x();let n=new R,o=n.createSDKSession(e,"",""),i=n.getPromptCounter(o);n.close();let a=b.formatTool(s,t),_=parseInt(process.env.CLAUDE_MEM_WORKER_PORT||"37777",10);b.dataIn("HOOK",`PostToolUse: ${a}`,{sessionId:o,workerPort:_});try{let c=await fetch(`http://127.0.0.1:${_}/sessions/${o}/observations`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({tool_name:s,tool_input:t!==void 0?JSON.stringify(t):"{}",tool_output:r!==void 0?JSON.stringify(r):"{}",prompt_number:i}),signal:AbortSignal.timeout(2e3)});if(!c.ok){let m=await c.text();throw b.failure("HOOK","Failed to send observation",{sessionId:o,status:c.status},m),new Error(`Failed to send observation to worker: ${c.status} ${m}`)}b.debug("HOOK","Observation sent successfully",{sessionId:o,toolName:s})}catch(c){throw c.cause?.code==="ECONNREFUSED"||c.name==="TimeoutError"||c.message.includes("fetch failed")?new Error("There's a problem with the worker. If you just updated, type `pm2 restart claude-mem-worker` in your terminal to continue"):c}console.log(f("PostToolUse",!0))}var I="";U.on("data",p=>I+=p);U.on("end",async()=>{let p=I?JSON.parse(I):void 0;await K(p)});
|
||||
`;try{let T=this.db.prepare(c).all(a,_,...i),g=this.db.prepare(m).all(a,_,...i),u=this.db.prepare(S).all(a,_,...i);return{observations:T,sessions:g.map(d=>({id:d.id,sdk_session_id:d.sdk_session_id,project:d.project,request:d.request,completed:d.completed,next_steps:d.next_steps,created_at:d.created_at,created_at_epoch:d.created_at_epoch})),prompts:u.map(d=>({id:d.id,claude_session_id:d.claude_session_id,project:d.project,prompt:d.prompt_text,created_at:d.created_at,created_at_epoch:d.created_at_epoch}))}}catch(T){return console.error("[SessionStore] Error querying timeline records:",T.message),{observations:[],sessions:[],prompts:[]}}}close(){this.db.close()}};function $(p,e,s){return p==="PreCompact"?e?{continue:!0,suppressOutput:!0}:{continue:!1,stopReason:s.reason||"Pre-compact operation failed",suppressOutput:!0}:p==="SessionStart"?e&&s.context?{continue:!0,suppressOutput:!0,hookSpecificOutput:{hookEventName:"SessionStart",additionalContext:s.context}}:{continue:!0,suppressOutput:!0}:p==="UserPromptSubmit"||p==="PostToolUse"?{continue:!0,suppressOutput:!0}:p==="Stop"?{continue:!0,suppressOutput:!0}:{continue:e,suppressOutput:!0,...s.reason&&!e?{stopReason:s.reason}:{}}}function f(p,e,s={}){let t=$(p,e,s);return JSON.stringify(t)}import y from"path";import{spawn as D}from"child_process";var W=parseInt(process.env.CLAUDE_MEM_WORKER_PORT||"37777",10);async function k(p=100){try{return(await fetch(`http://127.0.0.1:${W}/health`,{signal:AbortSignal.timeout(p)})).ok}catch{return!1}}async function G(p=1e4){let e=Date.now(),s=100;for(;Date.now()-e<p;){if(await k(1e3))return!0;await new Promise(t=>setTimeout(t,s))}return!1}async function x(){if(await k())return;let p=v(),e=y.join(p,"node_modules",".bin","pm2"),s=y.join(p,"ecosystem.config.cjs"),t=D(e,["list","--no-color"],{cwd:p,stdio:["ignore","pipe","ignore"]}),r="";if(t.stdout?.on("data",i=>{r+=i.toString()}),await new Promise((i,a)=>{t.on("error",_=>a(_)),t.on("close",_=>{i()})}),!(r.includes("claude-mem-worker")&&r.includes("online"))){let i=D(e,["start",s],{cwd:p,stdio:"ignore"});await new Promise((a,_)=>{i.on("error",c=>_(c)),i.on("close",c=>{c!==0&&c!==null?_(new Error(`PM2 start command failed with exit code ${c}`)):a()})})}if(!await G(1e4))throw new Error("Worker failed to become healthy after starting")}var Y=new Set(["ListMcpResourcesTool"]);async function K(p){if(!p)throw new Error("saveHook requires input");let{session_id:e,tool_name:s,tool_input:t,tool_response:r}=p;if(Y.has(s)){console.log(f("PostToolUse",!0));return}await x();let n=new R,o=n.createSDKSession(e,"",""),i=n.getPromptCounter(o);n.close();let a=b.formatTool(s,t),_=parseInt(process.env.CLAUDE_MEM_WORKER_PORT||"37777",10);b.dataIn("HOOK",`PostToolUse: ${a}`,{sessionId:o,workerPort:_});try{let c=await fetch(`http://127.0.0.1:${_}/sessions/${o}/observations`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({tool_name:s,tool_input:t!==void 0?JSON.stringify(t):"{}",tool_response:r!==void 0?JSON.stringify(r):"{}",prompt_number:i}),signal:AbortSignal.timeout(2e3)});if(!c.ok){let m=await c.text();throw b.failure("HOOK","Failed to send observation",{sessionId:o,status:c.status},m),new Error(`Failed to send observation to worker: ${c.status} ${m}`)}b.debug("HOOK","Observation sent successfully",{sessionId:o,toolName:s})}catch(c){throw c.cause?.code==="ECONNREFUSED"||c.name==="TimeoutError"||c.message.includes("fetch failed")?new Error("There's a problem with the worker. If you just updated, type `pm2 restart claude-mem-worker` in your terminal to continue"):c}console.log(f("PostToolUse",!0))}var I="";U.on("data",p=>I+=p);U.on("end",async()=>{let p=I?JSON.parse(I):void 0;await K(p)});
|
||||
|
||||
@@ -648,8 +648,8 @@ IMPORTANT: This is not the end of the session. You will receive more requests to
|
||||
WHERE up.claude_session_id = ?
|
||||
ORDER BY up.created_at_epoch DESC
|
||||
LIMIT 1
|
||||
`).get(l);n.close(),u&&this.broadcastSSE({type:"new_prompt",prompt:{id:u.id,claude_session_id:u.claude_session_id,project:u.project,prompt_number:u.prompt_number,prompt_text:u.prompt_text,created_at_epoch:u.created_at_epoch}}),u&&this.chromaSync.syncUserPrompt(u.id,u.sdk_session_id,u.project,u.prompt_text,u.prompt_number,u.created_at_epoch).catch(p=>{Y.failure("WORKER","Failed to sync user_prompt to Chroma - continuing",{promptId:u.id},p)}),c.generatorPromise=this.runSDKAgent(c).catch(p=>{Y.failure("WORKER","SDK agent error",{sessionId:r},p);let f=new pr;f.markSessionFailed(r),f.close(),this.sessions.delete(r)}),Y.success("WORKER","Session initialized",{sessionId:r,port:this.port}),a.json({status:"initialized",sessionDbId:r,port:this.port})}handleObservation(e,a){let r=parseInt(e.params.sessionDbId,10),{tool_name:s,tool_input:i,tool_output:n,prompt_number:o}=e.body,l=this.sessions.get(r);if(!l){let u=new pr,p=u.getSessionById(r);u.close(),l={sessionDbId:r,claudeSessionId:p.claude_session_id,sdkSessionId:null,project:p.project,userPrompt:p.user_prompt,pendingMessages:[],abortController:new AbortController,generatorPromise:null,lastPromptNumber:0,startTime:Date.now()},this.sessions.set(r,l),l.generatorPromise=this.runSDKAgent(l).catch(f=>{Y.failure("WORKER","SDK agent error",{sessionId:r},f);let d=new pr;d.markSessionFailed(r),d.close(),this.sessions.delete(r)})}let c=Y.formatTool(s,i);Y.dataIn("WORKER",`Observation queued: ${c}`,{sessionId:r,queue:l.pendingMessages.length+1}),l.pendingMessages.push({type:"observation",tool_name:s,tool_input:i,tool_output:n,prompt_number:o}),a.json({status:"queued",queueLength:l.pendingMessages.length})}handleSummarize(e,a){let r=parseInt(e.params.sessionDbId,10),{prompt_number:s}=e.body,i=this.sessions.get(r);if(!i){let n=new pr,o=n.getSessionById(r);n.close(),i={sessionDbId:r,claudeSessionId:o.claude_session_id,sdkSessionId:null,project:o.project,userPrompt:o.user_prompt,pendingMessages:[],abortController:new AbortController,generatorPromise:null,lastPromptNumber:0,startTime:Date.now()},this.sessions.set(r,i),i.generatorPromise=this.runSDKAgent(i).catch(l=>{Y.failure("WORKER","SDK agent error",{sessionId:r},l);let c=new pr;c.markSessionFailed(r),c.close(),this.sessions.delete(r)})}Y.dataIn("WORKER","Summary requested",{sessionId:r,promptNumber:s,queue:i.pendingMessages.length+1}),i.pendingMessages.push({type:"summarize",prompt_number:s}),this.broadcastProcessingStatus(i.claudeSessionId,!0),a.json({status:"queued",queueLength:i.pendingMessages.length})}handleStatus(e,a){let r=parseInt(e.params.sessionDbId,10),s=this.sessions.get(r);if(!s){a.status(404).json({error:"Session not found"});return}a.json({sessionDbId:r,sdkSessionId:s.sdkSessionId,project:s.project,pendingMessages:s.pendingMessages.length})}async handleDelete(e,a){let r=parseInt(e.params.sessionDbId,10),s=this.sessions.get(r);if(!s){a.status(404).json({error:"Session not found"});return}Y.warn("WORKER","Session delete requested",{sessionId:r}),s.abortController.abort(),s.generatorPromise&&await Promise.race([s.generatorPromise,new Promise(n=>setTimeout(n,5e3))]);let i=new pr;i.markSessionFailed(r),i.close(),this.sessions.delete(r),Y.info("WORKER","Session deleted",{sessionId:r}),a.json({status:"deleted"})}async runSDKAgent(e){Y.info("SDK","Agent starting",{sessionId:e.sessionDbId});let a=K5();Y.info("SDK",`Using Claude executable: ${a}`,{sessionId:e.sessionDbId});try{let r=$b({prompt:this.createMessageGenerator(e),options:{model:W5,disallowedTools:Q5,abortController:e.abortController,pathToClaudeCodeExecutable:a}});for await(let n of r){if(n.type==="assistant"){let o=n.message.content,l=Array.isArray(o)?o.filter(u=>u.type==="text").map(u=>u.text).join(`
|
||||
`):typeof o=="string"?o:"",c=l.length;Y.dataOut("SDK",`Response received (${c} chars)`,{sessionId:e.sessionDbId,promptNumber:e.lastPromptNumber}),Y.debug("SDK","Full response",{sessionId:e.sessionDbId},l),this.handleAgentMessage(e,l,e.lastPromptNumber)}n.type==="result"&&n.subtype}let s=Date.now()-e.startTime;Y.success("SDK","Agent completed",{sessionId:e.sessionDbId,duration:`${(s/1e3).toFixed(1)}s`});let i=new pr;i.markSessionCompleted(e.sessionDbId),i.close(),this.sessions.delete(e.sessionDbId)}catch(r){throw r.name==="AbortError"?Y.warn("SDK","Agent aborted",{sessionId:e.sessionDbId}):Y.failure("SDK","Agent error",{sessionId:e.sessionDbId},r),r}}async*createMessageGenerator(e){let a=dE(e.project,e.claudeSessionId,e.userPrompt);for(Y.dataIn("SDK",`Init prompt sent (${a.length} chars)`,{sessionId:e.sessionDbId,claudeSessionId:e.claudeSessionId,project:e.project}),Y.debug("SDK","Full init prompt",{sessionId:e.sessionDbId},a),yield{type:"user",session_id:e.claudeSessionId,parent_tool_use_id:null,message:{role:"user",content:a}};!e.abortController.signal.aborted;){if(e.pendingMessages.length===0){await new Promise(r=>setTimeout(r,100));continue}for(;e.pendingMessages.length>0;){let r=e.pendingMessages.shift();if(r.type==="summarize"){e.lastPromptNumber=r.prompt_number;let s=new pr,i=s.getSessionById(e.sessionDbId);s.close();let n=mE(i);Y.dataIn("SDK",`Summary prompt sent (${n.length} chars)`,{sessionId:e.sessionDbId,promptNumber:r.prompt_number}),Y.debug("SDK","Full summary prompt",{sessionId:e.sessionDbId},n),yield{type:"user",session_id:e.claudeSessionId,parent_tool_use_id:null,message:{role:"user",content:n}}}else if(r.type==="observation"){e.lastPromptNumber=r.prompt_number;let s=fE({id:0,tool_name:r.tool_name,tool_input:r.tool_input,tool_output:r.tool_output,created_at_epoch:Date.now()}),i=Y.formatTool(r.tool_name,r.tool_input);Y.dataIn("SDK",`Observation prompt: ${i}`,{sessionId:e.sessionDbId,promptNumber:r.prompt_number,size:`${s.length} chars`}),Y.debug("SDK","Full observation prompt",{sessionId:e.sessionDbId},s),yield{type:"user",session_id:e.claudeSessionId,parent_tool_use_id:null,message:{role:"user",content:s}}}}}}handleAgentMessage(e,a,r){Y.info("PARSER",`Processing response (${a.length} chars)`,{sessionId:e.sessionDbId,promptNumber:r,preview:a.substring(0,200)});let s=hE(a);s.length>0&&Y.info("PARSER",`Parsed ${s.length} observation(s)`,{sessionId:e.sessionDbId,promptNumber:r,types:s.map(o=>o.type).join(", ")});let i=new pr;for(let o of s){let{id:l,createdAtEpoch:c}=i.storeObservation(e.claudeSessionId,e.project,o,r);Y.success("DB","Observation stored",{sessionId:e.sessionDbId,type:o.type,title:o.title,id:l}),this.broadcastSSE({type:"new_observation",observation:{id:l,session_id:e.claudeSessionId,type:o.type,title:o.title,subtitle:o.subtitle,project:e.project,prompt_number:r,created_at_epoch:c}}),this.chromaSync.syncObservation(l,e.claudeSessionId,e.project,o,r,c).then(()=>{Y.success("WORKER","Observation synced to Chroma",{sessionId:e.sessionDbId,observationId:l})}).catch(u=>{Y.error("WORKER","Observation sync failed - continuing",{sessionId:e.sessionDbId,observationId:l},u)})}Y.info("PARSER","Looking for summary tags...",{sessionId:e.sessionDbId});let n=vE(a,e.sessionDbId);if(n){Y.success("PARSER","Summary parsed successfully!",{sessionId:e.sessionDbId,promptNumber:r,hasRequest:!!n.request,hasInvestigated:!!n.investigated,hasLearned:!!n.learned,hasCompleted:!!n.completed,hasNextSteps:!!n.next_steps});let{id:o,createdAtEpoch:l}=i.storeSummary(e.claudeSessionId,e.project,n,r);Y.success("DB","\u{1F4DD} SUMMARY STORED IN DATABASE",{sessionId:e.sessionDbId,promptNumber:r,id:o}),this.broadcastSSE({type:"new_summary",summary:{id:o,session_id:e.claudeSessionId,request:n.request,investigated:n.investigated,learned:n.learned,completed:n.completed,next_steps:n.next_steps,notes:n.notes,project:e.project,prompt_number:r,created_at_epoch:l}}),this.broadcastProcessingStatus(e.claudeSessionId,!1),this.chromaSync.syncSummary(o,e.claudeSessionId,e.project,n,r,l).then(()=>{Y.success("WORKER","Summary synced to Chroma",{sessionId:e.sessionDbId,summaryId:o})}).catch(c=>{Y.error("WORKER","Summary sync failed - continuing",{sessionId:e.sessionDbId,summaryId:o},c)})}else Y.warn("PARSER","NO SUMMARY TAGS FOUND in response",{sessionId:e.sessionDbId,promptNumber:r,contentSample:a.substring(0,500)}),this.broadcastProcessingStatus(e.claudeSessionId,!1);i.close()}};async function X5(){await new Gc().start(),process.on("SIGINT",()=>{Y.warn("SYSTEM","Shutting down (SIGINT)"),process.exit(0)}),process.on("SIGTERM",()=>{Y.warn("SYSTEM","Shutting down (SIGTERM)"),process.exit(0)})}X5().catch(t=>{Y.failure("SYSTEM","Fatal startup error",{},t),process.exit(1)});0&&(module.exports={WorkerService});
|
||||
`).get(l);n.close(),u&&this.broadcastSSE({type:"new_prompt",prompt:{id:u.id,claude_session_id:u.claude_session_id,project:u.project,prompt_number:u.prompt_number,prompt_text:u.prompt_text,created_at_epoch:u.created_at_epoch}}),u&&this.chromaSync.syncUserPrompt(u.id,u.sdk_session_id,u.project,u.prompt_text,u.prompt_number,u.created_at_epoch).catch(p=>{Y.failure("WORKER","Failed to sync user_prompt to Chroma - continuing",{promptId:u.id},p)}),c.generatorPromise=this.runSDKAgent(c).catch(p=>{Y.failure("WORKER","SDK agent error",{sessionId:r},p);let f=new pr;f.markSessionFailed(r),f.close(),this.sessions.delete(r)}),Y.success("WORKER","Session initialized",{sessionId:r,port:this.port}),a.json({status:"initialized",sessionDbId:r,port:this.port})}handleObservation(e,a){let r=parseInt(e.params.sessionDbId,10),{tool_name:s,tool_input:i,tool_response:n,prompt_number:o}=e.body,l=this.sessions.get(r);if(!l){let u=new pr,p=u.getSessionById(r);u.close(),l={sessionDbId:r,claudeSessionId:p.claude_session_id,sdkSessionId:null,project:p.project,userPrompt:p.user_prompt,pendingMessages:[],abortController:new AbortController,generatorPromise:null,lastPromptNumber:0,startTime:Date.now()},this.sessions.set(r,l),l.generatorPromise=this.runSDKAgent(l).catch(f=>{Y.failure("WORKER","SDK agent error",{sessionId:r},f);let d=new pr;d.markSessionFailed(r),d.close(),this.sessions.delete(r)})}let c=Y.formatTool(s,i);Y.dataIn("WORKER",`Observation queued: ${c}`,{sessionId:r,queue:l.pendingMessages.length+1}),l.pendingMessages.push({type:"observation",tool_name:s,tool_input:i,tool_response:n,prompt_number:o}),a.json({status:"queued",queueLength:l.pendingMessages.length})}handleSummarize(e,a){let r=parseInt(e.params.sessionDbId,10),{prompt_number:s}=e.body,i=this.sessions.get(r);if(!i){let n=new pr,o=n.getSessionById(r);n.close(),i={sessionDbId:r,claudeSessionId:o.claude_session_id,sdkSessionId:null,project:o.project,userPrompt:o.user_prompt,pendingMessages:[],abortController:new AbortController,generatorPromise:null,lastPromptNumber:0,startTime:Date.now()},this.sessions.set(r,i),i.generatorPromise=this.runSDKAgent(i).catch(l=>{Y.failure("WORKER","SDK agent error",{sessionId:r},l);let c=new pr;c.markSessionFailed(r),c.close(),this.sessions.delete(r)})}Y.dataIn("WORKER","Summary requested",{sessionId:r,promptNumber:s,queue:i.pendingMessages.length+1}),i.pendingMessages.push({type:"summarize",prompt_number:s}),this.broadcastProcessingStatus(i.claudeSessionId,!0),a.json({status:"queued",queueLength:i.pendingMessages.length})}handleStatus(e,a){let r=parseInt(e.params.sessionDbId,10),s=this.sessions.get(r);if(!s){a.status(404).json({error:"Session not found"});return}a.json({sessionDbId:r,sdkSessionId:s.sdkSessionId,project:s.project,pendingMessages:s.pendingMessages.length})}async handleDelete(e,a){let r=parseInt(e.params.sessionDbId,10),s=this.sessions.get(r);if(!s){a.status(404).json({error:"Session not found"});return}Y.warn("WORKER","Session delete requested",{sessionId:r}),s.abortController.abort(),s.generatorPromise&&await Promise.race([s.generatorPromise,new Promise(n=>setTimeout(n,5e3))]);let i=new pr;i.markSessionFailed(r),i.close(),this.sessions.delete(r),Y.info("WORKER","Session deleted",{sessionId:r}),a.json({status:"deleted"})}async runSDKAgent(e){Y.info("SDK","Agent starting",{sessionId:e.sessionDbId});let a=K5();Y.info("SDK",`Using Claude executable: ${a}`,{sessionId:e.sessionDbId});try{let r=$b({prompt:this.createMessageGenerator(e),options:{model:W5,disallowedTools:Q5,abortController:e.abortController,pathToClaudeCodeExecutable:a}});for await(let n of r){if(n.type==="assistant"){let o=n.message.content,l=Array.isArray(o)?o.filter(u=>u.type==="text").map(u=>u.text).join(`
|
||||
`):typeof o=="string"?o:"",c=l.length;Y.dataOut("SDK",`Response received (${c} chars)`,{sessionId:e.sessionDbId,promptNumber:e.lastPromptNumber}),Y.debug("SDK","Full response",{sessionId:e.sessionDbId},l),this.handleAgentMessage(e,l,e.lastPromptNumber)}n.type==="result"&&n.subtype}let s=Date.now()-e.startTime;Y.success("SDK","Agent completed",{sessionId:e.sessionDbId,duration:`${(s/1e3).toFixed(1)}s`});let i=new pr;i.markSessionCompleted(e.sessionDbId),i.close(),this.sessions.delete(e.sessionDbId)}catch(r){throw r.name==="AbortError"?Y.warn("SDK","Agent aborted",{sessionId:e.sessionDbId}):Y.failure("SDK","Agent error",{sessionId:e.sessionDbId},r),r}}async*createMessageGenerator(e){let a=dE(e.project,e.claudeSessionId,e.userPrompt);for(Y.dataIn("SDK",`Init prompt sent (${a.length} chars)`,{sessionId:e.sessionDbId,claudeSessionId:e.claudeSessionId,project:e.project}),Y.debug("SDK","Full init prompt",{sessionId:e.sessionDbId},a),yield{type:"user",session_id:e.claudeSessionId,parent_tool_use_id:null,message:{role:"user",content:a}};!e.abortController.signal.aborted;){if(e.pendingMessages.length===0){await new Promise(r=>setTimeout(r,100));continue}for(;e.pendingMessages.length>0;){let r=e.pendingMessages.shift();if(r.type==="summarize"){e.lastPromptNumber=r.prompt_number;let s=new pr,i=s.getSessionById(e.sessionDbId);s.close();let n=mE(i);Y.dataIn("SDK",`Summary prompt sent (${n.length} chars)`,{sessionId:e.sessionDbId,promptNumber:r.prompt_number}),Y.debug("SDK","Full summary prompt",{sessionId:e.sessionDbId},n),yield{type:"user",session_id:e.claudeSessionId,parent_tool_use_id:null,message:{role:"user",content:n}}}else if(r.type==="observation"){e.lastPromptNumber=r.prompt_number;let s=fE({id:0,tool_name:r.tool_name,tool_input:r.tool_input,tool_response:r.tool_response,created_at_epoch:Date.now()}),i=Y.formatTool(r.tool_name,r.tool_input);Y.dataIn("SDK",`Observation prompt: ${i}`,{sessionId:e.sessionDbId,promptNumber:r.prompt_number,size:`${s.length} chars`}),Y.debug("SDK","Full observation prompt",{sessionId:e.sessionDbId},s),yield{type:"user",session_id:e.claudeSessionId,parent_tool_use_id:null,message:{role:"user",content:s}}}}}}handleAgentMessage(e,a,r){Y.info("PARSER",`Processing response (${a.length} chars)`,{sessionId:e.sessionDbId,promptNumber:r,preview:a.substring(0,200)});let s=hE(a);s.length>0&&Y.info("PARSER",`Parsed ${s.length} observation(s)`,{sessionId:e.sessionDbId,promptNumber:r,types:s.map(o=>o.type).join(", ")});let i=new pr;for(let o of s){let{id:l,createdAtEpoch:c}=i.storeObservation(e.claudeSessionId,e.project,o,r);Y.success("DB","Observation stored",{sessionId:e.sessionDbId,type:o.type,title:o.title,id:l}),this.broadcastSSE({type:"new_observation",observation:{id:l,session_id:e.claudeSessionId,type:o.type,title:o.title,subtitle:o.subtitle,project:e.project,prompt_number:r,created_at_epoch:c}}),this.chromaSync.syncObservation(l,e.claudeSessionId,e.project,o,r,c).then(()=>{Y.success("WORKER","Observation synced to Chroma",{sessionId:e.sessionDbId,observationId:l})}).catch(u=>{Y.error("WORKER","Observation sync failed - continuing",{sessionId:e.sessionDbId,observationId:l},u)})}Y.info("PARSER","Looking for summary tags...",{sessionId:e.sessionDbId});let n=vE(a,e.sessionDbId);if(n){Y.success("PARSER","Summary parsed successfully!",{sessionId:e.sessionDbId,promptNumber:r,hasRequest:!!n.request,hasInvestigated:!!n.investigated,hasLearned:!!n.learned,hasCompleted:!!n.completed,hasNextSteps:!!n.next_steps});let{id:o,createdAtEpoch:l}=i.storeSummary(e.claudeSessionId,e.project,n,r);Y.success("DB","\u{1F4DD} SUMMARY STORED IN DATABASE",{sessionId:e.sessionDbId,promptNumber:r,id:o}),this.broadcastSSE({type:"new_summary",summary:{id:o,session_id:e.claudeSessionId,request:n.request,investigated:n.investigated,learned:n.learned,completed:n.completed,next_steps:n.next_steps,notes:n.notes,project:e.project,prompt_number:r,created_at_epoch:l}}),this.broadcastProcessingStatus(e.claudeSessionId,!1),this.chromaSync.syncSummary(o,e.claudeSessionId,e.project,n,r,l).then(()=>{Y.success("WORKER","Summary synced to Chroma",{sessionId:e.sessionDbId,summaryId:o})}).catch(c=>{Y.error("WORKER","Summary sync failed - continuing",{sessionId:e.sessionDbId,summaryId:o},c)})}else Y.warn("PARSER","NO SUMMARY TAGS FOUND in response",{sessionId:e.sessionDbId,promptNumber:r,contentSample:a.substring(0,500)}),this.broadcastProcessingStatus(e.claudeSessionId,!1);i.close()}};async function X5(){await new Gc().start(),process.on("SIGINT",()=>{Y.warn("SYSTEM","Shutting down (SIGINT)"),process.exit(0)}),process.on("SIGTERM",()=>{Y.warn("SYSTEM","Shutting down (SIGTERM)"),process.exit(0)})}X5().catch(t=>{Y.failure("SYSTEM","Fatal startup error",{},t),process.exit(1)});0&&(module.exports={WorkerService});
|
||||
/*! Bundled license information:
|
||||
|
||||
depd/index.js:
|
||||
|
||||
+91
-46
@@ -164,49 +164,85 @@ function runNpmInstall() {
|
||||
log('🔨 Installing dependencies...', colors.bright);
|
||||
log('', colors.reset);
|
||||
|
||||
try {
|
||||
// Run npm install with error output visible
|
||||
execSync('npm install --prefer-offline --no-audit --no-fund', {
|
||||
cwd: PLUGIN_ROOT,
|
||||
stdio: 'inherit', // Show all output including errors
|
||||
encoding: 'utf-8',
|
||||
});
|
||||
// Try normal install first, then retry with force if it fails
|
||||
const strategies = [
|
||||
{ command: 'npm install', label: 'normal' },
|
||||
{ command: 'npm install --force', label: 'with force flag' },
|
||||
];
|
||||
|
||||
// Verify better-sqlite3 was installed
|
||||
if (!existsSync(BETTER_SQLITE3_PATH)) {
|
||||
throw new Error('better-sqlite3 installation verification failed');
|
||||
let lastError = null;
|
||||
|
||||
for (const { command, label } of strategies) {
|
||||
try {
|
||||
log(`Attempting install ${label}...`, colors.dim);
|
||||
|
||||
// Run npm install silently
|
||||
execSync(command, {
|
||||
cwd: PLUGIN_ROOT,
|
||||
stdio: 'pipe', // Silent output unless error
|
||||
encoding: 'utf-8',
|
||||
});
|
||||
|
||||
// Verify better-sqlite3 was installed
|
||||
if (!existsSync(BETTER_SQLITE3_PATH)) {
|
||||
throw new Error('better-sqlite3 installation verification failed');
|
||||
}
|
||||
|
||||
const version = getPackageVersion();
|
||||
setInstalledVersion(version);
|
||||
|
||||
log('', colors.green);
|
||||
log('✅ Dependencies installed successfully!', colors.bright);
|
||||
log(` Version: ${version}`, colors.dim);
|
||||
log('', colors.reset);
|
||||
|
||||
return true;
|
||||
|
||||
} catch (error) {
|
||||
lastError = error;
|
||||
// Continue to next strategy
|
||||
}
|
||||
|
||||
const version = getPackageVersion();
|
||||
setInstalledVersion(version);
|
||||
|
||||
log('', colors.green);
|
||||
log('✅ Dependencies installed successfully!', colors.bright);
|
||||
log(` Version: ${version}`, colors.dim);
|
||||
log('', colors.reset);
|
||||
|
||||
return true;
|
||||
|
||||
} catch (error) {
|
||||
log('', colors.red);
|
||||
log('❌ Installation failed!', colors.bright);
|
||||
log('', colors.reset);
|
||||
|
||||
// Provide Windows-specific help
|
||||
if (isWindows && error.message && error.message.includes('better-sqlite3')) {
|
||||
log(getWindowsErrorHelp(error.message), colors.yellow);
|
||||
}
|
||||
|
||||
// Show generic error info
|
||||
if (error.stderr) {
|
||||
log('Error output:', colors.dim);
|
||||
log(error.stderr.toString(), colors.red);
|
||||
} else if (error.message) {
|
||||
log(error.message, colors.red);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// All strategies failed - show error
|
||||
log('', colors.red);
|
||||
log('❌ Installation failed after retrying!', colors.bright);
|
||||
log('', colors.reset);
|
||||
|
||||
// Provide Windows-specific help
|
||||
if (isWindows && lastError && lastError.message && lastError.message.includes('better-sqlite3')) {
|
||||
log(getWindowsErrorHelp(lastError.message), colors.yellow);
|
||||
}
|
||||
|
||||
// Show generic error info with troubleshooting steps
|
||||
if (lastError) {
|
||||
if (lastError.stderr) {
|
||||
log('Error output:', colors.dim);
|
||||
log(lastError.stderr.toString(), colors.red);
|
||||
} else if (lastError.message) {
|
||||
log(lastError.message, colors.red);
|
||||
}
|
||||
|
||||
log('', colors.yellow);
|
||||
log('📋 Troubleshooting Steps:', colors.bright);
|
||||
log('', colors.reset);
|
||||
log('1. Check your internet connection', colors.yellow);
|
||||
log('2. Try running: npm cache clean --force', colors.yellow);
|
||||
log('3. Try running: npm install (in plugin directory)', colors.yellow);
|
||||
log('4. Check npm version: npm --version (requires npm 7+)', colors.yellow);
|
||||
log('5. Try updating npm: npm install -g npm@latest', colors.yellow);
|
||||
log('', colors.reset);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we should fail when worker startup fails
|
||||
* Returns true if worker failed AND dependencies are missing
|
||||
*/
|
||||
function shouldFailOnWorkerStartup(workerStarted) {
|
||||
return !workerStarted && !existsSync(NODE_MODULES_PATH);
|
||||
}
|
||||
|
||||
function startWorker() {
|
||||
@@ -253,21 +289,30 @@ async function main() {
|
||||
|
||||
if (!installSuccess) {
|
||||
log('', colors.red);
|
||||
log('⚠️ Installation failed - worker startup may fail', colors.yellow);
|
||||
log('❌ Installation failed - cannot start worker without dependencies', colors.bright);
|
||||
log('', colors.reset);
|
||||
// Don't exit - still try to start worker with existing deps
|
||||
log('Please resolve the installation issues above and try again.', colors.yellow);
|
||||
log('', colors.reset);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Always start/ensure worker is running
|
||||
// This runs whether we installed deps or not
|
||||
startWorker();
|
||||
// Start/ensure worker is running (only after successful install or if deps already exist)
|
||||
const workerStarted = startWorker();
|
||||
|
||||
// Success - dependencies installed (if needed) and worker running
|
||||
if (shouldFailOnWorkerStartup(workerStarted)) {
|
||||
log('', colors.red);
|
||||
log('❌ Worker failed to start and dependencies are missing', colors.bright);
|
||||
log('', colors.reset);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Success - dependencies installed (if needed) and worker running (or already running)
|
||||
process.exit(0);
|
||||
|
||||
} catch (error) {
|
||||
log(`❌ Unexpected error: ${error.message}`, colors.red);
|
||||
log('', colors.reset);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ export interface PostToolUseInput {
|
||||
cwd: string;
|
||||
tool_name: string;
|
||||
tool_input: any;
|
||||
tool_output: any;
|
||||
tool_response: any;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ async function saveHook(input?: PostToolUseInput): Promise<void> {
|
||||
throw new Error('saveHook requires input');
|
||||
}
|
||||
|
||||
const { session_id, tool_name, tool_input, tool_output } = input;
|
||||
const { session_id, tool_name, tool_input, tool_response } = input;
|
||||
|
||||
if (SKIP_TOOLS.has(tool_name)) {
|
||||
console.log(createHookResponse('PostToolUse', true));
|
||||
@@ -65,7 +65,7 @@ async function saveHook(input?: PostToolUseInput): Promise<void> {
|
||||
body: JSON.stringify({
|
||||
tool_name,
|
||||
tool_input: tool_input !== undefined ? JSON.stringify(tool_input) : '{}',
|
||||
tool_output: tool_output !== undefined ? JSON.stringify(tool_output) : '{}',
|
||||
tool_response: tool_response !== undefined ? JSON.stringify(tool_response) : '{}',
|
||||
prompt_number: promptNumber
|
||||
}),
|
||||
signal: AbortSignal.timeout(2000)
|
||||
|
||||
@@ -68,7 +68,7 @@ interface ObservationMessage {
|
||||
type: 'observation';
|
||||
tool_name: string;
|
||||
tool_input: string;
|
||||
tool_output: string;
|
||||
tool_response: string;
|
||||
prompt_number: number;
|
||||
}
|
||||
|
||||
@@ -701,11 +701,11 @@ class WorkerService {
|
||||
|
||||
/**
|
||||
* POST /sessions/:sessionDbId/observations
|
||||
* Body: { tool_name, tool_input, tool_output, prompt_number }
|
||||
* Body: { tool_name, tool_input, tool_response, prompt_number }
|
||||
*/
|
||||
private handleObservation(req: Request, res: Response): void {
|
||||
const sessionDbId = parseInt(req.params.sessionDbId, 10);
|
||||
const { tool_name, tool_input, tool_output, prompt_number } = req.body;
|
||||
const { tool_name, tool_input, tool_response, prompt_number } = req.body;
|
||||
|
||||
let session = this.sessions.get(sessionDbId);
|
||||
if (!session) {
|
||||
@@ -751,7 +751,7 @@ class WorkerService {
|
||||
type: 'observation',
|
||||
tool_name,
|
||||
tool_input,
|
||||
tool_output,
|
||||
tool_response,
|
||||
prompt_number
|
||||
});
|
||||
|
||||
@@ -1015,7 +1015,7 @@ class WorkerService {
|
||||
id: 0,
|
||||
tool_name: message.tool_name,
|
||||
tool_input: message.tool_input,
|
||||
tool_output: message.tool_output,
|
||||
tool_response: message.tool_response,
|
||||
created_at_epoch: Date.now()
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user