claude-mem 12.4.2 → 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.
- package/dist/npx-cli/index.js +1 -1
- package/dist/opencode-plugin/index.js +1 -1
- package/openclaw/dist/index.js +13 -13
- package/openclaw/src/index.test.ts +1 -8
- package/openclaw/src/index.ts +3 -28
- package/package.json +1 -1
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/hooks/hooks.json +0 -12
- package/plugin/package.json +1 -1
- package/plugin/scripts/context-generator.cjs +1 -1
- package/plugin/scripts/mcp-server.cjs +1 -1
- package/plugin/scripts/worker-service.cjs +213 -199
package/dist/npx-cli/index.js
CHANGED
|
@@ -196,7 +196,7 @@ Examples:
|
|
|
196
196
|
claude-mem gemini-cli uninstall # Remove hooks
|
|
197
197
|
|
|
198
198
|
For more info: https://docs.claude-mem.ai/usage/gemini-provider
|
|
199
|
-
`),0}}var Qt,B,ne,dt,Qa,Pe,qr=S(()=>{"use strict";K();ut();Qt=Vr.join(Za(),".gemini"),B=Vr.join(Qt,"settings.json"),ne=Vr.join(Qt,"GEMINI.md"),dt="claude-mem",Qa=1e4,Pe={SessionStart:"context",BeforeAgent:"session-init",AfterAgent:"observation",BeforeTool:"observation",AfterTool:"observation",PreCompress:"summarize",Notification:"observation"
|
|
199
|
+
`),0}}var Qt,B,ne,dt,Qa,Pe,qr=S(()=>{"use strict";K();ut();Qt=Vr.join(Za(),".gemini"),B=Vr.join(Qt,"settings.json"),ne=Vr.join(Qt,"GEMINI.md"),dt="claude-mem",Qa=1e4,Pe={SessionStart:"context",BeforeAgent:"session-init",AfterAgent:"observation",BeforeTool:"observation",AfterTool:"observation",PreCompress:"summarize",Notification:"observation"}});import ac from"path";import{existsSync as cc,readFileSync as lc,writeFileSync as zr,mkdirSync as uc}from"fs";function er(e,t,r){let n=ac.dirname(e);uc(n,{recursive:!0});let s=`${pt}
|
|
200
200
|
${t}
|
|
201
201
|
${Fe}`;if(cc(e)){let o=lc(e,"utf-8"),i=o.indexOf(pt),a=o.indexOf(Fe);i!==-1&&a!==-1?o=o.slice(0,i)+s+o.slice(a+Fe.length):o=o.trimEnd()+`
|
|
202
202
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var d="http://127.0.0.1:37777";var g={"Content-Type":"application/json"};function l(
|
|
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};
|
package/openclaw/dist/index.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
var
|
|
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
|
|
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
|
-
`);
|
|
6
|
-
`).filter(S=>S.startsWith("data:")).map(S=>S.slice(5).trim());if(
|
|
7
|
-
`);if(
|
|
8
|
-
`));let
|
|
9
|
-
`));break}}await
|
|
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: ${
|
|
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,
|
|
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,
|
|
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(" "),
|
|
14
|
-
`)}}),e.registerCommand({name:"claude_mem_status",description:"Check Claude-Mem worker health and session status",handler:async()=>{let r=await
|
|
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: ${
|
|
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
|
|
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 () => {
|
package/openclaw/src/index.ts
CHANGED
|
@@ -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
|
|
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
|
-
//
|
|
926
|
-
//
|
|
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
package/plugin/hooks/hooks.json
CHANGED
|
@@ -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
|
}
|
package/plugin/package.json
CHANGED
|
@@ -671,7 +671,7 @@ ${o.stack}`:` ${o.message}`:this.getLevel()===0&&typeof o=="object"?u=`
|
|
|
671
671
|
content_session_id, prompt_number, prompt_text,
|
|
672
672
|
created_at, created_at_epoch
|
|
673
673
|
) VALUES (?, ?, ?, ?, ?)
|
|
674
|
-
`).run(e.content_session_id,e.prompt_number,e.prompt_text,e.created_at,e.created_at_epoch).lastInsertRowid}}};var Ue=L(require("path"),1),xe=require("os");var C=require("fs"),x=require("path"),oe=require("os"),W=class{static DEFAULTS={CLAUDE_MEM_MODEL:"claude-sonnet-4-6",CLAUDE_MEM_CONTEXT_OBSERVATIONS:"50",CLAUDE_MEM_WORKER_PORT:String(37700+(process.getuid?.()??77)%100),CLAUDE_MEM_WORKER_HOST:"127.0.0.1",CLAUDE_MEM_SKIP_TOOLS:"ListMcpResourcesTool,SlashCommand,Skill,TodoWrite,AskUserQuestion",CLAUDE_MEM_PROVIDER:"claude",CLAUDE_MEM_CLAUDE_AUTH_METHOD:"cli",CLAUDE_MEM_GEMINI_API_KEY:"",CLAUDE_MEM_GEMINI_MODEL:"gemini-2.5-flash-lite",CLAUDE_MEM_GEMINI_RATE_LIMITING_ENABLED:"true",CLAUDE_MEM_GEMINI_MAX_CONTEXT_MESSAGES:"20",CLAUDE_MEM_GEMINI_MAX_TOKENS:"100000",CLAUDE_MEM_OPENROUTER_API_KEY:"",CLAUDE_MEM_OPENROUTER_MODEL:"xiaomi/mimo-v2-flash:free",CLAUDE_MEM_OPENROUTER_SITE_URL:"",CLAUDE_MEM_OPENROUTER_APP_NAME:"claude-mem",CLAUDE_MEM_OPENROUTER_MAX_CONTEXT_MESSAGES:"20",CLAUDE_MEM_OPENROUTER_MAX_TOKENS:"100000",CLAUDE_MEM_DATA_DIR:(0,x.join)((0,oe.homedir)(),".claude-mem"),CLAUDE_MEM_LOG_LEVEL:"INFO",CLAUDE_MEM_PYTHON_VERSION:"3.13",CLAUDE_CODE_PATH:"",CLAUDE_MEM_MODE:"code",CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS:"false",CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS:"false",CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT:"false",CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT:"true",CLAUDE_MEM_CONTEXT_FULL_COUNT:"0",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",CLAUDE_MEM_CONTEXT_SHOW_TERMINAL_OUTPUT:"true",CLAUDE_MEM_FOLDER_CLAUDEMD_ENABLED:"false",CLAUDE_MEM_FOLDER_USE_LOCAL_MD:"false",CLAUDE_MEM_TRANSCRIPTS_ENABLED:"true",CLAUDE_MEM_TRANSCRIPTS_CONFIG_PATH:(0,x.join)((0,oe.homedir)(),".claude-mem","transcript-watch.json"),CLAUDE_MEM_MAX_CONCURRENT_AGENTS:"2",CLAUDE_MEM_HOOK_FAIL_LOUD_THRESHOLD:"3",CLAUDE_MEM_EXCLUDED_PROJECTS:"",CLAUDE_MEM_FOLDER_MD_EXCLUDE:"[]",CLAUDE_MEM_SEMANTIC_INJECT:"false",CLAUDE_MEM_SEMANTIC_INJECT_LIMIT:"5",CLAUDE_MEM_TIER_ROUTING_ENABLED:"true",CLAUDE_MEM_TIER_SIMPLE_MODEL:"haiku",CLAUDE_MEM_TIER_SUMMARY_MODEL:"",CLAUDE_MEM_CHROMA_ENABLED:"true",CLAUDE_MEM_CHROMA_MODE:"local",CLAUDE_MEM_CHROMA_HOST:"127.0.0.1",CLAUDE_MEM_CHROMA_PORT:"8000",CLAUDE_MEM_CHROMA_SSL:"false",CLAUDE_MEM_CHROMA_API_KEY:"",CLAUDE_MEM_CHROMA_TENANT:"default_tenant",CLAUDE_MEM_CHROMA_DATABASE:"default_database",CLAUDE_MEM_TELEGRAM_ENABLED:"true",CLAUDE_MEM_TELEGRAM_BOT_TOKEN:"",CLAUDE_MEM_TELEGRAM_CHAT_ID:"",CLAUDE_MEM_TELEGRAM_TRIGGER_TYPES:"security_alert",CLAUDE_MEM_TELEGRAM_TRIGGER_CONCEPTS:""};static getAllDefaults(){return{...this.DEFAULTS}}static get(e){return process.env[e]??this.DEFAULTS[e]}static getInt(e){let t=this.get(e);return parseInt(t,10)}static getBool(e){let t=this.get(e);return t==="true"||t===!0}static applyEnvOverrides(e){let t={...e};for(let s of Object.keys(this.DEFAULTS))process.env[s]!==void 0&&(t[s]=process.env[s]);return t}static loadFromFile(e){try{if(!(0,C.existsSync)(e)){let i=this.getAllDefaults();try{let a=(0,x.dirname)(e);(0,C.existsSync)(a)||(0,C.mkdirSync)(a,{recursive:!0}),(0,C.writeFileSync)(e,JSON.stringify(i,null,2),"utf-8"),console.log("[SETTINGS] Created settings file with defaults:",e)}catch(a){console.warn("[SETTINGS] Failed to create settings file, using in-memory defaults:",e,a instanceof Error?a.message:String(a))}return this.applyEnvOverrides(i)}let t=(0,C.readFileSync)(e,"utf-8"),s=JSON.parse(t),n=s;if(s.env&&typeof s.env=="object"){n=s.env;try{(0,C.writeFileSync)(e,JSON.stringify(n,null,2),"utf-8"),console.log("[SETTINGS] Migrated settings file from nested to flat schema:",e)}catch(i){console.warn("[SETTINGS] Failed to auto-migrate settings file:",e,i instanceof Error?i.message:String(i))}}let o={...this.DEFAULTS};for(let i of Object.keys(this.DEFAULTS))n[i]!==void 0&&(o[i]=n[i]);return this.applyEnvOverrides(o)}catch(t){return console.warn("[SETTINGS] Failed to load settings, using defaults:",e,t instanceof Error?t.message:String(t)),this.applyEnvOverrides(this.getAllDefaults())}}};var k=require("fs"),q=require("path");var A=class r{static instance=null;activeMode=null;modesDir;constructor(){let e=Ce(),t=[(0,q.join)(e,"modes"),(0,q.join)(e,"..","plugin","modes")],s=t.find(n=>(0,k.existsSync)(n));this.modesDir=s||t[0]}static getInstance(){return r.instance||(r.instance=new r),r.instance}parseInheritance(e){let t=e.split("--");if(t.length===1)return{hasParent:!1,parentId:"",overrideId:""};if(t.length>2)throw new Error(`Invalid mode inheritance: ${e}. Only one level of inheritance supported (parent--override)`);return{hasParent:!0,parentId:t[0],overrideId:e}}isPlainObject(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}deepMerge(e,t){let s={...e};for(let n in t){let o=t[n],i=e[n];this.isPlainObject(o)&&this.isPlainObject(i)?s[n]=this.deepMerge(i,o):s[n]=o}return s}loadModeFile(e){let t=(0,q.join)(this.modesDir,`${e}.json`);if(!(0,k.existsSync)(t))throw new Error(`Mode file not found: ${t}`);let s=(0,k.readFileSync)(t,"utf-8");return JSON.parse(s)}loadMode(e){let t=this.parseInheritance(e);if(!t.hasParent)try{let d=this.loadModeFile(e);return this.activeMode=d,c.debug("SYSTEM",`Loaded mode: ${d.name} (${e})`,void 0,{types:d.observation_types.map(m=>m.id),concepts:d.observation_concepts.map(m=>m.id)}),d}catch(d){if(d instanceof Error?c.warn("WORKER",`Mode file not found: ${e}, falling back to 'code'`,{message:d.message}):c.warn("WORKER",`Mode file not found: ${e}, falling back to 'code'`,{error:String(d)}),e==="code")throw new Error("Critical: code.json mode file missing");return this.loadMode("code")}let{parentId:s,overrideId:n}=t,o;try{o=this.loadMode(s)}catch(d){d instanceof Error?c.warn("WORKER",`Parent mode '${s}' not found for ${e}, falling back to 'code'`,{message:d.message}):c.warn("WORKER",`Parent mode '${s}' not found for ${e}, falling back to 'code'`,{error:String(d)}),o=this.loadMode("code")}let i;try{i=this.loadModeFile(n),c.debug("SYSTEM",`Loaded override file: ${n} for parent ${s}`)}catch(d){return d instanceof Error?c.warn("WORKER",`Override file '${n}' not found, using parent mode '${s}' only`,{message:d.message}):c.warn("WORKER",`Override file '${n}' not found, using parent mode '${s}' only`,{error:String(d)}),this.activeMode=o,o}if(!i)return c.warn("SYSTEM",`Invalid override file: ${n}, using parent mode '${s}' only`),this.activeMode=o,o;let a=this.deepMerge(o,i);return this.activeMode=a,c.debug("SYSTEM",`Loaded mode with inheritance: ${a.name} (${e} = ${s} + ${n})`,void 0,{parent:s,override:n,types:a.observation_types.map(d=>d.id),concepts:a.observation_concepts.map(d=>d.id)}),a}getActiveMode(){if(!this.activeMode)throw new Error("No mode loaded. Call loadMode() first.");return this.activeMode}getObservationTypes(){return this.getActiveMode().observation_types}getObservationConcepts(){return this.getActiveMode().observation_concepts}getTypeIcon(e){return this.getObservationTypes().find(s=>s.id===e)?.emoji||"\u{1F4DD}"}getWorkEmoji(e){return this.getObservationTypes().find(s=>s.id===e)?.work_emoji||"\u{1F4DD}"}validateType(e){return this.getObservationTypes().some(t=>t.id===e)}getTypeLabel(e){return this.getObservationTypes().find(s=>s.id===e)?.label||e}};function ie(){let r=Ue.default.join((0,xe.homedir)(),".claude-mem","settings.json"),e=W.loadFromFile(r),t=A.getInstance().getActiveMode(),s=new Set(t.observation_types.map(o=>o.id)),n=new Set(t.observation_concepts.map(o=>o.id));return{totalObservationCount:parseInt(e.CLAUDE_MEM_CONTEXT_OBSERVATIONS,10),fullObservationCount:parseInt(e.CLAUDE_MEM_CONTEXT_FULL_COUNT,10),sessionCount:parseInt(e.CLAUDE_MEM_CONTEXT_SESSION_COUNT,10),showReadTokens:e.CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS==="true",showWorkTokens:e.CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS==="true",showSavingsAmount:e.CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT==="true",showSavingsPercent:e.CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT==="true",observationTypes:s,observationConcepts:n,fullObservationField:e.CLAUDE_MEM_CONTEXT_FULL_FIELD,showLastSummary:e.CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY==="true",showLastMessage:e.CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE==="true"}}var _={reset:"\x1B[0m",bright:"\x1B[1m",dim:"\x1B[2m",cyan:"\x1B[36m",green:"\x1B[32m",yellow:"\x1B[33m",blue:"\x1B[34m",magenta:"\x1B[35m",gray:"\x1B[90m",red:"\x1B[31m"},ke=4,ae=1;function de(r){let e=(r.title?.length||0)+(r.subtitle?.length||0)+(r.narrative?.length||0)+JSON.stringify(r.facts||[]).length;return Math.ceil(e/ke)}function _e(r){let e=r.length,t=r.reduce((i,a)=>i+de(a),0),s=r.reduce((i,a)=>i+(a.discovery_tokens||0),0),n=s-t,o=s>0?Math.round(n/s*100):0;return{totalObservations:e,totalReadTokens:t,totalDiscoveryTokens:s,savings:n,savingsPercent:o}}function Bt(r){return A.getInstance().getWorkEmoji(r)}function w(r,e){let t=de(r),s=r.discovery_tokens||0,n=Bt(r.type),o=s>0?`${n} ${s.toLocaleString()}`:"-";return{readTokens:t,discoveryTokens:s,discoveryDisplay:o,workEmoji:n}}function Y(r){return r.showReadTokens||r.showWorkTokens||r.showSavingsAmount||r.showSavingsPercent}var Fe=L(require("path"),1),V=require("fs");var Wt=["private","claude-mem-context","system_instruction","system-instruction","persisted-output","system-reminder"],Ks=new RegExp(`<(${Wt.join("|")})\\b[^>]*>[\\s\\S]*?</\\1>`,"g"),we=/<system-reminder>[\s\S]*?<\/system-reminder>/g;var qt=["task-notification"],Js=new RegExp(`^\\s*<(${qt.join("|")})\\b[^>]*>[\\s\\S]*</\\1>\\s*$`);function ue(r,e,t){let s=Array.from(t.observationTypes),n=s.map(()=>"?").join(","),o=Array.from(t.observationConcepts),i=o.map(()=>"?").join(",");return r.db.prepare(`
|
|
674
|
+
`).run(e.content_session_id,e.prompt_number,e.prompt_text,e.created_at,e.created_at_epoch).lastInsertRowid}}};var Ue=L(require("path"),1),xe=require("os");var C=require("fs"),x=require("path"),oe=require("os"),W=class{static DEFAULTS={CLAUDE_MEM_MODEL:"claude-sonnet-4-6",CLAUDE_MEM_CONTEXT_OBSERVATIONS:"50",CLAUDE_MEM_WORKER_PORT:String(37700+(process.getuid?.()??77)%100),CLAUDE_MEM_WORKER_HOST:"127.0.0.1",CLAUDE_MEM_SKIP_TOOLS:"ListMcpResourcesTool,SlashCommand,Skill,TodoWrite,AskUserQuestion",CLAUDE_MEM_PROVIDER:"claude",CLAUDE_MEM_CLAUDE_AUTH_METHOD:"cli",CLAUDE_MEM_GEMINI_API_KEY:"",CLAUDE_MEM_GEMINI_MODEL:"gemini-2.5-flash-lite",CLAUDE_MEM_GEMINI_RATE_LIMITING_ENABLED:"true",CLAUDE_MEM_GEMINI_MAX_CONTEXT_MESSAGES:"20",CLAUDE_MEM_GEMINI_MAX_TOKENS:"100000",CLAUDE_MEM_OPENROUTER_API_KEY:"",CLAUDE_MEM_OPENROUTER_MODEL:"xiaomi/mimo-v2-flash:free",CLAUDE_MEM_OPENROUTER_SITE_URL:"",CLAUDE_MEM_OPENROUTER_APP_NAME:"claude-mem",CLAUDE_MEM_OPENROUTER_MAX_CONTEXT_MESSAGES:"20",CLAUDE_MEM_OPENROUTER_MAX_TOKENS:"100000",CLAUDE_MEM_DATA_DIR:(0,x.join)((0,oe.homedir)(),".claude-mem"),CLAUDE_MEM_LOG_LEVEL:"INFO",CLAUDE_MEM_PYTHON_VERSION:"3.13",CLAUDE_CODE_PATH:"",CLAUDE_MEM_MODE:"code",CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS:"false",CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS:"false",CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT:"false",CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT:"true",CLAUDE_MEM_CONTEXT_FULL_COUNT:"0",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",CLAUDE_MEM_CONTEXT_SHOW_TERMINAL_OUTPUT:"true",CLAUDE_MEM_FOLDER_CLAUDEMD_ENABLED:"false",CLAUDE_MEM_FOLDER_USE_LOCAL_MD:"false",CLAUDE_MEM_TRANSCRIPTS_ENABLED:"true",CLAUDE_MEM_TRANSCRIPTS_CONFIG_PATH:(0,x.join)((0,oe.homedir)(),".claude-mem","transcript-watch.json"),CLAUDE_MEM_MAX_CONCURRENT_AGENTS:"2",CLAUDE_MEM_HOOK_FAIL_LOUD_THRESHOLD:"3",CLAUDE_MEM_EXCLUDED_PROJECTS:"",CLAUDE_MEM_FOLDER_MD_EXCLUDE:"[]",CLAUDE_MEM_SEMANTIC_INJECT:"false",CLAUDE_MEM_SEMANTIC_INJECT_LIMIT:"5",CLAUDE_MEM_TIER_ROUTING_ENABLED:"true",CLAUDE_MEM_TIER_SIMPLE_MODEL:"haiku",CLAUDE_MEM_TIER_SUMMARY_MODEL:"",CLAUDE_MEM_CHROMA_ENABLED:"true",CLAUDE_MEM_CHROMA_MODE:"local",CLAUDE_MEM_CHROMA_HOST:"127.0.0.1",CLAUDE_MEM_CHROMA_PORT:"8000",CLAUDE_MEM_CHROMA_SSL:"false",CLAUDE_MEM_CHROMA_API_KEY:"",CLAUDE_MEM_CHROMA_TENANT:"default_tenant",CLAUDE_MEM_CHROMA_DATABASE:"default_database",CLAUDE_MEM_TELEGRAM_ENABLED:"true",CLAUDE_MEM_TELEGRAM_BOT_TOKEN:"",CLAUDE_MEM_TELEGRAM_CHAT_ID:"",CLAUDE_MEM_TELEGRAM_TRIGGER_TYPES:"security_alert",CLAUDE_MEM_TELEGRAM_TRIGGER_CONCEPTS:""};static getAllDefaults(){return{...this.DEFAULTS}}static get(e){return process.env[e]??this.DEFAULTS[e]}static getInt(e){let t=this.get(e);return parseInt(t,10)}static getBool(e){let t=this.get(e);return t==="true"||t===!0}static applyEnvOverrides(e){let t={...e};for(let s of Object.keys(this.DEFAULTS))process.env[s]!==void 0&&(t[s]=process.env[s]);return t}static loadFromFile(e){try{if(!(0,C.existsSync)(e)){let i=this.getAllDefaults();try{let a=(0,x.dirname)(e);(0,C.existsSync)(a)||(0,C.mkdirSync)(a,{recursive:!0}),(0,C.writeFileSync)(e,JSON.stringify(i,null,2),"utf-8"),console.log("[SETTINGS] Created settings file with defaults:",e)}catch(a){console.warn("[SETTINGS] Failed to create settings file, using in-memory defaults:",e,a instanceof Error?a.message:String(a))}return this.applyEnvOverrides(i)}let t=(0,C.readFileSync)(e,"utf-8"),s=JSON.parse(t),n=s;if(s.env&&typeof s.env=="object"){n=s.env;try{(0,C.writeFileSync)(e,JSON.stringify(n,null,2),"utf-8"),console.log("[SETTINGS] Migrated settings file from nested to flat schema:",e)}catch(i){console.warn("[SETTINGS] Failed to auto-migrate settings file:",e,i instanceof Error?i.message:String(i))}}let o={...this.DEFAULTS};for(let i of Object.keys(this.DEFAULTS))n[i]!==void 0&&(o[i]=n[i]);return this.applyEnvOverrides(o)}catch(t){return console.warn("[SETTINGS] Failed to load settings, using defaults:",e,t instanceof Error?t.message:String(t)),this.applyEnvOverrides(this.getAllDefaults())}}};var k=require("fs"),q=require("path");var A=class r{static instance=null;activeMode=null;modesDir;constructor(){let e=Ce(),t=[(0,q.join)(e,"modes"),(0,q.join)(e,"..","plugin","modes")],s=t.find(n=>(0,k.existsSync)(n));this.modesDir=s||t[0]}static getInstance(){return r.instance||(r.instance=new r),r.instance}parseInheritance(e){let t=e.split("--");if(t.length===1)return{hasParent:!1,parentId:"",overrideId:""};if(t.length>2)throw new Error(`Invalid mode inheritance: ${e}. Only one level of inheritance supported (parent--override)`);return{hasParent:!0,parentId:t[0],overrideId:e}}isPlainObject(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}deepMerge(e,t){let s={...e};for(let n in t){let o=t[n],i=e[n];this.isPlainObject(o)&&this.isPlainObject(i)?s[n]=this.deepMerge(i,o):s[n]=o}return s}loadModeFile(e){let t=(0,q.join)(this.modesDir,`${e}.json`);if(!(0,k.existsSync)(t))throw new Error(`Mode file not found: ${t}`);let s=(0,k.readFileSync)(t,"utf-8");return JSON.parse(s)}loadMode(e){let t=this.parseInheritance(e);if(!t.hasParent)try{let d=this.loadModeFile(e);return this.activeMode=d,c.debug("SYSTEM",`Loaded mode: ${d.name} (${e})`,void 0,{types:d.observation_types.map(m=>m.id),concepts:d.observation_concepts.map(m=>m.id)}),d}catch(d){if(d instanceof Error?c.warn("WORKER",`Mode file not found: ${e}, falling back to 'code'`,{message:d.message}):c.warn("WORKER",`Mode file not found: ${e}, falling back to 'code'`,{error:String(d)}),e==="code")throw new Error("Critical: code.json mode file missing");return this.loadMode("code")}let{parentId:s,overrideId:n}=t,o;try{o=this.loadMode(s)}catch(d){d instanceof Error?c.warn("WORKER",`Parent mode '${s}' not found for ${e}, falling back to 'code'`,{message:d.message}):c.warn("WORKER",`Parent mode '${s}' not found for ${e}, falling back to 'code'`,{error:String(d)}),o=this.loadMode("code")}let i;try{i=this.loadModeFile(n),c.debug("SYSTEM",`Loaded override file: ${n} for parent ${s}`)}catch(d){return d instanceof Error?c.warn("WORKER",`Override file '${n}' not found, using parent mode '${s}' only`,{message:d.message}):c.warn("WORKER",`Override file '${n}' not found, using parent mode '${s}' only`,{error:String(d)}),this.activeMode=o,o}if(!i)return c.warn("SYSTEM",`Invalid override file: ${n}, using parent mode '${s}' only`),this.activeMode=o,o;let a=this.deepMerge(o,i);return this.activeMode=a,c.debug("SYSTEM",`Loaded mode with inheritance: ${a.name} (${e} = ${s} + ${n})`,void 0,{parent:s,override:n,types:a.observation_types.map(d=>d.id),concepts:a.observation_concepts.map(d=>d.id)}),a}getActiveMode(){if(!this.activeMode)throw new Error("No mode loaded. Call loadMode() first.");return this.activeMode}getObservationTypes(){return this.getActiveMode().observation_types}getObservationConcepts(){return this.getActiveMode().observation_concepts}getTypeIcon(e){return this.getObservationTypes().find(s=>s.id===e)?.emoji||"\u{1F4DD}"}getWorkEmoji(e){return this.getObservationTypes().find(s=>s.id===e)?.work_emoji||"\u{1F4DD}"}validateType(e){return this.getObservationTypes().some(t=>t.id===e)}getTypeLabel(e){return this.getObservationTypes().find(s=>s.id===e)?.label||e}};function ie(){let r=Ue.default.join((0,xe.homedir)(),".claude-mem","settings.json"),e=W.loadFromFile(r),t=A.getInstance().getActiveMode(),s=new Set(t.observation_types.map(o=>o.id)),n=new Set(t.observation_concepts.map(o=>o.id));return{totalObservationCount:parseInt(e.CLAUDE_MEM_CONTEXT_OBSERVATIONS,10),fullObservationCount:parseInt(e.CLAUDE_MEM_CONTEXT_FULL_COUNT,10),sessionCount:parseInt(e.CLAUDE_MEM_CONTEXT_SESSION_COUNT,10),showReadTokens:e.CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS==="true",showWorkTokens:e.CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS==="true",showSavingsAmount:e.CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT==="true",showSavingsPercent:e.CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT==="true",observationTypes:s,observationConcepts:n,fullObservationField:e.CLAUDE_MEM_CONTEXT_FULL_FIELD,showLastSummary:e.CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY==="true",showLastMessage:e.CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE==="true"}}var _={reset:"\x1B[0m",bright:"\x1B[1m",dim:"\x1B[2m",cyan:"\x1B[36m",green:"\x1B[32m",yellow:"\x1B[33m",blue:"\x1B[34m",magenta:"\x1B[35m",gray:"\x1B[90m",red:"\x1B[31m"},ke=4,ae=1;function de(r){let e=(r.title?.length||0)+(r.subtitle?.length||0)+(r.narrative?.length||0)+JSON.stringify(r.facts||[]).length;return Math.ceil(e/ke)}function _e(r){let e=r.length,t=r.reduce((i,a)=>i+de(a),0),s=r.reduce((i,a)=>i+(a.discovery_tokens||0),0),n=s-t,o=s>0?Math.round(n/s*100):0;return{totalObservations:e,totalReadTokens:t,totalDiscoveryTokens:s,savings:n,savingsPercent:o}}function Bt(r){return A.getInstance().getWorkEmoji(r)}function w(r,e){let t=de(r),s=r.discovery_tokens||0,n=Bt(r.type),o=s>0?`${n} ${s.toLocaleString()}`:"-";return{readTokens:t,discoveryTokens:s,discoveryDisplay:o,workEmoji:n}}function Y(r){return r.showReadTokens||r.showWorkTokens||r.showSavingsAmount||r.showSavingsPercent}var Fe=L(require("path"),1),V=require("fs");var Wt=["private","claude-mem-context","system_instruction","system-instruction","persisted-output","system-reminder"],Ks=new RegExp(`<(${Wt.join("|")})\\b[^>]*>[\\s\\S]*?</\\1>`,"g"),we=/<system-reminder>[\s\S]*?<\/system-reminder>/g;var qt=["task-notification"],Js=new RegExp(`^\\s*<(${qt.join("|")})\\b[^>]*>(?:(?!<\\1\\b|</\\1\\b)[\\s\\S])*</\\1>\\s*$`),Qs=256*1024;function ue(r,e,t){let s=Array.from(t.observationTypes),n=s.map(()=>"?").join(","),o=Array.from(t.observationConcepts),i=o.map(()=>"?").join(",");return r.db.prepare(`
|
|
675
675
|
SELECT
|
|
676
676
|
o.id,
|
|
677
677
|
o.memory_session_id,
|
|
@@ -187,7 +187,7 @@ ${f}`}let s=i.lineStart;for(let u=i.lineStart-1;u>=0;u--){let l=a[u].trim();if(l
|
|
|
187
187
|
${c}`}var $b=new Set([".js",".jsx",".ts",".tsx",".mjs",".cjs",".py",".pyw",".go",".rs",".rb",".java",".cs",".cpp",".cc",".cxx",".c",".h",".hpp",".hh",".swift",".kt",".kts",".php",".vue",".svelte",".ex",".exs",".lua",".scala",".sc",".sh",".bash",".zsh",".hs",".zig",".css",".scss",".toml",".yml",".yaml",".sql",".md",".mdx"]),uD=new Set(["node_modules",".git","dist","build",".next","__pycache__",".venv","venv","env",".env","target","vendor",".cache",".turbo","coverage",".nyc_output",".claude",".smart-file-read"]),lD=512*1024;async function*bb(t,e,r=20,n){if(r<=0)return;let o;try{o=await(0,Zn.readdir)(t,{withFileTypes:!0})}catch(i){_.debug("WORKER",`walkDir: failed to read directory ${t}`,void 0,i instanceof Error?i:void 0);return}for(let i of o){if(i.name.startsWith(".")&&i.name!=="."||uD.has(i.name))continue;let a=(0,Ai.join)(t,i.name);if(i.isDirectory())yield*bb(a,e,r-1,n);else if(i.isFile()){let s=i.name.slice(i.name.lastIndexOf("."));($b.has(s)||n&&n.has(s))&&(yield a)}}}async function dD(t){try{let e=await(0,Zn.stat)(t);if(e.size>lD||e.size===0)return null;let r=await(0,Zn.readFile)(t,"utf-8");return r.slice(0,1e3).includes("\0")?null:r}catch(e){return _.debug("WORKER",`safeReadFile: failed to read ${t}`,void 0,e instanceof Error?e:void 0),null}}async function Sb(t,e,r={}){let n=r.maxResults||20,o=e.toLowerCase(),i=o.split(/[\s_\-./]+/).filter(x=>x.length>0),a=r.projectRoot||t,s=Ni(a),c=new Set;for(let x of Object.values(s.grammars))for(let S of x.extensions)$b.has(S)||c.add(S);let u=[];for await(let x of bb(t,t,20,c.size>0?c:void 0)){if(r.filePattern&&!(0,Ai.relative)(t,x).toLowerCase().includes(r.filePattern.toLowerCase()))continue;let S=await dD(x);S&&u.push({absolutePath:x,relativePath:(0,Ai.relative)(t,x),content:S})}let l=vb(u,a),d=[],p=[],f=0;for(let[x,S]of l){f+=pD(S);let z=nc(x.toLowerCase(),i)>0,Ve=[],We=(qn,qr)=>{for(let ye of qn){let rr=0,mt="",Vn=nc(ye.name.toLowerCase(),i);Vn>0&&(rr+=Vn*3,mt="name match"),ye.signature.toLowerCase().includes(o)&&(rr+=2,mt=mt?`${mt} + signature`:"signature match"),ye.jsdoc&&ye.jsdoc.toLowerCase().includes(o)&&(rr+=1,mt=mt?`${mt} + jsdoc`:"jsdoc match"),rr>0&&(z=!0,Ve.push({filePath:x,symbolName:qr?`${qr}.${ye.name}`:ye.name,kind:ye.kind,signature:ye.signature,jsdoc:ye.jsdoc,lineStart:ye.lineStart,lineEnd:ye.lineEnd,matchReason:mt})),ye.children&&We(ye.children,ye.name)}};We(S.symbols),z&&(d.push(S),p.push(...Ve))}p.sort((x,S)=>{let j=nc(x.symbolName.toLowerCase(),i);return nc(S.symbolName.toLowerCase(),i)-j});let h=p.slice(0,n),g=new Set(h.map(x=>x.filePath)),$=d.filter(x=>g.has(x.filePath)).slice(0,n),k=$.reduce((x,S)=>x+S.foldedTokenEstimate,0);return{foldedFiles:$,matchingSymbols:h,totalFilesScanned:u.length,totalSymbolsFound:f,tokenEstimate:k}}function nc(t,e){let r=0;for(let n of e)if(t===n)r+=10;else if(t.includes(n))r+=5;else{let o=0,i=0;for(let a of n){let s=t.indexOf(a,o);s!==-1&&(i++,o=s+1)}i===n.length&&(r+=1)}return r}function pD(t){let e=t.symbols.length;for(let r of t.symbols)r.children&&(e+=r.children.length);return e}function xb(t,e){let r=[];if(r.push(`\u{1F50D} Smart Search: "${e}"`),r.push(` Scanned ${t.totalFilesScanned} files, found ${t.totalSymbolsFound} symbols`),r.push(` ${t.matchingSymbols.length} matches across ${t.foldedFiles.length} files (~${t.tokenEstimate} tokens for folded view)`),r.push(""),t.matchingSymbols.length===0)return r.push(" No matching symbols found."),r.join(`
|
|
188
188
|
`);r.push("\u2500\u2500 Matching Symbols \u2500\u2500"),r.push("");for(let n of t.matchingSymbols){if(r.push(` ${n.kind} ${n.symbolName} (${n.filePath}:${n.lineStart+1})`),r.push(` ${n.signature}`),n.jsdoc){let o=n.jsdoc.split(`
|
|
189
189
|
`).find(i=>i.replace(/^[\s*/]+/,"").trim().length>0);o&&r.push(` \u{1F4AC} ${o.replace(/^[\s*/]+/,"").trim()}`)}r.push("")}r.push("\u2500\u2500 Folded File Views \u2500\u2500"),r.push("");for(let n of t.foldedFiles)r.push(Ln(n)),r.push("");return r.push("\u2500\u2500 Actions \u2500\u2500"),r.push(" To see full implementation: use smart_unfold with file path and symbol name"),r.join(`
|
|
190
|
-
`)}var ym=require("node:fs/promises"),Eb=require("node:fs"),Fr=require("node:path"),Ib=require("node:url"),xD={},fD="12.4.
|
|
190
|
+
`)}var ym=require("node:fs/promises"),Eb=require("node:fs"),Fr=require("node:path"),Ib=require("node:url"),xD={},fD="12.4.4";console.log=(...t)=>{_.error("CONSOLE","Intercepted console output (MCP protocol protection)",void 0,{args:t})};var Pb=!1,Tb=(()=>{if(typeof __dirname<"u")return __dirname;try{return(0,Fr.dirname)((0,Ib.fileURLToPath)(xD.url))}catch{return Pb=!0,process.cwd()}})(),$m=(0,Fr.resolve)(Tb,"worker-service.cjs");function mD(){Pb&&((0,Eb.existsSync)($m)||_.error("SYSTEM","mcp-server: dirname resolution failed (both __dirname and import.meta.url are unavailable). Fell back to process.cwd() and the resolved WORKER_SCRIPT_PATH does not exist. This is the actual problem \u2014 the worker bundle is fine, but mcp-server cannot locate it. Worker auto-start will fail until the dirname-resolution path is fixed.",{workerScriptPath:$m,mcpServerDir:Tb}))}var kb={search:"/api/search",timeline:"/api/timeline"};async function _m(t,e){_.debug("SYSTEM","\u2192 Worker API",void 0,{endpoint:t,params:e});let r=new URLSearchParams;for(let[o,i]of Object.entries(e))i!=null&&r.append(o,String(i));let n=`${t}?${r}`;try{let o=await ec(n);if(!o.ok){let a=await o.text();throw new Error(`Worker API error (${o.status}): ${a}`)}let i=await o.json();return _.debug("SYSTEM","\u2190 Worker API success",void 0,{endpoint:t}),i}catch(o){return _.error("SYSTEM","\u2190 Worker API error",{endpoint:t},o instanceof Error?o:new Error(String(o))),{content:[{type:"text",text:`Error calling Worker API: ${o instanceof Error?o.message:String(o)}`}],isError:!0}}}async function hD(t,e){let r=await ec(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!r.ok){let o=await r.text();throw new Error(`Worker API error (${r.status}): ${o}`)}let n=await r.json();return _.debug("HTTP","Worker API success (POST)",void 0,{endpoint:t}),{content:[{type:"text",text:JSON.stringify(n,null,2)}]}}async function Fn(t,e){_.debug("HTTP","Worker API request (POST)",void 0,{endpoint:t});try{return await hD(t,e)}catch(r){return _.error("HTTP","Worker API error (POST)",{endpoint:t},r instanceof Error?r:new Error(String(r))),{content:[{type:"text",text:`Error calling Worker API: ${r instanceof Error?r.message:String(r)}`}],isError:!0}}}async function gD(){try{return(await ec("/api/health")).ok}catch(t){return _.debug("SYSTEM","Worker health check failed",{},t instanceof Error?t:new Error(String(t))),!1}}async function vD(){if(await gD())return!0;_.warn("SYSTEM","Worker not available, attempting auto-start for MCP client"),mD();try{let t=am(),e=await ib(t,$m);return e||_.error("SYSTEM","Worker auto-start returned false \u2014 MCP tools that require the worker (search, timeline, get_observations) will fail until the worker is running. Check earlier log lines for the specific failure reason (Bun not found, missing worker bundle, port conflict, etc.)."),e}catch(t){return _.error("SYSTEM","Worker auto-start threw \u2014 MCP tools that require the worker (search, timeline, get_observations) will fail until the worker is running.",void 0,t instanceof Error?t:new Error(String(t))),!1}}var zb=[{name:"__IMPORTANT",description:`3-LAYER WORKFLOW (ALWAYS FOLLOW):
|
|
191
191
|
1. search(query) \u2192 Get index with IDs (~50-100 tokens/result)
|
|
192
192
|
2. timeline(anchor=ID) \u2192 Get context around interesting results
|
|
193
193
|
3. get_observations([IDs]) \u2192 Fetch full details ONLY for filtered IDs
|