claude-mem 12.4.3 → 12.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,2 +1,2 @@
1
- var d="http://127.0.0.1:37777";var g={"Content-Type":"application/json"};function l(t,s){fetch(`${d}${t}`,{method:"POST",headers:g,body:JSON.stringify(s)}).catch(o=>{let r=o instanceof Error?o.message:String(o);r.includes("ECONNREFUSED")||console.warn(`[claude-mem] Worker POST ${t} failed: ${r}`)})}async function E(t){try{let s=await fetch(`${d}${t}`,{headers:g});return s.ok?await s.text():(console.warn(`[claude-mem] Worker GET ${t} returned ${s.status}`),null)}catch(s){let o=s instanceof Error?s.message:String(s);return o.includes("ECONNREFUSED")||console.warn(`[claude-mem] Worker GET ${t} failed: ${o}`),null}}var a=new Map,S=1e3;function u(t){if(!a.has(t)){for(;a.size>=S;){let s=a.keys().next().value;if(s!==void 0)a.delete(s);else break}a.set(t,`opencode-${t}-${Date.now()}`)}return a.get(t)}var w=async t=>{let s=t.project?.name||"opencode";return console.log(`[claude-mem] OpenCode plugin loading (project: ${s})`),{hooks:{tool:{execute:{after:(o,r)=>{let e=u(o.sessionID),n=r.output||"";n.length>1e3&&(n=n.slice(0,1e3)),l("/api/sessions/observations",{contentSessionId:e,tool_name:o.tool,tool_input:o.args||{},tool_response:n,cwd:t.directory})}}}},event:(o,r)=>{switch(o){case"session.created":{let{event:e}=r,n=u(e.sessionID);l("/api/sessions/init",{contentSessionId:n,project:s,prompt:""});break}case"message.updated":{let{event:e}=r;if(e.role!=="assistant")break;let n=u(e.sessionID),c=e.content||"";c.length>1e3&&(c=c.slice(0,1e3)),l("/api/sessions/observations",{contentSessionId:n,tool_name:"assistant_message",tool_input:{},tool_response:c,cwd:t.directory});break}case"session.compacted":{let{event:e}=r,n=u(e.sessionID);l("/api/sessions/summarize",{contentSessionId:n,last_assistant_message:e.summary||""});break}case"file.edited":{let{event:e}=r,n=u(e.sessionID);l("/api/sessions/observations",{contentSessionId:n,tool_name:"file_edit",tool_input:{path:e.path},tool_response:e.diff?e.diff.slice(0,1e3):`File edited: ${e.path}`,cwd:t.directory});break}case"session.deleted":{let{event:e}=r,n=a.get(e.sessionID);n&&(l("/api/sessions/complete",{contentSessionId:n}),a.delete(e.sessionID));break}}},tool:{claude_mem_search:{description:"Search claude-mem memory database for past observations, sessions, and context",args:{query:{type:"string",description:"Search query for memory observations"}},async execute(o){let r=String(o.query||"");if(!r)return"Please provide a search query.";let e=await E(`/api/search/observations?query=${encodeURIComponent(r)}&limit=10`);if(!e)return"claude-mem worker is not running. Start it with: npx claude-mem start";let n;try{n=JSON.parse(e)}catch(i){return console.warn("[claude-mem] Failed to parse search results:",i instanceof Error?i.message:String(i)),"Failed to parse search results."}let c=Array.isArray(n.items)?n.items:[];return c.length===0?`No results found for "${r}".`:c.slice(0,10).map((i,m)=>{let f=String(i.title||i.subtitle||"Untitled"),p=i.project?` [${String(i.project)}]`:"";return`${m+1}. ${f}${p}`}).join(`
1
+ var d="http://127.0.0.1:37777";var g={"Content-Type":"application/json"};function l(n,s){fetch(`${d}${n}`,{method:"POST",headers:g,body:JSON.stringify(s)}).catch(o=>{let r=o instanceof Error?o.message:String(o);r.includes("ECONNREFUSED")||console.warn(`[claude-mem] Worker POST ${n} failed: ${r}`)})}async function E(n){try{let s=await fetch(`${d}${n}`,{headers:g});return s.ok?await s.text():(console.warn(`[claude-mem] Worker GET ${n} returned ${s.status}`),null)}catch(s){let o=s instanceof Error?s.message:String(s);return o.includes("ECONNREFUSED")||console.warn(`[claude-mem] Worker GET ${n} failed: ${o}`),null}}var c=new Map,S=1e3;function u(n){if(!c.has(n)){for(;c.size>=S;){let s=c.keys().next().value;if(s!==void 0)c.delete(s);else break}c.set(n,`opencode-${n}-${Date.now()}`)}return c.get(n)}var w=async n=>{let s=n.project?.name||"opencode";return console.log(`[claude-mem] OpenCode plugin loading (project: ${s})`),{hooks:{tool:{execute:{after:(o,r)=>{let e=u(o.sessionID),t=r.output||"";t.length>1e3&&(t=t.slice(0,1e3)),l("/api/sessions/observations",{contentSessionId:e,tool_name:o.tool,tool_input:o.args||{},tool_response:t,cwd:n.directory})}}}},event:(o,r)=>{switch(o){case"session.created":{let{event:e}=r,t=u(e.sessionID);l("/api/sessions/init",{contentSessionId:t,project:s,prompt:""});break}case"message.updated":{let{event:e}=r;if(e.role!=="assistant")break;let t=u(e.sessionID),a=e.content||"";a.length>1e3&&(a=a.slice(0,1e3)),l("/api/sessions/observations",{contentSessionId:t,tool_name:"assistant_message",tool_input:{},tool_response:a,cwd:n.directory});break}case"session.compacted":{let{event:e}=r,t=u(e.sessionID);l("/api/sessions/summarize",{contentSessionId:t,last_assistant_message:e.summary||""});break}case"file.edited":{let{event:e}=r,t=u(e.sessionID);l("/api/sessions/observations",{contentSessionId:t,tool_name:"file_edit",tool_input:{path:e.path},tool_response:e.diff?e.diff.slice(0,1e3):`File edited: ${e.path}`,cwd:n.directory});break}case"session.deleted":{let{event:e}=r;c.delete(e.sessionID);break}}},tool:{claude_mem_search:{description:"Search claude-mem memory database for past observations, sessions, and context",args:{query:{type:"string",description:"Search query for memory observations"}},async execute(o){let r=String(o.query||"");if(!r)return"Please provide a search query.";let e=await E(`/api/search/observations?query=${encodeURIComponent(r)}&limit=10`);if(!e)return"claude-mem worker is not running. Start it with: npx claude-mem start";let t;try{t=JSON.parse(e)}catch(i){return console.warn("[claude-mem] Failed to parse search results:",i instanceof Error?i.message:String(i)),"Failed to parse search results."}let a=Array.isArray(t.items)?t.items:[];return a.length===0?`No results found for "${r}".`:a.slice(0,10).map((i,m)=>{let f=String(i.title||i.subtitle||"Untitled"),p=i.project?` [${String(i.project)}]`:"";return`${m+1}. ${f}${p}`}).join(`
2
2
  `)}}}}},O=w;export{w as ClaudeMemPlugin,O as default};
@@ -1,15 +1,15 @@
1
- var V="127.0.0.1",Z=["\u{1F527}","\u{1F4D0}","\u{1F50D}","\u{1F4BB}","\u{1F9EA}","\u{1F41B}","\u{1F6E1}\uFE0F","\u2601\uFE0F","\u{1F4E6}","\u{1F3AF}","\u{1F52E}","\u26A1","\u{1F30A}","\u{1F3A8}","\u{1F4CA}","\u{1F680}","\u{1F52C}","\u{1F3D7}\uFE0F","\u{1F4DD}","\u{1F3AD}"];function te(e){let s=0;for(let o=0;o<e.length;o++)s=(s<<5)-s+e.charCodeAt(o)|0;return Z[Math.abs(s)%Z.length]}var re="\u{1F99E}",se="\u2328\uFE0F",oe="Claude Code Session",ie="\u{1F980}";function ae(e){let s=e?.primary??re,o=e?.claudeCode??se,a=e?.claudeCodeLabel??oe,c=e?.default??ie,g=e?.agents??{};return function(f){if(!f)return c;if(f.startsWith("openclaw-")){let b=f.slice(9);return b?`${g[b]||te(b)} ${b}`:`${s} openclaw`}if(f==="openclaw")return`${s} openclaw`;let v=a.trim();return v?`${o} ${v} (${f})`:`${o} ${f}`}}var H=V;function T(e){return`http://${H}:${e}`}var ce=3,ee=3e4,h="CLOSED",j=0,G=0,P=!1;function z(e){return h==="CLOSED"?!0:h==="OPEN"?Date.now()-G>=ee?(h="HALF_OPEN",e.info("[claude-mem] Circuit breaker: probing worker connection"),P?!1:(P=!0,!0)):!1:P?!1:(P=!0,!0)}function X(e){h!=="CLOSED"&&e.info("[claude-mem] Worker connection restored \u2014 circuit closed"),h="CLOSED",j=0,P=!1}function O(e){P=!1,j++,(h==="HALF_OPEN"||h==="CLOSED"&&j>=ce)&&(h="OPEN",G=Date.now(),e.warn(`[claude-mem] Worker unreachable \u2014 disabling requests for ${ee/1e3}s`))}function le(){h="CLOSED",j=0,G=0,P=!1}async function Y(e,s,o,a){if(!z(a))return null;try{let c=await fetch(`${T(e)}${s}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(o)});return c.ok?(X(a),await c.json()):(O(a),a.warn(`[claude-mem] Worker POST ${s} returned ${c.status}`),null)}catch(c){let g=c instanceof Error?c.message:String(c);return O(a),h!=="OPEN"&&a.warn(`[claude-mem] Worker POST ${s} failed: ${g}`),null}}function Q(e,s,o,a){z(a)&&fetch(`${T(e)}${s}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(o)}).then(c=>{if(!c.ok){O(a),a.warn(`[claude-mem] Worker POST ${s} returned ${c.status}`);return}X(a)}).catch(c=>{let g=c instanceof Error?c.message:String(c);O(a),h!=="OPEN"&&a.warn(`[claude-mem] Worker POST ${s} failed: ${g}`)})}async function J(e,s,o){if(!z(o))return null;try{let a=await fetch(`${T(e)}${s}`);return a.ok?(X(o),await a.text()):(O(o),o.warn(`[claude-mem] Worker GET ${s} returned ${a.status}`),null)}catch(a){let c=a instanceof Error?a.message:String(a);return O(o),h!=="OPEN"&&o.warn(`[claude-mem] Worker GET ${s} failed: ${c}`),null}}async function q(e,s,o){let a=await J(e,s,o);if(!a)return null;try{return JSON.parse(a)}catch{return o.warn(`[claude-mem] Worker GET ${s} returned non-JSON response`),null}}function ue(e,s){let o=e.title||"Untitled",c=`${s(e.project)}
1
+ var Z="127.0.0.1",z=["\u{1F527}","\u{1F4D0}","\u{1F50D}","\u{1F4BB}","\u{1F9EA}","\u{1F41B}","\u{1F6E1}\uFE0F","\u2601\uFE0F","\u{1F4E6}","\u{1F3AF}","\u{1F52E}","\u26A1","\u{1F30A}","\u{1F3A8}","\u{1F4CA}","\u{1F680}","\u{1F52C}","\u{1F3D7}\uFE0F","\u{1F4DD}","\u{1F3AD}"];function Q(e){let s=0;for(let o=0;o<e.length;o++)s=(s<<5)-s+e.charCodeAt(o)|0;return z[Math.abs(s)%z.length]}var V="\u{1F99E}",ee="\u2328\uFE0F",ne="Claude Code Session",te="\u{1F980}";function re(e){let s=e?.primary??V,o=e?.claudeCode??ee,a=e?.claudeCodeLabel??ne,c=e?.default??te,d=e?.agents??{};return function(m){if(!m)return c;if(m.startsWith("openclaw-")){let p=m.slice(9);return p?`${d[p]||Q(p)} ${p}`:`${s} openclaw`}if(m==="openclaw")return`${s} openclaw`;let b=a.trim();return b?`${o} ${b} (${m})`:`${o} ${m}`}}var W=Z;function T(e){return`http://${W}:${e}`}var se=3,Y=3e4,h="CLOSED",N=0,H=0,P=!1;function J(e){return h==="CLOSED"?!0:h==="OPEN"?Date.now()-H>=Y?(h="HALF_OPEN",e.info("[claude-mem] Circuit breaker: probing worker connection"),P?!1:(P=!0,!0)):!1:P?!1:(P=!0,!0)}function G(e){h!=="CLOSED"&&e.info("[claude-mem] Worker connection restored \u2014 circuit closed"),h="CLOSED",N=0,P=!1}function x(e){P=!1,N++,(h==="HALF_OPEN"||h==="CLOSED"&&N>=se)&&(h="OPEN",H=Date.now(),e.warn(`[claude-mem] Worker unreachable \u2014 disabling requests for ${Y/1e3}s`))}function oe(){h="CLOSED",N=0,H=0,P=!1}async function X(e,s,o,a){if(!J(a))return null;try{let c=await fetch(`${T(e)}${s}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(o)});return c.ok?(G(a),await c.json()):(x(a),a.warn(`[claude-mem] Worker POST ${s} returned ${c.status}`),null)}catch(c){let d=c instanceof Error?c.message:String(c);return x(a),h!=="OPEN"&&a.warn(`[claude-mem] Worker POST ${s} failed: ${d}`),null}}function ie(e,s,o,a){J(a)&&fetch(`${T(e)}${s}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(o)}).then(c=>{if(!c.ok){x(a),a.warn(`[claude-mem] Worker POST ${s} returned ${c.status}`);return}G(a)}).catch(c=>{let d=c instanceof Error?c.message:String(c);x(a),h!=="OPEN"&&a.warn(`[claude-mem] Worker POST ${s} failed: ${d}`)})}async function q(e,s,o){if(!J(o))return null;try{let a=await fetch(`${T(e)}${s}`);return a.ok?(G(o),await a.text()):(x(o),o.warn(`[claude-mem] Worker GET ${s} returned ${a.status}`),null)}catch(a){let c=a instanceof Error?a.message:String(a);return x(o),h!=="OPEN"&&o.warn(`[claude-mem] Worker GET ${s} failed: ${c}`),null}}async function K(e,s,o){let a=await q(e,s,o);if(!a)return null;try{return JSON.parse(a)}catch{return o.warn(`[claude-mem] Worker GET ${s} returned non-JSON response`),null}}function ae(e,s){let o=e.title||"Untitled",c=`${s(e.project)}
2
2
  **${o}**`;return e.subtitle&&(c+=`
3
- ${e.subtitle}`),c}var ge={telegram:{namespace:"telegram",functionName:"sendMessageTelegram"},whatsapp:{namespace:"whatsapp",functionName:"sendMessageWhatsApp"},discord:{namespace:"discord",functionName:"sendMessageDiscord"},slack:{namespace:"slack",functionName:"sendMessageSlack"},signal:{namespace:"signal",functionName:"sendMessageSignal"},imessage:{namespace:"imessage",functionName:"sendMessageIMessage"},line:{namespace:"line",functionName:"sendMessageLine"}};async function de(e,s,o,a){try{let c=await fetch(`https://api.telegram.org/bot${e}/sendMessage`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({chat_id:s,text:o,parse_mode:"Markdown"})});if(!c.ok){let g=await c.text();a.warn(`[claude-mem] Direct Telegram send failed (${c.status}): ${g}`)}}catch(c){let g=c instanceof Error?c.message:String(c);a.warn(`[claude-mem] Direct Telegram send error: ${g}`)}}function me(e,s,o,a,c){if(c&&s==="telegram")return de(c,o,a,e.logger);let g=ge[s];if(!g)return e.logger.warn(`[claude-mem] Unsupported channel type: ${s}`),Promise.resolve();let w=e.runtime.channel[g.namespace];if(!w)return e.logger.warn(`[claude-mem] Channel "${s}" not available in runtime`),Promise.resolve();let f=w[g.functionName];return f?f(...s==="whatsapp"?[o,a,{verbose:!1}]:[o,a]).catch(b=>{let m=b instanceof Error?b.message:String(b);e.logger.error(`[claude-mem] Failed to send to ${s}: ${m}`)}):(e.logger.warn(`[claude-mem] Channel "${s}" has no ${g.functionName} function`),Promise.resolve())}async function fe(e,s,o,a,c,g,w,f){let v=1e3,b=3e4;for(;!c.signal.aborted;){try{g("reconnecting"),e.logger.info(`[claude-mem] Connecting to SSE stream at ${T(s)}/stream`);let m=await fetch(`${T(s)}/stream`,{signal:c.signal,headers:{Accept:"text/event-stream"}});if(!m.ok)throw new Error(`SSE stream returned HTTP ${m.status}`);if(!m.body)throw new Error("SSE stream response has no body");g("connected"),v=1e3,e.logger.info("[claude-mem] Connected to SSE stream");let A=m.body.getReader(),D=new TextDecoder,k="";for(;;){let{done:B,value:U}=await A.read();if(B)break;k+=D.decode(U,{stream:!0}),k.length>1048576&&(e.logger.warn("[claude-mem] SSE buffer overflow, clearing buffer"),k="");let M=k.split(`
3
+ ${e.subtitle}`),c}var ce={telegram:{namespace:"telegram",functionName:"sendMessageTelegram"},whatsapp:{namespace:"whatsapp",functionName:"sendMessageWhatsApp"},discord:{namespace:"discord",functionName:"sendMessageDiscord"},slack:{namespace:"slack",functionName:"sendMessageSlack"},signal:{namespace:"signal",functionName:"sendMessageSignal"},imessage:{namespace:"imessage",functionName:"sendMessageIMessage"},line:{namespace:"line",functionName:"sendMessageLine"}};async function le(e,s,o,a){try{let c=await fetch(`https://api.telegram.org/bot${e}/sendMessage`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({chat_id:s,text:o,parse_mode:"Markdown"})});if(!c.ok){let d=await c.text();a.warn(`[claude-mem] Direct Telegram send failed (${c.status}): ${d}`)}}catch(c){let d=c instanceof Error?c.message:String(c);a.warn(`[claude-mem] Direct Telegram send error: ${d}`)}}function ue(e,s,o,a,c){if(c&&s==="telegram")return le(c,o,a,e.logger);let d=ce[s];if(!d)return e.logger.warn(`[claude-mem] Unsupported channel type: ${s}`),Promise.resolve();let w=e.runtime.channel[d.namespace];if(!w)return e.logger.warn(`[claude-mem] Channel "${s}" not available in runtime`),Promise.resolve();let m=w[d.functionName];return m?m(...s==="whatsapp"?[o,a,{verbose:!1}]:[o,a]).catch(p=>{let v=p instanceof Error?p.message:String(p);e.logger.error(`[claude-mem] Failed to send to ${s}: ${v}`)}):(e.logger.warn(`[claude-mem] Channel "${s}" has no ${d.functionName} function`),Promise.resolve())}async function de(e,s,o,a,c,d,w,m){let b=1e3,p=3e4;for(;!c.signal.aborted;){try{d("reconnecting"),e.logger.info(`[claude-mem] Connecting to SSE stream at ${T(s)}/stream`);let v=await fetch(`${T(s)}/stream`,{signal:c.signal,headers:{Accept:"text/event-stream"}});if(!v.ok)throw new Error(`SSE stream returned HTTP ${v.status}`);if(!v.body)throw new Error("SSE stream response has no body");d("connected"),b=1e3,e.logger.info("[claude-mem] Connected to SSE stream");let M=v.body.getReader(),j=new TextDecoder,_="";for(;;){let{done:R,value:k}=await M.read();if(R)break;_+=j.decode(k,{stream:!0}),_.length>1048576&&(e.logger.warn("[claude-mem] SSE buffer overflow, clearing buffer"),_="");let L=_.split(`
4
4
 
5
- `);k=M.pop()||"";for(let E of M){let R=E.split(`
6
- `).filter(S=>S.startsWith("data:")).map(S=>S.slice(5).trim());if(R.length===0)continue;let L=R.join(`
7
- `);if(L)try{let S=JSON.parse(L);if(S.type==="new_observation"&&S.observation){let x=ue(S.observation,w);await me(e,o,a,x,f)}}catch(S){let F=S instanceof Error?S.message:String(S);e.logger.warn(`[claude-mem] Failed to parse SSE frame: ${F}`)}}}}catch(m){if(c.signal.aborted)break;g("reconnecting");let A=m instanceof Error?m.message:String(m);e.logger.warn(`[claude-mem] SSE stream error: ${A}. Reconnecting in ${v/1e3}s`)}if(c.signal.aborted)break;await new Promise(m=>setTimeout(m,v)),v=Math.min(v*2,b)}g("disconnected")}function pe(e){let s=e.pluginConfig||{},o=s.workerPort||37777;H=s.workerHost||V;let a=s.project||"openclaw",c=ae(s.observationFeed?.emojis);function g(r){return r.agentId?`openclaw-${r.agentId}`:a}let w=new Map,f=new Map,v=new Map,b=new Map,m=new Map,A=(()=>{let r=Number(s.completionDelayMs);return Number.isFinite(r)?Math.max(0,r):5e3})(),D=s.syncMemoryFile!==!1,k=new Set(s.syncMemoryFileExclude||[]);function B(r){let n=r||"default";return w.has(n)||w.set(n,`openclaw-${n}-${Date.now()}`),w.get(n)}function U(r){if(!D)return!1;let n=r?.agentId;return!(n&&k.has(n))}function M(r){let n=new Set;for(let t of[r.sessionKey,r.conversationId,r.channelId]){let i=typeof t=="string"?t.trim():"";i&&n.add(i)}return n.size===0&&n.add("default"),Array.from(n)}function E(r){let n=M(r),t=n.find(u=>f.has(u));t=t?f.get(t):n[0];let i=v.get(t);i||(i=new Set([t]),v.set(t,i));for(let u of n)i.add(u),f.set(u,t);let l=B(t);for(let u of i)w.set(u,l);return{canonicalKey:t,contentSessionId:l}}function R(r,n,t){let i=Date.now();for(let[d,p]of m)i-p>2e3&&m.delete(d);let l=`${r}::${n}::${t}`,u=m.get(l);return m.set(l,i),typeof u=="number"&&i-u<=2e3}function L(r){let n=M(r),t=n.map(l=>f.get(l)).find(Boolean)||n[0],i=v.get(t)||new Set([t,...n]);for(let l of i)f.delete(l),w.delete(l);v.delete(t),w.delete(t)}function S(r){let n=b.get(r);n&&clearTimeout(n);let t=setTimeout(()=>{b.delete(r),Q(o,"/api/sessions/complete",{contentSessionId:r},e.logger)},A);b.set(r,t)}let F=6e4,x=new Map;async function ne(r){let n=[a],t=r?g(r):null;t&&t!==a&&n.push(t);let i=n.join(","),l=x.get(i);if(l&&Date.now()-l.fetchedAt<F)return l.text;let u=await J(o,`/api/context/inject?projects=${encodeURIComponent(i)}`,e.logger);if(u&&u.trim().length>0){let d=u.trim();return x.set(i,{text:d,fetchedAt:Date.now()}),d}return null}e.on("session_start",async(r,n)=>{let{contentSessionId:t}=E(n);e.logger.info(`[claude-mem] Session tracking initialized: ${t}`)}),e.on("message_received",async(r,n)=>{let{canonicalKey:t,contentSessionId:i}=E(n);e.logger.info(`[claude-mem] Message received \u2014 prompt capture deferred to before_agent_start: session=${t} contentSessionId=${i} hasContent=${!!r.content}`)}),e.on("after_compaction",async(r,n)=>{let{contentSessionId:t}=E(n);e.logger.info(`[claude-mem] Session preserved after compaction: ${t}`)}),e.on("before_agent_start",async(r,n)=>{let{contentSessionId:t}=E(n),i=g(n),l=r.prompt||"agent run";if(R(t,i,l)){e.logger.info(`[claude-mem] Skipping duplicate prompt init: contentSessionId=${t} project=${i}`);return}await Y(o,"/api/sessions/init",{contentSessionId:t,project:i,prompt:l},e.logger),e.logger.info(`[claude-mem] Session initialized via before_agent_start: contentSessionId=${t} project=${i}`)}),e.on("before_prompt_build",async(r,n)=>{if(!U(n))return;let t=await ne(n);if(t)return e.logger.info(`[claude-mem] Context injected via system prompt for agent=${n.agentId??"unknown"}`),{appendSystemContext:t}}),e.on("tool_result_persist",(r,n)=>{e.logger.info(`[claude-mem] tool_result_persist fired: tool=${r.toolName??"unknown"} agent=${n.agentId??"none"} session=${n.sessionKey??"none"}`);let t=r.toolName;if(!t||t.startsWith("memory_"))return;let{canonicalKey:i,contentSessionId:l}=E(n),u="",d=r.message?.content;Array.isArray(d)&&(u=d.filter(C=>(C.type==="tool_result"||C.type==="text")&&"text"in C).map(C=>String(C.text)).join(`
8
- `));let p=1e3;u.length>p&&(u=u.slice(0,p));let y=n.workspaceDir;if(!y){e.logger.warn(`[claude-mem] Skipping observation persist because workspaceDir is unavailable: session=${i} tool=${t}`);return}Q(o,"/api/sessions/observations",{contentSessionId:l,tool_name:t,tool_input:r.params||{},tool_response:u,cwd:y},e.logger)}),e.on("agent_end",async(r,n)=>{let{contentSessionId:t}=E(n),i="";if(Array.isArray(r.messages))for(let l=r.messages.length-1;l>=0;l--){let u=r.messages[l];if(u?.role==="assistant"){typeof u.content=="string"?i=u.content:Array.isArray(u.content)&&(i=u.content.filter(d=>d.type==="text").map(d=>d.text||"").join(`
9
- `));break}}await Y(o,"/api/sessions/summarize",{contentSessionId:t,last_assistant_message:i},e.logger),e.logger.info(`[claude-mem] Scheduling session complete in ${A}ms: ${t}`),S(t)}),e.on("session_end",async(r,n)=>{L(n),e.logger.info("[claude-mem] Session tracking cleaned up")}),e.on("gateway_start",async()=>{le(),w.clear(),x.clear(),m.clear(),f.clear(),v.clear();for(let r of b.values())clearTimeout(r);b.clear(),e.logger.info("[claude-mem] Gateway started \u2014 session tracking reset")});let _=null,N="disconnected",$=null;e.registerService({id:"claude-mem-observation-feed",start:async r=>{_&&(_.abort(),$&&(await $,$=null));let n=s.observationFeed;if(!n?.enabled){e.logger.info("[claude-mem] Observation feed disabled");return}if(!n.channel||!n.to){e.logger.warn("[claude-mem] Observation feed misconfigured \u2014 channel or target missing");return}e.logger.info(`[claude-mem] Observation feed starting \u2014 channel: ${n.channel}, target: ${n.to}`),_=new AbortController,$=fe(e,o,n.channel,n.to,_,t=>{N=t},c,n.botToken)},stop:async r=>{_&&(_.abort(),_=null),$&&(await $,$=null),N="disconnected",e.logger.info("[claude-mem] Observation feed stopped \u2014 SSE connection closed")}});function K(r,n=5){return!Array.isArray(r)||r.length===0?"No results found.":r.slice(0,n).map((t,i)=>{let l=t,u=String(l.title||l.subtitle||l.text||"Untitled"),d=l.project?` [${String(l.project)}]`:"";return`${i+1}. ${u}${d}`}).join(`
10
- `)}function I(r,n=10){let t=Number(r);return Number.isFinite(t)?Math.max(1,Math.min(50,Math.trunc(t))):n}e.registerCommand({name:"claude_mem_feed",description:"Show or toggle Claude-Mem observation feed status",acceptsArgs:!0,handler:async r=>{let n=s.observationFeed;if(!n)return{text:"Observation feed not configured. Add observationFeed to your plugin config."};let t=r.args?.trim();return t==="on"?(e.logger.info("[claude-mem] Feed enable requested via command"),{text:"Feed enable requested. Update observationFeed.enabled in your plugin config to persist."}):t==="off"?(e.logger.info("[claude-mem] Feed disable requested via command"),{text:"Feed disable requested. Update observationFeed.enabled in your plugin config to persist."}):{text:["Claude-Mem Observation Feed",`Enabled: ${n.enabled?"yes":"no"}`,`Channel: ${n.channel||"not set"}`,`Target: ${n.to||"not set"}`,`Connection: ${N}`].join(`
11
- `)}}}),e.registerCommand({name:"claude-mem-search",description:"Search Claude-Mem observations by query",acceptsArgs:!0,handler:async r=>{let n=r.args?.trim()||"";if(!n)return"Usage: /claude-mem-search <query> [limit]";let t=n.split(/\s+/),i=t[t.length-1],l=/^\d+$/.test(i),u=l?I(i,10):10,d=l?t.slice(0,-1).join(" "):n,p=await q(o,`/api/search/observations?query=${encodeURIComponent(d)}&limit=${u}`,e.logger);if(!p)return"Claude-Mem search failed (worker unavailable or invalid response).";let y=Array.isArray(p.items)?p.items:[];return[`Claude-Mem Search: "${d}"`,K(y,u)].join(`
12
- `)}}),e.registerCommand({name:"claude-mem-recent",description:"Show recent Claude-Mem context for a project",acceptsArgs:!0,handler:async r=>{let n=r.args?.trim()||"",t=n?n.split(/\s+/):[],i=t.length>0?t[t.length-1]:"",l=/^\d+$/.test(i),u=l?I(i,3):3,d=l?t.slice(0,-1).join(" "):n,p=new URLSearchParams;p.set("limit",String(u)),d&&p.set("project",d);let y=await q(o,`/api/context/recent?${p.toString()}`,e.logger);if(!y)return"Claude-Mem recent context failed (worker unavailable or invalid response).";let C=Array.isArray(y.session_summaries)?y.session_summaries:[],W=Array.isArray(y.recent_observations)?y.recent_observations:[];return["Claude-Mem Recent Context",`Project: ${d||"(auto)"}`,`Session summaries: ${C.length}`,`Recent observations: ${W.length}`,K(W,Math.min(5,W.length||5))].join(`
13
- `)}}),e.registerCommand({name:"claude-mem-timeline",description:"Find best memory match and show nearby timeline events",acceptsArgs:!0,handler:async r=>{let n=r.args?.trim()||"";if(!n)return"Usage: /claude-mem-timeline <query> [depthBefore] [depthAfter]";let t=n.split(/\s+/),i=5,l=5;t.length>=2&&/^\d+$/.test(t[t.length-1])&&(i=I(t.pop(),5)),t.length>=2&&/^\d+$/.test(t[t.length-1])&&(l=I(t.pop(),5));let u=t.join(" "),d=new URLSearchParams({query:u,mode:"auto",depth_before:String(l),depth_after:String(i)}),p=await q(o,`/api/timeline/by-query?${d.toString()}`,e.logger);if(!p)return"Claude-Mem timeline lookup failed (worker unavailable or invalid response).";let y=Array.isArray(p.timeline)?p.timeline:[],C=p.anchor?String(p.anchor):"(none)";return[`Claude-Mem Timeline: "${u}"`,`Anchor: ${C}`,K(y,8)].join(`
14
- `)}}),e.registerCommand({name:"claude_mem_status",description:"Check Claude-Mem worker health and session status",handler:async()=>{let r=await J(o,"/api/health",e.logger);if(!r)return{text:`Claude-Mem worker unreachable at port ${o}`};try{return{text:["Claude-Mem Worker Status",`Status: ${JSON.parse(r).status||"unknown"}`,`Port: ${o}`,`Active sessions: ${w.size}`,`Observation feed: ${N}`].join(`
15
- `)}}catch{return{text:"Claude-Mem worker responded but returned unexpected data"}}}}),e.logger.info(`[claude-mem] OpenClaw plugin loaded \u2014 v1.0.0 (worker: ${H}:${o})`)}export{pe as default};
5
+ `);_=L.pop()||"";for(let D of L){let F=D.split(`
6
+ `).filter(S=>S.startsWith("data:")).map(S=>S.slice(5).trim());if(F.length===0)continue;let A=F.join(`
7
+ `);if(A)try{let S=JSON.parse(A);if(S.type==="new_observation"&&S.observation){let O=ae(S.observation,w);await ue(e,o,a,O,m)}}catch(S){let C=S instanceof Error?S.message:String(S);e.logger.warn(`[claude-mem] Failed to parse SSE frame: ${C}`)}}}}catch(v){if(c.signal.aborted)break;d("reconnecting");let M=v instanceof Error?v.message:String(v);e.logger.warn(`[claude-mem] SSE stream error: ${M}. Reconnecting in ${b/1e3}s`)}if(c.signal.aborted)break;await new Promise(v=>setTimeout(v,b)),b=Math.min(b*2,p)}d("disconnected")}function ge(e){let s=e.pluginConfig||{},o=s.workerPort||37777;W=s.workerHost||Z;let a=s.project||"openclaw",c=re(s.observationFeed?.emojis);function d(r){return r.agentId?`openclaw-${r.agentId}`:a}let w=new Map,m=new Map,b=new Map,p=new Map,v=s.syncMemoryFile!==!1,M=new Set(s.syncMemoryFileExclude||[]);function j(r){let n=r||"default";return w.has(n)||w.set(n,`openclaw-${n}-${Date.now()}`),w.get(n)}function _(r){if(!v)return!1;let n=r?.agentId;return!(n&&M.has(n))}function R(r){let n=new Set;for(let t of[r.sessionKey,r.conversationId,r.channelId]){let i=typeof t=="string"?t.trim():"";i&&n.add(i)}return n.size===0&&n.add("default"),Array.from(n)}function k(r){let n=R(r),t=n.find(u=>m.has(u));t=t?m.get(t):n[0];let i=b.get(t);i||(i=new Set([t]),b.set(t,i));for(let u of n)i.add(u),m.set(u,t);let l=j(t);for(let u of i)w.set(u,l);return{canonicalKey:t,contentSessionId:l}}function L(r,n,t){let i=Date.now();for(let[g,f]of p)i-f>2e3&&p.delete(g);let l=`${r}::${n}::${t}`,u=p.get(l);return p.set(l,i),typeof u=="number"&&i-u<=2e3}function D(r){let n=R(r),t=n.map(l=>m.get(l)).find(Boolean)||n[0],i=b.get(t)||new Set([t,...n]);for(let l of i)m.delete(l),w.delete(l);b.delete(t),w.delete(t)}let F=6e4,A=new Map;async function S(r){let n=[a],t=r?d(r):null;t&&t!==a&&n.push(t);let i=n.join(","),l=A.get(i);if(l&&Date.now()-l.fetchedAt<F)return l.text;let u=await q(o,`/api/context/inject?projects=${encodeURIComponent(i)}`,e.logger);if(u&&u.trim().length>0){let g=u.trim();return A.set(i,{text:g,fetchedAt:Date.now()}),g}return null}e.on("session_start",async(r,n)=>{let{contentSessionId:t}=k(n);e.logger.info(`[claude-mem] Session tracking initialized: ${t}`)}),e.on("message_received",async(r,n)=>{let{canonicalKey:t,contentSessionId:i}=k(n);e.logger.info(`[claude-mem] Message received \u2014 prompt capture deferred to before_agent_start: session=${t} contentSessionId=${i} hasContent=${!!r.content}`)}),e.on("after_compaction",async(r,n)=>{let{contentSessionId:t}=k(n);e.logger.info(`[claude-mem] Session preserved after compaction: ${t}`)}),e.on("before_agent_start",async(r,n)=>{let{contentSessionId:t}=k(n),i=d(n),l=r.prompt||"agent run";if(L(t,i,l)){e.logger.info(`[claude-mem] Skipping duplicate prompt init: contentSessionId=${t} project=${i}`);return}await X(o,"/api/sessions/init",{contentSessionId:t,project:i,prompt:l},e.logger),e.logger.info(`[claude-mem] Session initialized via before_agent_start: contentSessionId=${t} project=${i}`)}),e.on("before_prompt_build",async(r,n)=>{if(!_(n))return;let t=await S(n);if(t)return e.logger.info(`[claude-mem] Context injected via system prompt for agent=${n.agentId??"unknown"}`),{appendSystemContext:t}}),e.on("tool_result_persist",(r,n)=>{e.logger.info(`[claude-mem] tool_result_persist fired: tool=${r.toolName??"unknown"} agent=${n.agentId??"none"} session=${n.sessionKey??"none"}`);let t=r.toolName;if(!t||t.startsWith("memory_"))return;let{canonicalKey:i,contentSessionId:l}=k(n),u="",g=r.message?.content;Array.isArray(g)&&(u=g.filter(E=>(E.type==="tool_result"||E.type==="text")&&"text"in E).map(E=>String(E.text)).join(`
8
+ `));let f=1e3;u.length>f&&(u=u.slice(0,f));let y=n.workspaceDir;if(!y){e.logger.warn(`[claude-mem] Skipping observation persist because workspaceDir is unavailable: session=${i} tool=${t}`);return}ie(o,"/api/sessions/observations",{contentSessionId:l,tool_name:t,tool_input:r.params||{},tool_response:u,cwd:y},e.logger)}),e.on("agent_end",async(r,n)=>{let{contentSessionId:t}=k(n),i="";if(Array.isArray(r.messages))for(let l=r.messages.length-1;l>=0;l--){let u=r.messages[l];if(u?.role==="assistant"){typeof u.content=="string"?i=u.content:Array.isArray(u.content)&&(i=u.content.filter(g=>g.type==="text").map(g=>g.text||"").join(`
9
+ `));break}}await X(o,"/api/sessions/summarize",{contentSessionId:t,last_assistant_message:i},e.logger)}),e.on("session_end",async(r,n)=>{D(n),e.logger.info("[claude-mem] Session tracking cleaned up")}),e.on("gateway_start",async()=>{oe(),w.clear(),A.clear(),p.clear(),m.clear(),b.clear(),e.logger.info("[claude-mem] Gateway started \u2014 session tracking reset")});let C=null,O="disconnected",$=null;e.registerService({id:"claude-mem-observation-feed",start:async r=>{C&&(C.abort(),$&&(await $,$=null));let n=s.observationFeed;if(!n?.enabled){e.logger.info("[claude-mem] Observation feed disabled");return}if(!n.channel||!n.to){e.logger.warn("[claude-mem] Observation feed misconfigured \u2014 channel or target missing");return}e.logger.info(`[claude-mem] Observation feed starting \u2014 channel: ${n.channel}, target: ${n.to}`),C=new AbortController,$=de(e,o,n.channel,n.to,C,t=>{O=t},c,n.botToken)},stop:async r=>{C&&(C.abort(),C=null),$&&(await $,$=null),O="disconnected",e.logger.info("[claude-mem] Observation feed stopped \u2014 SSE connection closed")}});function B(r,n=5){return!Array.isArray(r)||r.length===0?"No results found.":r.slice(0,n).map((t,i)=>{let l=t,u=String(l.title||l.subtitle||l.text||"Untitled"),g=l.project?` [${String(l.project)}]`:"";return`${i+1}. ${u}${g}`}).join(`
10
+ `)}function I(r,n=10){let t=Number(r);return Number.isFinite(t)?Math.max(1,Math.min(50,Math.trunc(t))):n}e.registerCommand({name:"claude_mem_feed",description:"Show or toggle Claude-Mem observation feed status",acceptsArgs:!0,handler:async r=>{let n=s.observationFeed;if(!n)return{text:"Observation feed not configured. Add observationFeed to your plugin config."};let t=r.args?.trim();return t==="on"?(e.logger.info("[claude-mem] Feed enable requested via command"),{text:"Feed enable requested. Update observationFeed.enabled in your plugin config to persist."}):t==="off"?(e.logger.info("[claude-mem] Feed disable requested via command"),{text:"Feed disable requested. Update observationFeed.enabled in your plugin config to persist."}):{text:["Claude-Mem Observation Feed",`Enabled: ${n.enabled?"yes":"no"}`,`Channel: ${n.channel||"not set"}`,`Target: ${n.to||"not set"}`,`Connection: ${O}`].join(`
11
+ `)}}}),e.registerCommand({name:"claude-mem-search",description:"Search Claude-Mem observations by query",acceptsArgs:!0,handler:async r=>{let n=r.args?.trim()||"";if(!n)return"Usage: /claude-mem-search <query> [limit]";let t=n.split(/\s+/),i=t[t.length-1],l=/^\d+$/.test(i),u=l?I(i,10):10,g=l?t.slice(0,-1).join(" "):n,f=await K(o,`/api/search/observations?query=${encodeURIComponent(g)}&limit=${u}`,e.logger);if(!f)return"Claude-Mem search failed (worker unavailable or invalid response).";let y=Array.isArray(f.items)?f.items:[];return[`Claude-Mem Search: "${g}"`,B(y,u)].join(`
12
+ `)}}),e.registerCommand({name:"claude-mem-recent",description:"Show recent Claude-Mem context for a project",acceptsArgs:!0,handler:async r=>{let n=r.args?.trim()||"",t=n?n.split(/\s+/):[],i=t.length>0?t[t.length-1]:"",l=/^\d+$/.test(i),u=l?I(i,3):3,g=l?t.slice(0,-1).join(" "):n,f=new URLSearchParams;f.set("limit",String(u)),g&&f.set("project",g);let y=await K(o,`/api/context/recent?${f.toString()}`,e.logger);if(!y)return"Claude-Mem recent context failed (worker unavailable or invalid response).";let E=Array.isArray(y.session_summaries)?y.session_summaries:[],U=Array.isArray(y.recent_observations)?y.recent_observations:[];return["Claude-Mem Recent Context",`Project: ${g||"(auto)"}`,`Session summaries: ${E.length}`,`Recent observations: ${U.length}`,B(U,Math.min(5,U.length||5))].join(`
13
+ `)}}),e.registerCommand({name:"claude-mem-timeline",description:"Find best memory match and show nearby timeline events",acceptsArgs:!0,handler:async r=>{let n=r.args?.trim()||"";if(!n)return"Usage: /claude-mem-timeline <query> [depthBefore] [depthAfter]";let t=n.split(/\s+/),i=5,l=5;t.length>=2&&/^\d+$/.test(t[t.length-1])&&(i=I(t.pop(),5)),t.length>=2&&/^\d+$/.test(t[t.length-1])&&(l=I(t.pop(),5));let u=t.join(" "),g=new URLSearchParams({query:u,mode:"auto",depth_before:String(l),depth_after:String(i)}),f=await K(o,`/api/timeline/by-query?${g.toString()}`,e.logger);if(!f)return"Claude-Mem timeline lookup failed (worker unavailable or invalid response).";let y=Array.isArray(f.timeline)?f.timeline:[],E=f.anchor?String(f.anchor):"(none)";return[`Claude-Mem Timeline: "${u}"`,`Anchor: ${E}`,B(y,8)].join(`
14
+ `)}}),e.registerCommand({name:"claude_mem_status",description:"Check Claude-Mem worker health and session status",handler:async()=>{let r=await q(o,"/api/health",e.logger);if(!r)return{text:`Claude-Mem worker unreachable at port ${o}`};try{return{text:["Claude-Mem Worker Status",`Status: ${JSON.parse(r).status||"unknown"}`,`Port: ${o}`,`Active sessions: ${w.size}`,`Observation feed: ${O}`].join(`
15
+ `)}}catch{return{text:"Claude-Mem worker responded but returned unexpected data"}}}}),e.logger.info(`[claude-mem] OpenClaw plugin loaded \u2014 v1.0.0 (worker: ${W}:${o})`)}export{ge as default};
@@ -266,12 +266,6 @@ describe("Observation I/O event handlers", () => {
266
266
  return;
267
267
  }
268
268
 
269
- if (req.url === "/api/sessions/complete") {
270
- res.writeHead(200, { "Content-Type": "application/json" });
271
- res.end(JSON.stringify({ status: "completed" }));
272
- return;
273
- }
274
-
275
269
  if (req.url?.startsWith("/api/context/inject")) {
276
270
  res.writeHead(200, { "Content-Type": "text/plain; charset=utf-8" });
277
271
  res.end("# Claude-Mem Context\n\n## Timeline\n- Session 1: Did some work");
@@ -446,8 +440,7 @@ describe("Observation I/O event handlers", () => {
446
440
  assert.ok(summarizeRequest!.body.contentSessionId.startsWith("openclaw-summarize-test-"));
447
441
 
448
442
  const completeRequest = receivedRequests.find((r) => r.url === "/api/sessions/complete");
449
- assert.ok(completeRequest, "should send complete to worker");
450
- assert.ok(completeRequest!.body.contentSessionId.startsWith("openclaw-summarize-test-"));
443
+ assert.ok(!completeRequest, "should not send complete (worker self-completes)");
451
444
  });
452
445
 
453
446
  it("agent_end extracts text from array content", async () => {
@@ -644,12 +644,7 @@ export default function claudeMemPlugin(api: OpenClawPluginApi): void {
644
644
  const sessionIds = new Map<string, string>();
645
645
  const canonicalSessionKeys = new Map<string, string>();
646
646
  const sessionAliasesByCanonicalKey = new Map<string, Set<string>>();
647
- const pendingCompletionTimers = new Map<string, ReturnType<typeof setTimeout>>();
648
647
  const recentPromptInits = new Map<string, number>();
649
- const completionDelayMs = (() => {
650
- const val = Number((userConfig as Record<string, unknown>).completionDelayMs);
651
- return Number.isFinite(val) ? Math.max(0, val) : 5000;
652
- })();
653
648
  const syncMemoryFile = userConfig.syncMemoryFile !== false; // default true
654
649
  const syncMemoryFileExclude = new Set(userConfig.syncMemoryFileExclude || []);
655
650
 
@@ -733,18 +728,6 @@ export default function claudeMemPlugin(api: OpenClawPluginApi): void {
733
728
  sessionIds.delete(canonicalKey);
734
729
  }
735
730
 
736
- function scheduleSessionComplete(contentSessionId: string): void {
737
- const existingTimer = pendingCompletionTimers.get(contentSessionId);
738
- if (existingTimer) clearTimeout(existingTimer);
739
- const timer = setTimeout(() => {
740
- pendingCompletionTimers.delete(contentSessionId);
741
- workerPostFireAndForget(workerPort, "/api/sessions/complete", {
742
- contentSessionId,
743
- }, api.logger);
744
- }, completionDelayMs);
745
- pendingCompletionTimers.set(contentSessionId, timer);
746
- }
747
-
748
731
  // TTL cache for context injection to avoid re-fetching on every LLM turn.
749
732
  // before_prompt_build fires on every turn; caching for 60s keeps the worker
750
733
  // load manageable while still picking up new observations reasonably quickly.
@@ -898,7 +881,7 @@ export default function claudeMemPlugin(api: OpenClawPluginApi): void {
898
881
  });
899
882
 
900
883
  // ------------------------------------------------------------------
901
- // Event: agent_end — summarize and complete session
884
+ // Event: agent_end — summarize session (worker self-completes)
902
885
  // ------------------------------------------------------------------
903
886
  api.on("agent_end", async (event, ctx) => {
904
887
  const { contentSessionId } = rememberSessionContext(ctx);
@@ -922,16 +905,12 @@ export default function claudeMemPlugin(api: OpenClawPluginApi): void {
922
905
  }
923
906
  }
924
907
 
925
- // Await summarize so the worker receives it before complete.
926
- // This also gives in-flight tool_result_persist observations time to arrive
927
- // (they use fire-and-forget and may still be in transit).
908
+ // Send summarize. The worker self-completes the session when its SDK-agent
909
+ // generator drains; no explicit complete call needed.
928
910
  await workerPost(workerPort, "/api/sessions/summarize", {
929
911
  contentSessionId,
930
912
  last_assistant_message: lastAssistantMessage,
931
913
  }, api.logger);
932
-
933
- api.logger.info(`[claude-mem] Scheduling session complete in ${completionDelayMs}ms: ${contentSessionId}`);
934
- scheduleSessionComplete(contentSessionId);
935
914
  });
936
915
 
937
916
  // ------------------------------------------------------------------
@@ -952,10 +931,6 @@ export default function claudeMemPlugin(api: OpenClawPluginApi): void {
952
931
  recentPromptInits.clear();
953
932
  canonicalSessionKeys.clear();
954
933
  sessionAliasesByCanonicalKey.clear();
955
- for (const timer of pendingCompletionTimers.values()) {
956
- clearTimeout(timer);
957
- }
958
- pendingCompletionTimers.clear();
959
934
  api.logger.info("[claude-mem] Gateway started — session tracking reset");
960
935
  });
961
936
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-mem",
3
- "version": "12.4.3",
3
+ "version": "12.4.4",
4
4
  "description": "Memory compression system for Claude Code - persist context across sessions",
5
5
  "keywords": [
6
6
  "claude",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-mem",
3
- "version": "12.4.3",
3
+ "version": "12.4.4",
4
4
  "description": "Persistent memory system for Claude Code - seamlessly preserve context across sessions",
5
5
  "author": {
6
6
  "name": "Alex Newman"
@@ -88,18 +88,6 @@
88
88
  }
89
89
  ]
90
90
  }
91
- ],
92
- "SessionEnd": [
93
- {
94
- "hooks": [
95
- {
96
- "type": "command",
97
- "shell": "bash",
98
- "command": "export PATH=\"$($SHELL -lc 'echo $PATH' 2>/dev/null):$PATH\"; _R=\"${CLAUDE_PLUGIN_ROOT}\"; [ -z \"$_R\" ] && _R=$(ls -dt $HOME/.claude/plugins/cache/thedotmack/claude-mem/[0-9]*/ 2>/dev/null | head -1); _R=\"${_R%/}\"; [ -z \"$_R\" ] && _R=\"$HOME/.claude/plugins/marketplaces/thedotmack/plugin\"; node \"$_R/scripts/bun-runner.js\" \"$_R/scripts/worker-service.cjs\" hook claude-code session-complete",
99
- "timeout": 30
100
- }
101
- ]
102
- }
103
91
  ]
104
92
  }
105
93
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-mem-plugin",
3
- "version": "12.4.3",
3
+ "version": "12.4.4",
4
4
  "private": true,
5
5
  "description": "Runtime dependencies for claude-mem bundled hooks",
6
6
  "type": "module",