chore: bump version to 7.0.2

Auto-start worker functionality improvements

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Alex Newman
2025-12-09 01:02:55 -05:00
parent b003a43e73
commit 06ba1cd92c
13 changed files with 94 additions and 86 deletions
+1 -1
View File
@@ -10,7 +10,7 @@
"plugins": [ "plugins": [
{ {
"name": "claude-mem", "name": "claude-mem",
"version": "7.0.1", "version": "7.0.2",
"source": "./plugin", "source": "./plugin",
"description": "Persistent memory system for Claude Code - context compression across sessions" "description": "Persistent memory system for Claude Code - context compression across sessions"
} }
+1 -1
View File
@@ -6,7 +6,7 @@
Claude-mem is a Claude Code plugin providing persistent memory across sessions. It captures tool usage, compresses observations using the Claude Agent SDK, and injects relevant context into future sessions. Claude-mem is a Claude Code plugin providing persistent memory across sessions. It captures tool usage, compresses observations using the Claude Agent SDK, and injects relevant context into future sessions.
**Current Version**: 7.0.1 **Current Version**: 7.0.2
## Architecture ## Architecture
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "claude-mem", "name": "claude-mem",
"version": "7.0.1", "version": "7.0.2",
"description": "Memory compression system for Claude Code - persist context across sessions", "description": "Memory compression system for Claude Code - persist context across sessions",
"keywords": [ "keywords": [
"claude", "claude",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "claude-mem", "name": "claude-mem",
"version": "7.0.1", "version": "7.0.2",
"description": "Persistent memory system for Claude Code - seamlessly preserve context across sessions", "description": "Persistent memory system for Claude Code - seamlessly preserve context across sessions",
"author": { "author": {
"name": "Alex Newman" "name": "Alex Newman"
+6 -6
View File
@@ -1,11 +1,11 @@
#!/usr/bin/env node #!/usr/bin/env node
import{stdin as d}from"process";import m from"path";import{existsSync as C}from"fs";import{homedir as w}from"os";import{spawnSync as v}from"child_process";import{join as r,dirname as R,basename as G}from"path";import{homedir as O}from"os";import{fileURLToPath as U}from"url";function h(){return typeof __dirname<"u"?__dirname:R(U(import.meta.url))}var y=h(),a=process.env.CLAUDE_MEM_DATA_DIR||r(O(),".claude-mem"),S=process.env.CLAUDE_CONFIG_DIR||r(O(),".claude"),q=r(a,"archives"),z=r(a,"logs"),Q=r(a,"trash"),Z=r(a,"backups"),tt=r(a,"settings.json"),et=r(a,"claude-mem.db"),ot=r(a,"vector-db"),rt=r(S,"settings.json"),nt=r(S,"commands"),st=r(S,"CLAUDE.md");function g(){return r(y,"..","..")}import{readFileSync as P,existsSync as k}from"fs";var I=["bugfix","feature","refactor","discovery","decision","change"],x=["how-it-works","why-it-exists","what-changed","problem-solution","gotcha","pattern","trade-off"];var f=I.join(","),A=x.join(",");var u=class{static DEFAULTS={CLAUDE_MEM_MODEL:"claude-haiku-4-5",CLAUDE_MEM_CONTEXT_OBSERVATIONS:"50",CLAUDE_MEM_WORKER_PORT:"37777",CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS:"true",CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS:"true",CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT:"true",CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT:"true",CLAUDE_MEM_CONTEXT_OBSERVATION_TYPES:f,CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS:A,CLAUDE_MEM_CONTEXT_FULL_COUNT:"5",CLAUDE_MEM_CONTEXT_FULL_FIELD:"narrative",CLAUDE_MEM_CONTEXT_SESSION_COUNT:"10",CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY:"true",CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE:"false"};static getAllDefaults(){return{...this.DEFAULTS}}static get(t){return process.env[t]||this.DEFAULTS[t]}static getInt(t){let o=this.get(t);return parseInt(o,10)}static getBool(t){return this.get(t)==="true"}static loadFromFile(t){if(!k(t))return this.getAllDefaults();let o=P(t,"utf-8"),n=JSON.parse(o).env||{},s={...this.DEFAULTS};for(let c of Object.keys(this.DEFAULTS))n[c]!==void 0&&(s[c]=n[c]);return s}};var b=100,W=500,F=10;function T(){let e=m.join(w(),".claude-mem","settings.json"),t=u.loadFromFile(e);return parseInt(t.CLAUDE_MEM_WORKER_PORT,10)}async function D(){try{let e=T();return(await fetch(`http://127.0.0.1:${e}/health`,{signal:AbortSignal.timeout(b)})).ok}catch{return!1}}async function H(){try{let e=g(),t=m.join(e,"ecosystem.config.cjs");if(!C(t))throw new Error(`Ecosystem config not found at ${t}`);let o=m.join(e,"node_modules",".bin","pm2"),i=process.platform==="win32"?o+".cmd":o,n=C(i)?i:"pm2",s=v(n,["start",t],{cwd:e,stdio:"pipe",encoding:"utf-8",windowsHide:!0});if(s.status!==0)throw new Error(s.stderr||"PM2 start failed");for(let c=0;c<F;c++)if(await new Promise(_=>setTimeout(_,W)),await D())return!0;return!1}catch{return!1}}async function M(){if(await D())return;if(!await H()){let t=T(),o=g();throw new Error(`Worker service failed to start on port ${t}. import{stdin as u}from"process";import T from"path";import{existsSync as f}from"fs";import{homedir as d}from"os";import{spawnSync as U}from"child_process";import{readFileSync as D,existsSync as h}from"fs";var N=["bugfix","feature","refactor","discovery","decision","change"],L=["how-it-works","why-it-exists","what-changed","problem-solution","gotcha","pattern","trade-off"];var p=N.join(","),g=L.join(",");var _=class{static DEFAULTS={CLAUDE_MEM_MODEL:"claude-haiku-4-5",CLAUDE_MEM_CONTEXT_OBSERVATIONS:"50",CLAUDE_MEM_WORKER_PORT:"37777",CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS:"true",CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS:"true",CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT:"true",CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT:"true",CLAUDE_MEM_CONTEXT_OBSERVATION_TYPES:p,CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS:g,CLAUDE_MEM_CONTEXT_FULL_COUNT:"5",CLAUDE_MEM_CONTEXT_FULL_FIELD:"narrative",CLAUDE_MEM_CONTEXT_SESSION_COUNT:"10",CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY:"true",CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE:"false"};static getAllDefaults(){return{...this.DEFAULTS}}static get(t){return process.env[t]||this.DEFAULTS[t]}static getInt(t){let n=this.get(t);return parseInt(n,10)}static getBool(t){return this.get(t)==="true"}static loadFromFile(t){if(!h(t))return this.getAllDefaults();let n=D(t,"utf-8"),o=JSON.parse(n).env||{},s={...this.DEFAULTS};for(let i of Object.keys(this.DEFAULTS))o[i]!==void 0&&(s[i]=o[i]);return s}};var E=T.join(d(),".claude","plugins","marketplaces","thedotmack"),y=100,R=500,I=10;function l(){let e=T.join(d(),".claude-mem","settings.json"),t=_.loadFromFile(e);return parseInt(t.CLAUDE_MEM_WORKER_PORT,10)}async function A(){try{let e=l();return(await fetch(`http://127.0.0.1:${e}/health`,{signal:AbortSignal.timeout(y)})).ok}catch{return!1}}async function P(){try{let e=T.join(E,"ecosystem.config.cjs");if(!f(e))throw new Error(`Ecosystem config not found at ${e}`);let t=T.join(E,"node_modules",".bin","pm2"),n=process.platform==="win32"?t+".cmd":t,r=f(n)?n:"pm2",o=U(r,["start",e],{cwd:E,stdio:"pipe",encoding:"utf-8",windowsHide:!0});if(o.status!==0)throw new Error(o.stderr||"PM2 start failed");for(let s=0;s<I;s++)if(await new Promise(i=>setTimeout(i,R)),await A())return!0;return!1}catch{return!1}}async function C(){if(await A())return;if(!await P()){let t=l();throw new Error(`Worker service failed to start on port ${t}.
To start manually, run: To start manually, run:
cd ${o} cd ${E}
npx pm2 start ecosystem.config.cjs npx pm2 start ecosystem.config.cjs
If already running, try: npx pm2 restart claude-mem-worker`)}}import{appendFileSync as X}from"fs";import{homedir as B}from"os";import{join as V}from"path";var $=V(B(),".claude-mem","silent.log");function E(e,t,o=""){let i=new Date().toISOString(),_=((new Error().stack||"").split(` If already running, try: npx pm2 restart claude-mem-worker`)}}import{appendFileSync as k}from"fs";import{homedir as w}from"os";import{join as x}from"path";var W=x(w(),".claude-mem","silent.log");function a(e,t,n=""){let r=new Date().toISOString(),S=((new Error().stack||"").split(`
`)[2]||"").match(/at\s+(?:.*\s+)?\(?([^:]+):(\d+):(\d+)\)?/),L=_?`${_[1].split("/").pop()}:${_[2]}`:"unknown",p=`[${i}] [${L}] ${e}`;if(t!==void 0)try{p+=` ${JSON.stringify(t)}`}catch(l){p+=` [stringify error: ${l}]`}p+=` `)[2]||"").match(/at\s+(?:.*\s+)?\(?([^:]+):(\d+):(\d+)\)?/),M=S?`${S[1].split("/").pop()}:${S[2]}`:"unknown",c=`[${r}] [${M}] ${e}`;if(t!==void 0)try{c+=` ${JSON.stringify(t)}`}catch(O){c+=` [stringify error: ${O}]`}c+=`
`;try{X($,p)}catch(l){console.error("[silent-debug] Failed to write to log:",l)}return o}async function N(e){await M(),E("[cleanup-hook] Hook fired",{session_id:e?.session_id,cwd:e?.cwd,reason:e?.reason}),e||(console.log("No input provided - this script is designed to run as a Claude Code SessionEnd hook"),console.log(` `;try{k(W,c)}catch(O){console.error("[silent-debug] Failed to write to log:",O)}return n}async function m(e){await C(),a("[cleanup-hook] Hook fired",{session_id:e?.session_id,cwd:e?.cwd,reason:e?.reason}),e||(console.log("No input provided - this script is designed to run as a Claude Code SessionEnd hook"),console.log(`
Expected input format:`),console.log(JSON.stringify({session_id:"string",cwd:"string",transcript_path:"string",hook_event_name:"SessionEnd",reason:"exit"},null,2)),process.exit(0));let{session_id:t,reason:o}=e,i=T();try{let n=await fetch(`http://127.0.0.1:${i}/api/sessions/complete`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({claudeSessionId:t,reason:o}),signal:AbortSignal.timeout(2e3)});if(n.ok){let s=await n.json();E("[cleanup-hook] Session cleanup completed",s)}else E("[cleanup-hook] Session not found or already cleaned up")}catch(n){E("[cleanup-hook] Worker not reachable (non-critical)",{error:n.message})}console.log('{"continue": true, "suppressOutput": true}'),process.exit(0)}if(d.isTTY)N(void 0);else{let e="";d.on("data",t=>e+=t),d.on("end",async()=>{let t=e?JSON.parse(e):void 0;await N(t)})} Expected input format:`),console.log(JSON.stringify({session_id:"string",cwd:"string",transcript_path:"string",hook_event_name:"SessionEnd",reason:"exit"},null,2)),process.exit(0));let{session_id:t,reason:n}=e,r=l();try{let o=await fetch(`http://127.0.0.1:${r}/api/sessions/complete`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({claudeSessionId:t,reason:n}),signal:AbortSignal.timeout(2e3)});if(o.ok){let s=await o.json();a("[cleanup-hook] Session cleanup completed",s)}else a("[cleanup-hook] Session not found or already cleaned up")}catch(o){a("[cleanup-hook] Worker not reachable (non-critical)",{error:o.message})}console.log('{"continue": true, "suppressOutput": true}'),process.exit(0)}if(u.isTTY)m(void 0);else{let e="";u.on("data",t=>e+=t),u.on("end",async()=>{let t=e?JSON.parse(e):void 0;await m(t)})}
+3 -3
View File
@@ -1,8 +1,8 @@
#!/usr/bin/env node #!/usr/bin/env node
import W from"path";import{stdin as S}from"process";import{execSync as b}from"child_process";import p from"path";import{existsSync as f}from"fs";import{homedir as y}from"os";import{spawnSync as P}from"child_process";import{join as o,dirname as D,basename as F}from"path";import{homedir as m}from"os";import{fileURLToPath as M}from"url";function N(){return typeof __dirname<"u"?__dirname:D(M(import.meta.url))}var R=N(),n=process.env.CLAUDE_MEM_DATA_DIR||o(m(),".claude-mem"),T=process.env.CLAUDE_CONFIG_DIR||o(m(),".claude"),G=o(n,"archives"),K=o(n,"logs"),Y=o(n,"trash"),$=o(n,"backups"),J=o(n,"settings.json"),q=o(n,"claude-mem.db"),z=o(n,"vector-db"),Q=o(T,"settings.json"),Z=o(T,"commands"),tt=o(T,"CLAUDE.md");function u(){return o(R,"..","..")}import{readFileSync as I,existsSync as x}from"fs";var L=["bugfix","feature","refactor","discovery","decision","change"],U=["how-it-works","why-it-exists","what-changed","problem-solution","gotcha","pattern","trade-off"];var O=L.join(","),g=U.join(",");var _=class{static DEFAULTS={CLAUDE_MEM_MODEL:"claude-haiku-4-5",CLAUDE_MEM_CONTEXT_OBSERVATIONS:"50",CLAUDE_MEM_WORKER_PORT:"37777",CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS:"true",CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS:"true",CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT:"true",CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT:"true",CLAUDE_MEM_CONTEXT_OBSERVATION_TYPES:O,CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS:g,CLAUDE_MEM_CONTEXT_FULL_COUNT:"5",CLAUDE_MEM_CONTEXT_FULL_FIELD:"narrative",CLAUDE_MEM_CONTEXT_SESSION_COUNT:"10",CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY:"true",CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE:"false"};static getAllDefaults(){return{...this.DEFAULTS}}static get(t){return process.env[t]||this.DEFAULTS[t]}static getInt(t){let r=this.get(t);return parseInt(r,10)}static getBool(t){return this.get(t)==="true"}static loadFromFile(t){if(!x(t))return this.getAllDefaults();let r=I(t,"utf-8"),s=JSON.parse(r).env||{},i={...this.DEFAULTS};for(let c of Object.keys(this.DEFAULTS))s[c]!==void 0&&(i[c]=s[c]);return i}};var h=100,w=500,k=10;function E(){let e=p.join(y(),".claude-mem","settings.json"),t=_.loadFromFile(e);return parseInt(t.CLAUDE_MEM_WORKER_PORT,10)}async function A(){try{let e=E();return(await fetch(`http://127.0.0.1:${e}/health`,{signal:AbortSignal.timeout(h)})).ok}catch{return!1}}async function v(){try{let e=u(),t=p.join(e,"ecosystem.config.cjs");if(!f(t))throw new Error(`Ecosystem config not found at ${t}`);let r=p.join(e,"node_modules",".bin","pm2"),a=process.platform==="win32"?r+".cmd":r,s=f(a)?a:"pm2",i=P(s,["start",t],{cwd:e,stdio:"pipe",encoding:"utf-8",windowsHide:!0});if(i.status!==0)throw new Error(i.stderr||"PM2 start failed");for(let c=0;c<k;c++)if(await new Promise(d=>setTimeout(d,w)),await A())return!0;return!1}catch{return!1}}async function C(){if(await A())return;if(!await v()){let t=E(),r=u();throw new Error(`Worker service failed to start on port ${t}. import R from"path";import{stdin as T}from"process";import{execSync as y}from"child_process";import _ from"path";import{existsSync as u}from"fs";import{homedir as p}from"os";import{spawnSync as m}from"child_process";import{readFileSync as N,existsSync as g}from"fs";var M=["bugfix","feature","refactor","discovery","decision","change"],l=["how-it-works","why-it-exists","what-changed","problem-solution","gotcha","pattern","trade-off"];var O=M.join(","),S=l.join(",");var i=class{static DEFAULTS={CLAUDE_MEM_MODEL:"claude-haiku-4-5",CLAUDE_MEM_CONTEXT_OBSERVATIONS:"50",CLAUDE_MEM_WORKER_PORT:"37777",CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS:"true",CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS:"true",CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT:"true",CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT:"true",CLAUDE_MEM_CONTEXT_OBSERVATION_TYPES:O,CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS:S,CLAUDE_MEM_CONTEXT_FULL_COUNT:"5",CLAUDE_MEM_CONTEXT_FULL_FIELD:"narrative",CLAUDE_MEM_CONTEXT_SESSION_COUNT:"10",CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY:"true",CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE:"false"};static getAllDefaults(){return{...this.DEFAULTS}}static get(t){return process.env[t]||this.DEFAULTS[t]}static getInt(t){let r=this.get(t);return parseInt(r,10)}static getBool(t){return this.get(t)==="true"}static loadFromFile(t){if(!g(t))return this.getAllDefaults();let r=N(t,"utf-8"),s=JSON.parse(r).env||{},n={...this.DEFAULTS};for(let o of Object.keys(this.DEFAULTS))s[o]!==void 0&&(n[o]=s[o]);return n}};var E=_.join(p(),".claude","plugins","marketplaces","thedotmack"),d=100,D=500,L=10;function a(){let e=_.join(p(),".claude-mem","settings.json"),t=i.loadFromFile(e);return parseInt(t.CLAUDE_MEM_WORKER_PORT,10)}async function C(){try{let e=a();return(await fetch(`http://127.0.0.1:${e}/health`,{signal:AbortSignal.timeout(d)})).ok}catch{return!1}}async function U(){try{let e=_.join(E,"ecosystem.config.cjs");if(!u(e))throw new Error(`Ecosystem config not found at ${e}`);let t=_.join(E,"node_modules",".bin","pm2"),r=process.platform==="win32"?t+".cmd":t,c=u(r)?r:"pm2",s=m(c,["start",e],{cwd:E,stdio:"pipe",encoding:"utf-8",windowsHide:!0});if(s.status!==0)throw new Error(s.stderr||"PM2 start failed");for(let n=0;n<L;n++)if(await new Promise(o=>setTimeout(o,D)),await C())return!0;return!1}catch{return!1}}async function A(){if(await C())return;if(!await U()){let t=a();throw new Error(`Worker service failed to start on port ${t}.
To start manually, run: To start manually, run:
cd ${r} cd ${E}
npx pm2 start ecosystem.config.cjs npx pm2 start ecosystem.config.cjs
If already running, try: npx pm2 restart claude-mem-worker`)}}async function l(e){await C();let t=e?.cwd??process.cwd(),r=t?W.basename(t):"unknown-project",s=`http://127.0.0.1:${E()}/api/context/inject?project=${encodeURIComponent(r)}`;return b(`curl -s "${s}"`,{encoding:"utf-8",timeout:5e3}).trim()}var H=process.argv.includes("--colors");if(S.isTTY||H)l(void 0).then(e=>{console.log(e),process.exit(0)});else{let e="";S.on("data",t=>e+=t),S.on("end",async()=>{let t=e.trim()?JSON.parse(e):void 0,r=await l(t);console.log(JSON.stringify({hookSpecificOutput:{hookEventName:"SessionStart",additionalContext:r}})),process.exit(0)})} If already running, try: npx pm2 restart claude-mem-worker`)}}async function f(e){await A();let t=e?.cwd??process.cwd(),r=t?R.basename(t):"unknown-project",s=`http://127.0.0.1:${a()}/api/context/inject?project=${encodeURIComponent(r)}`;return y(`curl -s "${s}"`,{encoding:"utf-8",timeout:5e3}).trim()}var I=process.argv.includes("--colors");if(T.isTTY||I)f(void 0).then(e=>{console.log(e),process.exit(0)});else{let e="";T.on("data",t=>e+=t),T.on("end",async()=>{let t=e.trim()?JSON.parse(e):void 0,r=await f(t);console.log(JSON.stringify({hookSpecificOutput:{hookEventName:"SessionStart",additionalContext:r}})),process.exit(0)})}
+8 -8
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env node #!/usr/bin/env node
import ue from"path";import{stdin as B}from"process";import q from"better-sqlite3";import{join as m,dirname as $,basename as Te}from"path";import{homedir as v}from"os";import{existsSync as Re,mkdirSync as G}from"fs";import{fileURLToPath as Y}from"url";function V(){return typeof __dirname<"u"?__dirname:$(Y(import.meta.url))}var K=V(),l=process.env.CLAUDE_MEM_DATA_DIR||m(v(),".claude-mem"),N=process.env.CLAUDE_CONFIG_DIR||m(v(),".claude"),he=m(l,"archives"),Ne=m(l,"logs"),fe=m(l,"trash"),Ie=m(l,"backups"),Ae=m(l,"settings.json"),y=m(l,"claude-mem.db"),Le=m(l,"vector-db"),Ce=m(N,"settings.json"),De=m(N,"commands"),ve=m(N,"CLAUDE.md");function k(a){G(a,{recursive:!0})}function f(){return m(K,"..","..")}var I=(o=>(o[o.DEBUG=0]="DEBUG",o[o.INFO=1]="INFO",o[o.WARN=2]="WARN",o[o.ERROR=3]="ERROR",o[o.SILENT=4]="SILENT",o))(I||{}),A=class{level;useColor;constructor(){let e=process.env.CLAUDE_MEM_LOG_LEVEL?.toUpperCase()||"INFO";this.level=I[e]??1,this.useColor=process.stdout.isTTY??!1}correlationId(e,s){return`obs-${e}-${s}`}sessionId(e){return`session-${e}`}formatData(e){if(e==null)return"";if(typeof e=="string")return e;if(typeof e=="number"||typeof e=="boolean")return e.toString();if(typeof e=="object"){if(e instanceof Error)return this.level===0?`${e.message} import _e from"path";import{stdin as W}from"process";import q from"better-sqlite3";import{join as m,dirname as G,basename as le}from"path";import{homedir as v}from"os";import{existsSync as be,mkdirSync as Y}from"fs";import{fileURLToPath as V}from"url";function K(){return typeof __dirname<"u"?__dirname:G(V(import.meta.url))}var Oe=K(),l=process.env.CLAUDE_MEM_DATA_DIR||m(v(),".claude-mem"),I=process.env.CLAUDE_CONFIG_DIR||m(v(),".claude"),he=m(l,"archives"),Ne=m(l,"logs"),fe=m(l,"trash"),Ie=m(l,"backups"),Ae=m(l,"settings.json"),y=m(l,"claude-mem.db"),Le=m(l,"vector-db"),Ce=m(I,"settings.json"),De=m(I,"commands"),ve=m(I,"CLAUDE.md");function k(a){Y(a,{recursive:!0})}var A=(o=>(o[o.DEBUG=0]="DEBUG",o[o.INFO=1]="INFO",o[o.WARN=2]="WARN",o[o.ERROR=3]="ERROR",o[o.SILENT=4]="SILENT",o))(A||{}),L=class{level;useColor;constructor(){let e=process.env.CLAUDE_MEM_LOG_LEVEL?.toUpperCase()||"INFO";this.level=A[e]??1,this.useColor=process.stdout.isTTY??!1}correlationId(e,s){return`obs-${e}-${s}`}sessionId(e){return`session-${e}`}formatData(e){if(e==null)return"";if(typeof e=="string")return e;if(typeof e=="number"||typeof e=="boolean")return e.toString();if(typeof e=="object"){if(e instanceof Error)return this.level===0?`${e.message}
${e.stack}`:e.message;if(Array.isArray(e))return`[${e.length} items]`;let s=Object.keys(e);return s.length===0?"{}":s.length<=3?JSON.stringify(e):`{${s.length} keys: ${s.slice(0,3).join(", ")}...}`}return String(e)}formatTool(e,s){if(!s)return e;try{let t=typeof s=="string"?JSON.parse(s):s;if(e==="Bash"&&t.command){let r=t.command.length>50?t.command.substring(0,50)+"...":t.command;return`${e}(${r})`}if(e==="Read"&&t.file_path){let r=t.file_path.split("/").pop()||t.file_path;return`${e}(${r})`}if(e==="Edit"&&t.file_path){let r=t.file_path.split("/").pop()||t.file_path;return`${e}(${r})`}if(e==="Write"&&t.file_path){let r=t.file_path.split("/").pop()||t.file_path;return`${e}(${r})`}return e}catch{return e}}log(e,s,t,r,o){if(e<this.level)return;let n=new Date().toISOString().replace("T"," ").substring(0,23),i=I[e].padEnd(5),p=s.padEnd(6),d="";r?.correlationId?d=`[${r.correlationId}] `:r?.sessionId&&(d=`[session-${r.sessionId}] `);let E="";o!=null&&(this.level===0&&typeof o=="object"?E=` ${e.stack}`:e.message;if(Array.isArray(e))return`[${e.length} items]`;let s=Object.keys(e);return s.length===0?"{}":s.length<=3?JSON.stringify(e):`{${s.length} keys: ${s.slice(0,3).join(", ")}...}`}return String(e)}formatTool(e,s){if(!s)return e;try{let t=typeof s=="string"?JSON.parse(s):s;if(e==="Bash"&&t.command){let r=t.command.length>50?t.command.substring(0,50)+"...":t.command;return`${e}(${r})`}if(e==="Read"&&t.file_path){let r=t.file_path.split("/").pop()||t.file_path;return`${e}(${r})`}if(e==="Edit"&&t.file_path){let r=t.file_path.split("/").pop()||t.file_path;return`${e}(${r})`}if(e==="Write"&&t.file_path){let r=t.file_path.split("/").pop()||t.file_path;return`${e}(${r})`}return e}catch{return e}}log(e,s,t,r,o){if(e<this.level)return;let n=new Date().toISOString().replace("T"," ").substring(0,23),i=A[e].padEnd(5),p=s.padEnd(6),d="";r?.correlationId?d=`[${r.correlationId}] `:r?.sessionId&&(d=`[session-${r.sessionId}] `);let E="";o!=null&&(this.level===0&&typeof o=="object"?E=`
`+JSON.stringify(o,null,2):E=" "+this.formatData(o));let _="";if(r){let{sessionId:S,sdkSessionId:b,correlationId:u,...c}=r;Object.keys(c).length>0&&(_=` {${Object.entries(c).map(([W,j])=>`${W}=${j}`).join(", ")}}`)}let T=`[${n}] [${i}] [${p}] ${d}${t}${_}${E}`;e===3?console.error(T):console.log(T)}debug(e,s,t,r){this.log(0,e,s,t,r)}info(e,s,t,r){this.log(1,e,s,t,r)}warn(e,s,t,r){this.log(2,e,s,t,r)}error(e,s,t,r){this.log(3,e,s,t,r)}dataIn(e,s,t,r){this.info(e,`\u2192 ${s}`,t,r)}dataOut(e,s,t,r){this.info(e,`\u2190 ${s}`,t,r)}success(e,s,t,r){this.info(e,`\u2713 ${s}`,t,r)}failure(e,s,t,r){this.error(e,`\u2717 ${s}`,t,r)}timing(e,s,t,r){this.info(e,`\u23F1 ${s}`,r,{duration:`${t}ms`})}},U=new A;var R=class{db;constructor(){k(l),this.db=new q(y),this.db.pragma("journal_mode = WAL"),this.db.pragma("synchronous = NORMAL"),this.db.pragma("foreign_keys = ON"),this.initializeSchema(),this.ensureWorkerPortColumn(),this.ensurePromptTrackingColumns(),this.removeSessionSummariesUniqueConstraint(),this.addObservationHierarchicalFields(),this.makeObservationsTextNullable(),this.createUserPromptsTable(),this.ensureDiscoveryTokensColumn()}initializeSchema(){try{this.db.exec(` `+JSON.stringify(o,null,2):E=" "+this.formatData(o));let _="";if(r){let{sessionId:S,sdkSessionId:b,correlationId:u,...c}=r;Object.keys(c).length>0&&(_=` {${Object.entries(c).map(([j,$])=>`${j}=${$}`).join(", ")}}`)}let T=`[${n}] [${i}] [${p}] ${d}${t}${_}${E}`;e===3?console.error(T):console.log(T)}debug(e,s,t,r){this.log(0,e,s,t,r)}info(e,s,t,r){this.log(1,e,s,t,r)}warn(e,s,t,r){this.log(2,e,s,t,r)}error(e,s,t,r){this.log(3,e,s,t,r)}dataIn(e,s,t,r){this.info(e,`\u2192 ${s}`,t,r)}dataOut(e,s,t,r){this.info(e,`\u2190 ${s}`,t,r)}success(e,s,t,r){this.info(e,`\u2713 ${s}`,t,r)}failure(e,s,t,r){this.error(e,`\u2717 ${s}`,t,r)}timing(e,s,t,r){this.info(e,`\u23F1 ${s}`,r,{duration:`${t}ms`})}},M=new L;var R=class{db;constructor(){k(l),this.db=new q(y),this.db.pragma("journal_mode = WAL"),this.db.pragma("synchronous = NORMAL"),this.db.pragma("foreign_keys = ON"),this.initializeSchema(),this.ensureWorkerPortColumn(),this.ensurePromptTrackingColumns(),this.removeSessionSummariesUniqueConstraint(),this.addObservationHierarchicalFields(),this.makeObservationsTextNullable(),this.createUserPromptsTable(),this.ensureDiscoveryTokensColumn()}initializeSchema(){try{this.db.exec(`
CREATE TABLE IF NOT EXISTS schema_versions ( CREATE TABLE IF NOT EXISTS schema_versions (
id INTEGER PRIMARY KEY, id INTEGER PRIMARY KEY,
version INTEGER UNIQUE NOT NULL, version INTEGER UNIQUE NOT NULL,
@@ -314,7 +314,7 @@ ${e.stack}`:e.message;if(Array.isArray(e))return`[${e.length} items]`;let s=Obje
UPDATE sdk_sessions UPDATE sdk_sessions
SET sdk_session_id = ? SET sdk_session_id = ?
WHERE id = ? AND sdk_session_id IS NULL WHERE id = ? AND sdk_session_id IS NULL
`).run(s,e).changes===0?(U.debug("DB","sdk_session_id already set, skipping update",{sessionId:e,sdkSessionId:s}),!1):!0}setWorkerPort(e,s){this.db.prepare(` `).run(s,e).changes===0?(M.debug("DB","sdk_session_id already set, skipping update",{sessionId:e,sdkSessionId:s}),!1):!0}setWorkerPort(e,s){this.db.prepare(`
UPDATE sdk_sessions UPDATE sdk_sessions
SET worker_port = ? SET worker_port = ?
WHERE id = ? WHERE id = ?
@@ -417,12 +417,12 @@ ${e.stack}`:e.message;if(Array.isArray(e))return`[${e.length} items]`;let s=Obje
JOIN sdk_sessions s ON up.claude_session_id = s.claude_session_id JOIN sdk_sessions s ON up.claude_session_id = s.claude_session_id
WHERE up.created_at_epoch >= ? AND up.created_at_epoch <= ? ${n.replace("project","s.project")} WHERE up.created_at_epoch >= ? AND up.created_at_epoch <= ? ${n.replace("project","s.project")}
ORDER BY up.created_at_epoch ASC ORDER BY up.created_at_epoch ASC
`;try{let S=this.db.prepare(E).all(p,d,...i),b=this.db.prepare(_).all(p,d,...i),u=this.db.prepare(T).all(p,d,...i);return{observations:S,sessions:b.map(c=>({id:c.id,sdk_session_id:c.sdk_session_id,project:c.project,request:c.request,completed:c.completed,next_steps:c.next_steps,created_at:c.created_at,created_at_epoch:c.created_at_epoch})),prompts:u.map(c=>({id:c.id,claude_session_id:c.claude_session_id,project:c.project,prompt:c.prompt_text,created_at:c.created_at,created_at_epoch:c.created_at_epoch}))}}catch(S){return console.error("[SessionStore] Error querying timeline records:",S.message),{observations:[],sessions:[],prompts:[]}}}close(){this.db.close()}};function J(a,e,s){return a==="PreCompact"?e?{continue:!0,suppressOutput:!0}:{continue:!1,stopReason:s.reason||"Pre-compact operation failed",suppressOutput:!0}:a==="SessionStart"?e&&s.context?{continue:!0,suppressOutput:!0,hookSpecificOutput:{hookEventName:"SessionStart",additionalContext:s.context}}:{continue:!0,suppressOutput:!0}:a==="UserPromptSubmit"||a==="PostToolUse"?{continue:!0,suppressOutput:!0}:a==="Stop"?{continue:!0,suppressOutput:!0}:{continue:e,suppressOutput:!0,...s.reason&&!e?{stopReason:s.reason}:{}}}function L(a,e,s={}){let t=J(a,e,s);return JSON.stringify(t)}import C from"path";import{existsSync as w}from"fs";import{homedir as se}from"os";import{spawnSync as te}from"child_process";import{readFileSync as Z,existsSync as ee}from"fs";var Q=["bugfix","feature","refactor","discovery","decision","change"],z=["how-it-works","why-it-exists","what-changed","problem-solution","gotcha","pattern","trade-off"];var x=Q.join(","),M=z.join(",");var O=class{static DEFAULTS={CLAUDE_MEM_MODEL:"claude-haiku-4-5",CLAUDE_MEM_CONTEXT_OBSERVATIONS:"50",CLAUDE_MEM_WORKER_PORT:"37777",CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS:"true",CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS:"true",CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT:"true",CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT:"true",CLAUDE_MEM_CONTEXT_OBSERVATION_TYPES:x,CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS:M,CLAUDE_MEM_CONTEXT_FULL_COUNT:"5",CLAUDE_MEM_CONTEXT_FULL_FIELD:"narrative",CLAUDE_MEM_CONTEXT_SESSION_COUNT:"10",CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY:"true",CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE:"false"};static getAllDefaults(){return{...this.DEFAULTS}}static get(e){return process.env[e]||this.DEFAULTS[e]}static getInt(e){let s=this.get(e);return parseInt(s,10)}static getBool(e){return this.get(e)==="true"}static loadFromFile(e){if(!ee(e))return this.getAllDefaults();let s=Z(e,"utf-8"),r=JSON.parse(s).env||{},o={...this.DEFAULTS};for(let n of Object.keys(this.DEFAULTS))r[n]!==void 0&&(o[n]=r[n]);return o}};var re=100,oe=500,ne=10;function h(){let a=C.join(se(),".claude-mem","settings.json"),e=O.loadFromFile(a);return parseInt(e.CLAUDE_MEM_WORKER_PORT,10)}async function F(){try{let a=h();return(await fetch(`http://127.0.0.1:${a}/health`,{signal:AbortSignal.timeout(re)})).ok}catch{return!1}}async function ie(){try{let a=f(),e=C.join(a,"ecosystem.config.cjs");if(!w(e))throw new Error(`Ecosystem config not found at ${e}`);let s=C.join(a,"node_modules",".bin","pm2"),t=process.platform==="win32"?s+".cmd":s,r=w(t)?t:"pm2",o=te(r,["start",e],{cwd:a,stdio:"pipe",encoding:"utf-8",windowsHide:!0});if(o.status!==0)throw new Error(o.stderr||"PM2 start failed");for(let n=0;n<ne;n++)if(await new Promise(i=>setTimeout(i,oe)),await F())return!0;return!1}catch{return!1}}async function X(){if(await F())return;if(!await ie()){let e=h(),s=f();throw new Error(`Worker service failed to start on port ${e}. `;try{let S=this.db.prepare(E).all(p,d,...i),b=this.db.prepare(_).all(p,d,...i),u=this.db.prepare(T).all(p,d,...i);return{observations:S,sessions:b.map(c=>({id:c.id,sdk_session_id:c.sdk_session_id,project:c.project,request:c.request,completed:c.completed,next_steps:c.next_steps,created_at:c.created_at,created_at_epoch:c.created_at_epoch})),prompts:u.map(c=>({id:c.id,claude_session_id:c.claude_session_id,project:c.project,prompt:c.prompt_text,created_at:c.created_at,created_at_epoch:c.created_at_epoch}))}}catch(S){return console.error("[SessionStore] Error querying timeline records:",S.message),{observations:[],sessions:[],prompts:[]}}}close(){this.db.close()}};function J(a,e,s){return a==="PreCompact"?e?{continue:!0,suppressOutput:!0}:{continue:!1,stopReason:s.reason||"Pre-compact operation failed",suppressOutput:!0}:a==="SessionStart"?e&&s.context?{continue:!0,suppressOutput:!0,hookSpecificOutput:{hookEventName:"SessionStart",additionalContext:s.context}}:{continue:!0,suppressOutput:!0}:a==="UserPromptSubmit"||a==="PostToolUse"?{continue:!0,suppressOutput:!0}:a==="Stop"?{continue:!0,suppressOutput:!0}:{continue:e,suppressOutput:!0,...s.reason&&!e?{stopReason:s.reason}:{}}}function C(a,e,s={}){let t=J(a,e,s);return JSON.stringify(t)}import N from"path";import{existsSync as w}from"fs";import{homedir as F}from"os";import{spawnSync as se}from"child_process";import{readFileSync as Z,existsSync as ee}from"fs";var Q=["bugfix","feature","refactor","discovery","decision","change"],z=["how-it-works","why-it-exists","what-changed","problem-solution","gotcha","pattern","trade-off"];var U=Q.join(","),x=z.join(",");var O=class{static DEFAULTS={CLAUDE_MEM_MODEL:"claude-haiku-4-5",CLAUDE_MEM_CONTEXT_OBSERVATIONS:"50",CLAUDE_MEM_WORKER_PORT:"37777",CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS:"true",CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS:"true",CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT:"true",CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT:"true",CLAUDE_MEM_CONTEXT_OBSERVATION_TYPES:U,CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS:x,CLAUDE_MEM_CONTEXT_FULL_COUNT:"5",CLAUDE_MEM_CONTEXT_FULL_FIELD:"narrative",CLAUDE_MEM_CONTEXT_SESSION_COUNT:"10",CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY:"true",CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE:"false"};static getAllDefaults(){return{...this.DEFAULTS}}static get(e){return process.env[e]||this.DEFAULTS[e]}static getInt(e){let s=this.get(e);return parseInt(s,10)}static getBool(e){return this.get(e)==="true"}static loadFromFile(e){if(!ee(e))return this.getAllDefaults();let s=Z(e,"utf-8"),r=JSON.parse(s).env||{},o={...this.DEFAULTS};for(let n of Object.keys(this.DEFAULTS))r[n]!==void 0&&(o[n]=r[n]);return o}};var h=N.join(F(),".claude","plugins","marketplaces","thedotmack"),te=100,re=500,oe=10;function f(){let a=N.join(F(),".claude-mem","settings.json"),e=O.loadFromFile(a);return parseInt(e.CLAUDE_MEM_WORKER_PORT,10)}async function X(){try{let a=f();return(await fetch(`http://127.0.0.1:${a}/health`,{signal:AbortSignal.timeout(te)})).ok}catch{return!1}}async function ne(){try{let a=N.join(h,"ecosystem.config.cjs");if(!w(a))throw new Error(`Ecosystem config not found at ${a}`);let e=N.join(h,"node_modules",".bin","pm2"),s=process.platform==="win32"?e+".cmd":e,t=w(s)?s:"pm2",r=se(t,["start",a],{cwd:h,stdio:"pipe",encoding:"utf-8",windowsHide:!0});if(r.status!==0)throw new Error(r.stderr||"PM2 start failed");for(let o=0;o<oe;o++)if(await new Promise(n=>setTimeout(n,re)),await X())return!0;return!1}catch{return!1}}async function P(){if(await X())return;if(!await ne()){let e=f();throw new Error(`Worker service failed to start on port ${e}.
To start manually, run: To start manually, run:
cd ${s} cd ${h}
npx pm2 start ecosystem.config.cjs npx pm2 start ecosystem.config.cjs
If already running, try: npx pm2 restart claude-mem-worker`)}}import{appendFileSync as ae}from"fs";import{homedir as pe}from"os";import{join as ce}from"path";var de=ce(pe(),".claude-mem","silent.log");function g(a,e,s=""){let t=new Date().toISOString(),i=((new Error().stack||"").split(` If already running, try: npx pm2 restart claude-mem-worker`)}}import{appendFileSync as ie}from"fs";import{homedir as ae}from"os";import{join as pe}from"path";var ce=pe(ae(),".claude-mem","silent.log");function g(a,e,s=""){let t=new Date().toISOString(),i=((new Error().stack||"").split(`
`)[2]||"").match(/at\s+(?:.*\s+)?\(?([^:]+):(\d+):(\d+)\)?/),p=i?`${i[1].split("/").pop()}:${i[2]}`:"unknown",d=`[${t}] [${p}] ${a}`;if(e!==void 0)try{d+=` ${JSON.stringify(e)}`}catch(E){d+=` [stringify error: ${E}]`}d+=` `)[2]||"").match(/at\s+(?:.*\s+)?\(?([^:]+):(\d+):(\d+)\)?/),p=i?`${i[1].split("/").pop()}:${i[2]}`:"unknown",d=`[${t}] [${p}] ${a}`;if(e!==void 0)try{d+=` ${JSON.stringify(e)}`}catch(E){d+=` [stringify error: ${E}]`}d+=`
`;try{ae(de,d)}catch(E){console.error("[silent-debug] Failed to write to log:",E)}return s}var P=100;function _e(a){let e=(a.match(/<private>/g)||[]).length,s=(a.match(/<claude-mem-context>/g)||[]).length;return e+s}function H(a){if(typeof a!="string")return g("[tag-stripping] received non-string for prompt context:",{type:typeof a}),"";let e=_e(a);return e>P&&g("[tag-stripping] tag count exceeds limit, truncating:",{tagCount:e,maxAllowed:P,contentLength:a.length}),a.replace(/<claude-mem-context>[\s\S]*?<\/claude-mem-context>/g,"").replace(/<private>[\s\S]*?<\/private>/g,"").trim()}async function Ee(a){if(await X(),!a)throw new Error("newHook requires input");let{session_id:e,cwd:s,prompt:t}=a;g("[new-hook] Input received",{session_id:e,cwd:s,cwd_type:typeof s,cwd_length:s?.length,has_cwd:!!s,prompt_length:t?.length});let r=ue.basename(s);g("[new-hook] Project extracted",{project:r,project_type:typeof r,project_length:r?.length,is_empty:r==="",cwd_was:s});let o=new R,n=o.createSDKSession(e,r,t),i=o.incrementPromptCounter(n),p=H(t);if(!p||p.trim()===""){g("[new-hook] Prompt entirely private, skipping memory operations",{session_id:e,promptNumber:i,originalLength:t.length}),o.close(),console.error(`[new-hook] Session ${n}, prompt #${i} (fully private - skipped)`),console.log(L("UserPromptSubmit",!0));return}o.saveUserPrompt(e,i,p),console.error(`[new-hook] Session ${n}, prompt #${i}`),o.close();let d=h(),E=t.startsWith("/")?t.substring(1):t;try{let _=await fetch(`http://127.0.0.1:${d}/sessions/${n}/init`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({project:r,userPrompt:E,promptNumber:i}),signal:AbortSignal.timeout(5e3)});if(!_.ok){let T=await _.text();throw new Error(`Failed to initialize session: ${_.status} ${T}`)}}catch(_){throw _.cause?.code==="ECONNREFUSED"||_.name==="TimeoutError"||_.message.includes("fetch failed")?new Error("There's a problem with the worker. If you just updated, type `pm2 restart claude-mem-worker` in your terminal to continue"):_}console.log(L("UserPromptSubmit",!0))}var D="";B.on("data",a=>D+=a);B.on("end",async()=>{let a=D?JSON.parse(D):void 0;await Ee(a)}); `;try{ie(ce,d)}catch(E){console.error("[silent-debug] Failed to write to log:",E)}return s}var H=100;function de(a){let e=(a.match(/<private>/g)||[]).length,s=(a.match(/<claude-mem-context>/g)||[]).length;return e+s}function B(a){if(typeof a!="string")return g("[tag-stripping] received non-string for prompt context:",{type:typeof a}),"";let e=de(a);return e>H&&g("[tag-stripping] tag count exceeds limit, truncating:",{tagCount:e,maxAllowed:H,contentLength:a.length}),a.replace(/<claude-mem-context>[\s\S]*?<\/claude-mem-context>/g,"").replace(/<private>[\s\S]*?<\/private>/g,"").trim()}async function ue(a){if(await P(),!a)throw new Error("newHook requires input");let{session_id:e,cwd:s,prompt:t}=a;g("[new-hook] Input received",{session_id:e,cwd:s,cwd_type:typeof s,cwd_length:s?.length,has_cwd:!!s,prompt_length:t?.length});let r=_e.basename(s);g("[new-hook] Project extracted",{project:r,project_type:typeof r,project_length:r?.length,is_empty:r==="",cwd_was:s});let o=new R,n=o.createSDKSession(e,r,t),i=o.incrementPromptCounter(n),p=B(t);if(!p||p.trim()===""){g("[new-hook] Prompt entirely private, skipping memory operations",{session_id:e,promptNumber:i,originalLength:t.length}),o.close(),console.error(`[new-hook] Session ${n}, prompt #${i} (fully private - skipped)`),console.log(C("UserPromptSubmit",!0));return}o.saveUserPrompt(e,i,p),console.error(`[new-hook] Session ${n}, prompt #${i}`),o.close();let d=f(),E=t.startsWith("/")?t.substring(1):t;try{let _=await fetch(`http://127.0.0.1:${d}/sessions/${n}/init`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({project:r,userPrompt:E,promptNumber:i}),signal:AbortSignal.timeout(5e3)});if(!_.ok){let T=await _.text();throw new Error(`Failed to initialize session: ${_.status} ${T}`)}}catch(_){throw _.cause?.code==="ECONNREFUSED"||_.name==="TimeoutError"||_.message.includes("fetch failed")?new Error("There's a problem with the worker. If you just updated, type `pm2 restart claude-mem-worker` in your terminal to continue"):_}console.log(C("UserPromptSubmit",!0))}var D="";W.on("data",a=>D+=a);W.on("end",async()=>{let a=D?JSON.parse(D):void 0;await ue(a)});
+5 -5
View File
@@ -1,10 +1,10 @@
#!/usr/bin/env node #!/usr/bin/env node
import{stdin as x}from"process";function k(n,t,e){return n==="PreCompact"?t?{continue:!0,suppressOutput:!0}:{continue:!1,stopReason:e.reason||"Pre-compact operation failed",suppressOutput:!0}:n==="SessionStart"?t&&e.context?{continue:!0,suppressOutput:!0,hookSpecificOutput:{hookEventName:"SessionStart",additionalContext:e.context}}:{continue:!0,suppressOutput:!0}:n==="UserPromptSubmit"||n==="PostToolUse"?{continue:!0,suppressOutput:!0}:n==="Stop"?{continue:!0,suppressOutput:!0}:{continue:t,suppressOutput:!0,...e.reason&&!t?{stopReason:e.reason}:{}}}function S(n,t,e={}){let o=k(n,t,e);return JSON.stringify(o)}var T=(s=>(s[s.DEBUG=0]="DEBUG",s[s.INFO=1]="INFO",s[s.WARN=2]="WARN",s[s.ERROR=3]="ERROR",s[s.SILENT=4]="SILENT",s))(T||{}),m=class{level;useColor;constructor(){let t=process.env.CLAUDE_MEM_LOG_LEVEL?.toUpperCase()||"INFO";this.level=T[t]??1,this.useColor=process.stdout.isTTY??!1}correlationId(t,e){return`obs-${t}-${e}`}sessionId(t){return`session-${t}`}formatData(t){if(t==null)return"";if(typeof t=="string")return t;if(typeof t=="number"||typeof t=="boolean")return t.toString();if(typeof t=="object"){if(t instanceof Error)return this.level===0?`${t.message} import{stdin as U}from"process";function P(r,t,e){return r==="PreCompact"?t?{continue:!0,suppressOutput:!0}:{continue:!1,stopReason:e.reason||"Pre-compact operation failed",suppressOutput:!0}:r==="SessionStart"?t&&e.context?{continue:!0,suppressOutput:!0,hookSpecificOutput:{hookEventName:"SessionStart",additionalContext:e.context}}:{continue:!0,suppressOutput:!0}:r==="UserPromptSubmit"||r==="PostToolUse"?{continue:!0,suppressOutput:!0}:r==="Stop"?{continue:!0,suppressOutput:!0}:{continue:t,suppressOutput:!0,...e.reason&&!t?{stopReason:e.reason}:{}}}function S(r,t,e={}){let o=P(r,t,e);return JSON.stringify(o)}var T=(s=>(s[s.DEBUG=0]="DEBUG",s[s.INFO=1]="INFO",s[s.WARN=2]="WARN",s[s.ERROR=3]="ERROR",s[s.SILENT=4]="SILENT",s))(T||{}),g=class{level;useColor;constructor(){let t=process.env.CLAUDE_MEM_LOG_LEVEL?.toUpperCase()||"INFO";this.level=T[t]??1,this.useColor=process.stdout.isTTY??!1}correlationId(t,e){return`obs-${t}-${e}`}sessionId(t){return`session-${t}`}formatData(t){if(t==null)return"";if(typeof t=="string")return t;if(typeof t=="number"||typeof t=="boolean")return t.toString();if(typeof t=="object"){if(t instanceof Error)return this.level===0?`${t.message}
${t.stack}`:t.message;if(Array.isArray(t))return`[${t.length} items]`;let e=Object.keys(t);return e.length===0?"{}":e.length<=3?JSON.stringify(t):`{${e.length} keys: ${e.slice(0,3).join(", ")}...}`}return String(t)}formatTool(t,e){if(!e)return t;try{let o=typeof e=="string"?JSON.parse(e):e;if(t==="Bash"&&o.command){let r=o.command.length>50?o.command.substring(0,50)+"...":o.command;return`${t}(${r})`}if(t==="Read"&&o.file_path){let r=o.file_path.split("/").pop()||o.file_path;return`${t}(${r})`}if(t==="Edit"&&o.file_path){let r=o.file_path.split("/").pop()||o.file_path;return`${t}(${r})`}if(t==="Write"&&o.file_path){let r=o.file_path.split("/").pop()||o.file_path;return`${t}(${r})`}return t}catch{return t}}log(t,e,o,r,s){if(t<this.level)return;let a=new Date().toISOString().replace("T"," ").substring(0,23),_=T[t].padEnd(5),c=e.padEnd(6),p="";r?.correlationId?p=`[${r.correlationId}] `:r?.sessionId&&(p=`[session-${r.sessionId}] `);let g="";s!=null&&(this.level===0&&typeof s=="object"?g=` ${t.stack}`:t.message;if(Array.isArray(t))return`[${t.length} items]`;let e=Object.keys(t);return e.length===0?"{}":e.length<=3?JSON.stringify(t):`{${e.length} keys: ${e.slice(0,3).join(", ")}...}`}return String(t)}formatTool(t,e){if(!e)return t;try{let o=typeof e=="string"?JSON.parse(e):e;if(t==="Bash"&&o.command){let n=o.command.length>50?o.command.substring(0,50)+"...":o.command;return`${t}(${n})`}if(t==="Read"&&o.file_path){let n=o.file_path.split("/").pop()||o.file_path;return`${t}(${n})`}if(t==="Edit"&&o.file_path){let n=o.file_path.split("/").pop()||o.file_path;return`${t}(${n})`}if(t==="Write"&&o.file_path){let n=o.file_path.split("/").pop()||o.file_path;return`${t}(${n})`}return t}catch{return t}}log(t,e,o,n,s){if(t<this.level)return;let a=new Date().toISOString().replace("T"," ").substring(0,23),f=T[t].padEnd(5),i=e.padEnd(6),u="";n?.correlationId?u=`[${n.correlationId}] `:n?.sessionId&&(u=`[session-${n.sessionId}] `);let O="";s!=null&&(this.level===0&&typeof s=="object"?O=`
`+JSON.stringify(s,null,2):g=" "+this.formatData(s));let D="";if(r){let{sessionId:z,sdkSessionId:Z,correlationId:tt,...h}=r;Object.keys(h).length>0&&(D=` {${Object.entries(h).map(([P,v])=>`${P}=${v}`).join(", ")}}`)}let R=`[${a}] [${_}] [${c}] ${p}${o}${D}${g}`;t===3?console.error(R):console.log(R)}debug(t,e,o,r){this.log(0,t,e,o,r)}info(t,e,o,r){this.log(1,t,e,o,r)}warn(t,e,o,r){this.log(2,t,e,o,r)}error(t,e,o,r){this.log(3,t,e,o,r)}dataIn(t,e,o,r){this.info(t,`\u2192 ${e}`,o,r)}dataOut(t,e,o,r){this.info(t,`\u2190 ${e}`,o,r)}success(t,e,o,r){this.info(t,`\u2713 ${e}`,o,r)}failure(t,e,o,r){this.error(t,`\u2717 ${e}`,o,r)}timing(t,e,o,r){this.info(t,`\u23F1 ${e}`,r,{duration:`${o}ms`})}},E=new m;import C from"path";import{existsSync as N}from"fs";import{homedir as j}from"os";import{spawnSync as K}from"child_process";import{join as i,dirname as b,basename as st}from"path";import{homedir as y}from"os";import{fileURLToPath as w}from"url";function $(){return typeof __dirname<"u"?__dirname:b(w(import.meta.url))}var H=$(),u=process.env.CLAUDE_MEM_DATA_DIR||i(y(),".claude-mem"),O=process.env.CLAUDE_CONFIG_DIR||i(y(),".claude"),ut=i(u,"archives"),pt=i(u,"logs"),_t=i(u,"trash"),Et=i(u,"backups"),ft=i(u,"settings.json"),lt=i(u,"claude-mem.db"),gt=i(u,"vector-db"),St=i(O,"settings.json"),Tt=i(O,"commands"),mt=i(O,"CLAUDE.md");function d(){return i(H,"..","..")}import{readFileSync as B,existsSync as X}from"fs";var W=["bugfix","feature","refactor","discovery","decision","change"],F=["how-it-works","why-it-exists","what-changed","problem-solution","gotcha","pattern","trade-off"];var L=W.join(","),M=F.join(",");var f=class{static DEFAULTS={CLAUDE_MEM_MODEL:"claude-haiku-4-5",CLAUDE_MEM_CONTEXT_OBSERVATIONS:"50",CLAUDE_MEM_WORKER_PORT:"37777",CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS:"true",CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS:"true",CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT:"true",CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT:"true",CLAUDE_MEM_CONTEXT_OBSERVATION_TYPES:L,CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS:M,CLAUDE_MEM_CONTEXT_FULL_COUNT:"5",CLAUDE_MEM_CONTEXT_FULL_FIELD:"narrative",CLAUDE_MEM_CONTEXT_SESSION_COUNT:"10",CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY:"true",CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE:"false"};static getAllDefaults(){return{...this.DEFAULTS}}static get(t){return process.env[t]||this.DEFAULTS[t]}static getInt(t){let e=this.get(t);return parseInt(e,10)}static getBool(t){return this.get(t)==="true"}static loadFromFile(t){if(!X(t))return this.getAllDefaults();let e=B(t,"utf-8"),r=JSON.parse(e).env||{},s={...this.DEFAULTS};for(let a of Object.keys(this.DEFAULTS))r[a]!==void 0&&(s[a]=r[a]);return s}};var V=100,G=500,Y=10;function l(){let n=C.join(j(),".claude-mem","settings.json"),t=f.loadFromFile(n);return parseInt(t.CLAUDE_MEM_WORKER_PORT,10)}async function U(){try{let n=l();return(await fetch(`http://127.0.0.1:${n}/health`,{signal:AbortSignal.timeout(V)})).ok}catch{return!1}}async function J(){try{let n=d(),t=C.join(n,"ecosystem.config.cjs");if(!N(t))throw new Error(`Ecosystem config not found at ${t}`);let e=C.join(n,"node_modules",".bin","pm2"),o=process.platform==="win32"?e+".cmd":e,r=N(o)?o:"pm2",s=K(r,["start",t],{cwd:n,stdio:"pipe",encoding:"utf-8",windowsHide:!0});if(s.status!==0)throw new Error(s.stderr||"PM2 start failed");for(let a=0;a<Y;a++)if(await new Promise(_=>setTimeout(_,G)),await U())return!0;return!1}catch{return!1}}async function I(){if(await U())return;if(!await J()){let t=l(),e=d();throw new Error(`Worker service failed to start on port ${t}. `+JSON.stringify(s,null,2):O=" "+this.formatData(s));let C="";if(n){let{sessionId:K,sdkSessionId:j,correlationId:V,...A}=n;Object.keys(A).length>0&&(C=` {${Object.entries(A).map(([D,I])=>`${D}=${I}`).join(", ")}}`)}let d=`[${a}] [${f}] [${i}] ${u}${o}${C}${O}`;t===3?console.error(d):console.log(d)}debug(t,e,o,n){this.log(0,t,e,o,n)}info(t,e,o,n){this.log(1,t,e,o,n)}warn(t,e,o,n){this.log(2,t,e,o,n)}error(t,e,o,n){this.log(3,t,e,o,n)}dataIn(t,e,o,n){this.info(t,`\u2192 ${e}`,o,n)}dataOut(t,e,o,n){this.info(t,`\u2190 ${e}`,o,n)}success(t,e,o,n){this.info(t,`\u2713 ${e}`,o,n)}failure(t,e,o,n){this.error(t,`\u2717 ${e}`,o,n)}timing(t,e,o,n){this.info(t,`\u23F1 ${e}`,n,{duration:`${o}ms`})}},c=new g;import _ from"path";import{existsSync as h}from"fs";import{homedir as R}from"os";import{spawnSync as x}from"child_process";import{readFileSync as v,existsSync as w}from"fs";var b=["bugfix","feature","refactor","discovery","decision","change"],k=["how-it-works","why-it-exists","what-changed","problem-solution","gotcha","pattern","trade-off"];var y=b.join(","),M=k.join(",");var p=class{static DEFAULTS={CLAUDE_MEM_MODEL:"claude-haiku-4-5",CLAUDE_MEM_CONTEXT_OBSERVATIONS:"50",CLAUDE_MEM_WORKER_PORT:"37777",CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS:"true",CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS:"true",CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT:"true",CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT:"true",CLAUDE_MEM_CONTEXT_OBSERVATION_TYPES:y,CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS:M,CLAUDE_MEM_CONTEXT_FULL_COUNT:"5",CLAUDE_MEM_CONTEXT_FULL_FIELD:"narrative",CLAUDE_MEM_CONTEXT_SESSION_COUNT:"10",CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY:"true",CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE:"false"};static getAllDefaults(){return{...this.DEFAULTS}}static get(t){return process.env[t]||this.DEFAULTS[t]}static getInt(t){let e=this.get(t);return parseInt(e,10)}static getBool(t){return this.get(t)==="true"}static loadFromFile(t){if(!w(t))return this.getAllDefaults();let e=v(t,"utf-8"),n=JSON.parse(e).env||{},s={...this.DEFAULTS};for(let a of Object.keys(this.DEFAULTS))n[a]!==void 0&&(s[a]=n[a]);return s}};var E=_.join(R(),".claude","plugins","marketplaces","thedotmack"),$=100,H=500,W=10;function l(){let r=_.join(R(),".claude-mem","settings.json"),t=p.loadFromFile(r);return parseInt(t.CLAUDE_MEM_WORKER_PORT,10)}async function L(){try{let r=l();return(await fetch(`http://127.0.0.1:${r}/health`,{signal:AbortSignal.timeout($)})).ok}catch{return!1}}async function F(){try{let r=_.join(E,"ecosystem.config.cjs");if(!h(r))throw new Error(`Ecosystem config not found at ${r}`);let t=_.join(E,"node_modules",".bin","pm2"),e=process.platform==="win32"?t+".cmd":t,o=h(e)?e:"pm2",n=x(o,["start",r],{cwd:E,stdio:"pipe",encoding:"utf-8",windowsHide:!0});if(n.status!==0)throw new Error(n.stderr||"PM2 start failed");for(let s=0;s<W;s++)if(await new Promise(a=>setTimeout(a,H)),await L())return!0;return!1}catch{return!1}}async function N(){if(await L())return;if(!await F()){let t=l();throw new Error(`Worker service failed to start on port ${t}.
To start manually, run: To start manually, run:
cd ${e} cd ${E}
npx pm2 start ecosystem.config.cjs npx pm2 start ecosystem.config.cjs
If already running, try: npx pm2 restart claude-mem-worker`)}}var q=new Set(["ListMcpResourcesTool","SlashCommand","Skill","TodoWrite","AskUserQuestion"]);async function Q(n){if(await I(),!n)throw new Error("saveHook requires input");let{session_id:t,cwd:e,tool_name:o,tool_input:r,tool_response:s}=n;if(q.has(o)){console.log(S("PostToolUse",!0));return}let a=l(),_=E.formatTool(o,r);E.dataIn("HOOK",`PostToolUse: ${_}`,{workerPort:a});try{let c=await fetch(`http://127.0.0.1:${a}/api/sessions/observations`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({claudeSessionId:t,tool_name:o,tool_input:r,tool_response:s,cwd:e||""}),signal:AbortSignal.timeout(2e3)});if(!c.ok){let p=await c.text();throw E.failure("HOOK","Failed to send observation",{status:c.status},p),new Error(`Failed to send observation to worker: ${c.status} ${p}`)}E.debug("HOOK","Observation sent successfully",{toolName:o})}catch(c){throw c.cause?.code==="ECONNREFUSED"||c.name==="TimeoutError"||c.message.includes("fetch failed")?new Error("There's a problem with the worker. If you just updated, type `pm2 restart claude-mem-worker` in your terminal to continue"):c}console.log(S("PostToolUse",!0))}var A="";x.on("data",n=>A+=n);x.on("end",async()=>{let n=A?JSON.parse(A):void 0;await Q(n)}); If already running, try: npx pm2 restart claude-mem-worker`)}}var X=new Set(["ListMcpResourcesTool","SlashCommand","Skill","TodoWrite","AskUserQuestion"]);async function B(r){if(await N(),!r)throw new Error("saveHook requires input");let{session_id:t,cwd:e,tool_name:o,tool_input:n,tool_response:s}=r;if(X.has(o)){console.log(S("PostToolUse",!0));return}let a=l(),f=c.formatTool(o,n);c.dataIn("HOOK",`PostToolUse: ${f}`,{workerPort:a});try{let i=await fetch(`http://127.0.0.1:${a}/api/sessions/observations`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({claudeSessionId:t,tool_name:o,tool_input:n,tool_response:s,cwd:e||""}),signal:AbortSignal.timeout(2e3)});if(!i.ok){let u=await i.text();throw c.failure("HOOK","Failed to send observation",{status:i.status},u),new Error(`Failed to send observation to worker: ${i.status} ${u}`)}c.debug("HOOK","Observation sent successfully",{toolName:o})}catch(i){throw i.cause?.code==="ECONNREFUSED"||i.name==="TimeoutError"||i.message.includes("fetch failed")?new Error("There's a problem with the worker. If you just updated, type `pm2 restart claude-mem-worker` in your terminal to continue"):i}console.log(S("PostToolUse",!0))}var m="";U.on("data",r=>m+=r);U.on("end",async()=>{let r=m?JSON.parse(m):void 0;await B(r)});
+9 -9
View File
@@ -1,16 +1,16 @@
#!/usr/bin/env node #!/usr/bin/env node
import{stdin as I}from"process";import{readFileSync as P,existsSync as k}from"fs";function w(o,t,e){return o==="PreCompact"?t?{continue:!0,suppressOutput:!0}:{continue:!1,stopReason:e.reason||"Pre-compact operation failed",suppressOutput:!0}:o==="SessionStart"?t&&e.context?{continue:!0,suppressOutput:!0,hookSpecificOutput:{hookEventName:"SessionStart",additionalContext:e.context}}:{continue:!0,suppressOutput:!0}:o==="UserPromptSubmit"||o==="PostToolUse"?{continue:!0,suppressOutput:!0}:o==="Stop"?{continue:!0,suppressOutput:!0}:{continue:t,suppressOutput:!0,...e.reason&&!t?{stopReason:e.reason}:{}}}function R(o,t,e={}){let r=w(o,t,e);return JSON.stringify(r)}var m=(s=>(s[s.DEBUG=0]="DEBUG",s[s.INFO=1]="INFO",s[s.WARN=2]="WARN",s[s.ERROR=3]="ERROR",s[s.SILENT=4]="SILENT",s))(m||{}),S=class{level;useColor;constructor(){let t=process.env.CLAUDE_MEM_LOG_LEVEL?.toUpperCase()||"INFO";this.level=m[t]??1,this.useColor=process.stdout.isTTY??!1}correlationId(t,e){return`obs-${t}-${e}`}sessionId(t){return`session-${t}`}formatData(t){if(t==null)return"";if(typeof t=="string")return t;if(typeof t=="number"||typeof t=="boolean")return t.toString();if(typeof t=="object"){if(t instanceof Error)return this.level===0?`${t.message} import{stdin as D}from"process";import{readFileSync as U,existsSync as I}from"fs";function k(o,t,e){return o==="PreCompact"?t?{continue:!0,suppressOutput:!0}:{continue:!1,stopReason:e.reason||"Pre-compact operation failed",suppressOutput:!0}:o==="SessionStart"?t&&e.context?{continue:!0,suppressOutput:!0,hookSpecificOutput:{hookEventName:"SessionStart",additionalContext:e.context}}:{continue:!0,suppressOutput:!0}:o==="UserPromptSubmit"||o==="PostToolUse"?{continue:!0,suppressOutput:!0}:o==="Stop"?{continue:!0,suppressOutput:!0}:{continue:t,suppressOutput:!0,...e.reason&&!t?{stopReason:e.reason}:{}}}function d(o,t,e={}){let n=k(o,t,e);return JSON.stringify(n)}var O=(s=>(s[s.DEBUG=0]="DEBUG",s[s.INFO=1]="INFO",s[s.WARN=2]="WARN",s[s.ERROR=3]="ERROR",s[s.SILENT=4]="SILENT",s))(O||{}),S=class{level;useColor;constructor(){let t=process.env.CLAUDE_MEM_LOG_LEVEL?.toUpperCase()||"INFO";this.level=O[t]??1,this.useColor=process.stdout.isTTY??!1}correlationId(t,e){return`obs-${t}-${e}`}sessionId(t){return`session-${t}`}formatData(t){if(t==null)return"";if(typeof t=="string")return t;if(typeof t=="number"||typeof t=="boolean")return t.toString();if(typeof t=="object"){if(t instanceof Error)return this.level===0?`${t.message}
${t.stack}`:t.message;if(Array.isArray(t))return`[${t.length} items]`;let e=Object.keys(t);return e.length===0?"{}":e.length<=3?JSON.stringify(t):`{${e.length} keys: ${e.slice(0,3).join(", ")}...}`}return String(t)}formatTool(t,e){if(!e)return t;try{let r=typeof e=="string"?JSON.parse(e):e;if(t==="Bash"&&r.command){let n=r.command.length>50?r.command.substring(0,50)+"...":r.command;return`${t}(${n})`}if(t==="Read"&&r.file_path){let n=r.file_path.split("/").pop()||r.file_path;return`${t}(${n})`}if(t==="Edit"&&r.file_path){let n=r.file_path.split("/").pop()||r.file_path;return`${t}(${n})`}if(t==="Write"&&r.file_path){let n=r.file_path.split("/").pop()||r.file_path;return`${t}(${n})`}return t}catch{return t}}log(t,e,r,n,s){if(t<this.level)return;let i=new Date().toISOString().replace("T"," ").substring(0,23),c=m[t].padEnd(5),f=e.padEnd(6),g="";n?.correlationId?g=`[${n.correlationId}] `:n?.sessionId&&(g=`[session-${n.sessionId}] `);let l="";s!=null&&(this.level===0&&typeof s=="object"?l=` ${t.stack}`:t.message;if(Array.isArray(t))return`[${t.length} items]`;let e=Object.keys(t);return e.length===0?"{}":e.length<=3?JSON.stringify(t):`{${e.length} keys: ${e.slice(0,3).join(", ")}...}`}return String(t)}formatTool(t,e){if(!e)return t;try{let n=typeof e=="string"?JSON.parse(e):e;if(t==="Bash"&&n.command){let r=n.command.length>50?n.command.substring(0,50)+"...":n.command;return`${t}(${r})`}if(t==="Read"&&n.file_path){let r=n.file_path.split("/").pop()||n.file_path;return`${t}(${r})`}if(t==="Edit"&&n.file_path){let r=n.file_path.split("/").pop()||n.file_path;return`${t}(${r})`}if(t==="Write"&&n.file_path){let r=n.file_path.split("/").pop()||n.file_path;return`${t}(${r})`}return t}catch{return t}}log(t,e,n,r,s){if(t<this.level)return;let i=new Date().toISOString().replace("T"," ").substring(0,23),a=O[t].padEnd(5),u=e.padEnd(6),l="";r?.correlationId?l=`[${r.correlationId}] `:r?.sessionId&&(l=`[session-${r.sessionId}] `);let g="";s!=null&&(this.level===0&&typeof s=="object"?g=`
`+JSON.stringify(s,null,2):l=" "+this.formatData(s));let y="";if(n){let{sessionId:et,sdkSessionId:rt,correlationId:nt,...D}=n;Object.keys(D).length>0&&(y=` {${Object.entries(D).map(([v,b])=>`${v}=${b}`).join(", ")}}`)}let A=`[${i}] [${c}] [${f}] ${g}${r}${y}${l}`;t===3?console.error(A):console.log(A)}debug(t,e,r,n){this.log(0,t,e,r,n)}info(t,e,r,n){this.log(1,t,e,r,n)}warn(t,e,r,n){this.log(2,t,e,r,n)}error(t,e,r,n){this.log(3,t,e,r,n)}dataIn(t,e,r,n){this.info(t,`\u2192 ${e}`,r,n)}dataOut(t,e,r,n){this.info(t,`\u2190 ${e}`,r,n)}success(t,e,r,n){this.info(t,`\u2713 ${e}`,r,n)}failure(t,e,r,n){this.error(t,`\u2717 ${e}`,r,n)}timing(t,e,r,n){this.info(t,`\u23F1 ${e}`,n,{duration:`${r}ms`})}},p=new S;import d from"path";import{existsSync as N}from"fs";import{homedir as V}from"os";import{spawnSync as G}from"child_process";import{join as a,dirname as $,basename as ct}from"path";import{homedir as h}from"os";import{fileURLToPath as H}from"url";function F(){return typeof __dirname<"u"?__dirname:$(H(import.meta.url))}var W=F(),u=process.env.CLAUDE_MEM_DATA_DIR||a(h(),".claude-mem"),O=process.env.CLAUDE_CONFIG_DIR||a(h(),".claude"),Et=a(u,"archives"),_t=a(u,"logs"),gt=a(u,"trash"),lt=a(u,"backups"),mt=a(u,"settings.json"),St=a(u,"claude-mem.db"),Ot=a(u,"vector-db"),Tt=a(O,"settings.json"),dt=a(O,"commands"),Ct=a(O,"CLAUDE.md");function T(){return a(W,"..","..")}import{readFileSync as X,existsSync as K}from"fs";var j=["bugfix","feature","refactor","discovery","decision","change"],B=["how-it-works","why-it-exists","what-changed","problem-solution","gotcha","pattern","trade-off"];var M=j.join(","),L=B.join(",");var E=class{static DEFAULTS={CLAUDE_MEM_MODEL:"claude-haiku-4-5",CLAUDE_MEM_CONTEXT_OBSERVATIONS:"50",CLAUDE_MEM_WORKER_PORT:"37777",CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS:"true",CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS:"true",CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT:"true",CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT:"true",CLAUDE_MEM_CONTEXT_OBSERVATION_TYPES:M,CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS:L,CLAUDE_MEM_CONTEXT_FULL_COUNT:"5",CLAUDE_MEM_CONTEXT_FULL_FIELD:"narrative",CLAUDE_MEM_CONTEXT_SESSION_COUNT:"10",CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY:"true",CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE:"false"};static getAllDefaults(){return{...this.DEFAULTS}}static get(t){return process.env[t]||this.DEFAULTS[t]}static getInt(t){let e=this.get(t);return parseInt(e,10)}static getBool(t){return this.get(t)==="true"}static loadFromFile(t){if(!K(t))return this.getAllDefaults();let e=X(t,"utf-8"),n=JSON.parse(e).env||{},s={...this.DEFAULTS};for(let i of Object.keys(this.DEFAULTS))n[i]!==void 0&&(s[i]=n[i]);return s}};var Y=100,J=500,q=10;function _(){let o=d.join(V(),".claude-mem","settings.json"),t=E.loadFromFile(o);return parseInt(t.CLAUDE_MEM_WORKER_PORT,10)}async function x(){try{let o=_();return(await fetch(`http://127.0.0.1:${o}/health`,{signal:AbortSignal.timeout(Y)})).ok}catch{return!1}}async function z(){try{let o=T(),t=d.join(o,"ecosystem.config.cjs");if(!N(t))throw new Error(`Ecosystem config not found at ${t}`);let e=d.join(o,"node_modules",".bin","pm2"),r=process.platform==="win32"?e+".cmd":e,n=N(r)?r:"pm2",s=G(n,["start",t],{cwd:o,stdio:"pipe",encoding:"utf-8",windowsHide:!0});if(s.status!==0)throw new Error(s.stderr||"PM2 start failed");for(let i=0;i<q;i++)if(await new Promise(c=>setTimeout(c,J)),await x())return!0;return!1}catch{return!1}}async function U(){if(await x())return;if(!await z()){let t=_(),e=T();throw new Error(`Worker service failed to start on port ${t}. `+JSON.stringify(s,null,2):g=" "+this.formatData(s));let T="";if(r){let{sessionId:G,sdkSessionId:Y,correlationId:J,...C}=r;Object.keys(C).length>0&&(T=` {${Object.entries(C).map(([x,b])=>`${x}=${b}`).join(", ")}}`)}let y=`[${i}] [${a}] [${u}] ${l}${n}${T}${g}`;t===3?console.error(y):console.log(y)}debug(t,e,n,r){this.log(0,t,e,n,r)}info(t,e,n,r){this.log(1,t,e,n,r)}warn(t,e,n,r){this.log(2,t,e,n,r)}error(t,e,n,r){this.log(3,t,e,n,r)}dataIn(t,e,n,r){this.info(t,`\u2192 ${e}`,n,r)}dataOut(t,e,n,r){this.info(t,`\u2190 ${e}`,n,r)}success(t,e,n,r){this.info(t,`\u2713 ${e}`,n,r)}failure(t,e,n,r){this.error(t,`\u2717 ${e}`,n,r)}timing(t,e,n,r){this.info(t,`\u23F1 ${e}`,r,{duration:`${n}ms`})}},c=new S;import f from"path";import{existsSync as M}from"fs";import{homedir as R}from"os";import{spawnSync as H}from"child_process";import{readFileSync as w,existsSync as $}from"fs";var P=["bugfix","feature","refactor","discovery","decision","change"],v=["how-it-works","why-it-exists","what-changed","problem-solution","gotcha","pattern","trade-off"];var A=P.join(","),h=v.join(",");var p=class{static DEFAULTS={CLAUDE_MEM_MODEL:"claude-haiku-4-5",CLAUDE_MEM_CONTEXT_OBSERVATIONS:"50",CLAUDE_MEM_WORKER_PORT:"37777",CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS:"true",CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS:"true",CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT:"true",CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT:"true",CLAUDE_MEM_CONTEXT_OBSERVATION_TYPES:A,CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS:h,CLAUDE_MEM_CONTEXT_FULL_COUNT:"5",CLAUDE_MEM_CONTEXT_FULL_FIELD:"narrative",CLAUDE_MEM_CONTEXT_SESSION_COUNT:"10",CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY:"true",CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE:"false"};static getAllDefaults(){return{...this.DEFAULTS}}static get(t){return process.env[t]||this.DEFAULTS[t]}static getInt(t){let e=this.get(t);return parseInt(e,10)}static getBool(t){return this.get(t)==="true"}static loadFromFile(t){if(!$(t))return this.getAllDefaults();let e=w(t,"utf-8"),r=JSON.parse(e).env||{},s={...this.DEFAULTS};for(let i of Object.keys(this.DEFAULTS))r[i]!==void 0&&(s[i]=r[i]);return s}};var E=f.join(R(),".claude","plugins","marketplaces","thedotmack"),W=100,F=500,X=10;function _(){let o=f.join(R(),".claude-mem","settings.json"),t=p.loadFromFile(o);return parseInt(t.CLAUDE_MEM_WORKER_PORT,10)}async function L(){try{let o=_();return(await fetch(`http://127.0.0.1:${o}/health`,{signal:AbortSignal.timeout(W)})).ok}catch{return!1}}async function j(){try{let o=f.join(E,"ecosystem.config.cjs");if(!M(o))throw new Error(`Ecosystem config not found at ${o}`);let t=f.join(E,"node_modules",".bin","pm2"),e=process.platform==="win32"?t+".cmd":t,n=M(e)?e:"pm2",r=H(n,["start",o],{cwd:E,stdio:"pipe",encoding:"utf-8",windowsHide:!0});if(r.status!==0)throw new Error(r.stderr||"PM2 start failed");for(let s=0;s<X;s++)if(await new Promise(i=>setTimeout(i,F)),await L())return!0;return!1}catch{return!1}}async function N(){if(await L())return;if(!await j()){let t=_();throw new Error(`Worker service failed to start on port ${t}.
To start manually, run: To start manually, run:
cd ${e} cd ${E}
npx pm2 start ecosystem.config.cjs npx pm2 start ecosystem.config.cjs
If already running, try: npx pm2 restart claude-mem-worker`)}}function Q(o){if(!o||!k(o))return"";try{let t=P(o,"utf-8").trim();if(!t)return"";let e=t.split(` If already running, try: npx pm2 restart claude-mem-worker`)}}function B(o){if(!o||!I(o))return"";try{let t=U(o,"utf-8").trim();if(!t)return"";let e=t.split(`
`);for(let r=e.length-1;r>=0;r--)try{let n=JSON.parse(e[r]);if(n.type==="user"&&n.message?.content){let s=n.message.content;if(typeof s=="string")return s;if(Array.isArray(s))return s.filter(c=>c.type==="text").map(c=>c.text).join(` `);for(let n=e.length-1;n>=0;n--)try{let r=JSON.parse(e[n]);if(r.type==="user"&&r.message?.content){let s=r.message.content;if(typeof s=="string")return s;if(Array.isArray(s))return s.filter(a=>a.type==="text").map(a=>a.text).join(`
`)}}catch{continue}}catch(t){p.error("HOOK","Failed to read transcript",{transcriptPath:o},t)}return""}function Z(o){if(!o||!k(o))return"";try{let t=P(o,"utf-8").trim();if(!t)return"";let e=t.split(` `)}}catch{continue}}catch(t){c.error("HOOK","Failed to read transcript",{transcriptPath:o},t)}return""}function K(o){if(!o||!I(o))return"";try{let t=U(o,"utf-8").trim();if(!t)return"";let e=t.split(`
`);for(let r=e.length-1;r>=0;r--)try{let n=JSON.parse(e[r]);if(n.type==="assistant"&&n.message?.content){let s="",i=n.message.content;return typeof i=="string"?s=i:Array.isArray(i)&&(s=i.filter(f=>f.type==="text").map(f=>f.text).join(` `);for(let n=e.length-1;n>=0;n--)try{let r=JSON.parse(e[n]);if(r.type==="assistant"&&r.message?.content){let s="",i=r.message.content;return typeof i=="string"?s=i:Array.isArray(i)&&(s=i.filter(u=>u.type==="text").map(u=>u.text).join(`
`)),s=s.replace(/<system-reminder>[\s\S]*?<\/system-reminder>/g,""),s=s.replace(/\n{3,}/g,` `)),s=s.replace(/<system-reminder>[\s\S]*?<\/system-reminder>/g,""),s=s.replace(/\n{3,}/g,`
`).trim(),s}}catch{continue}}catch(t){p.error("HOOK","Failed to read transcript",{transcriptPath:o},t)}return""}async function tt(o){if(await U(),!o)throw new Error("summaryHook requires input");let{session_id:t}=o,e=_(),r=Q(o.transcript_path||""),n=Z(o.transcript_path||"");p.dataIn("HOOK","Stop: Requesting summary",{workerPort:e,hasLastUserMessage:!!r,hasLastAssistantMessage:!!n});try{let s=await fetch(`http://127.0.0.1:${e}/api/sessions/summarize`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({claudeSessionId:t,last_user_message:r,last_assistant_message:n}),signal:AbortSignal.timeout(2e3)});if(!s.ok){let i=await s.text();throw p.failure("HOOK","Failed to generate summary",{status:s.status},i),new Error(`Failed to request summary from worker: ${s.status} ${i}`)}p.debug("HOOK","Summary request sent successfully")}catch(s){throw s.cause?.code==="ECONNREFUSED"||s.name==="TimeoutError"||s.message.includes("fetch failed")?new Error("There's a problem with the worker. If you just updated, type `pm2 restart claude-mem-worker` in your terminal to continue"):s}finally{fetch(`http://127.0.0.1:${e}/api/processing`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({isProcessing:!1})}).catch(()=>{})}console.log(R("Stop",!0))}var C="";I.on("data",o=>C+=o);I.on("end",async()=>{let o=C?JSON.parse(C):void 0;await tt(o)}); `).trim(),s}}catch{continue}}catch(t){c.error("HOOK","Failed to read transcript",{transcriptPath:o},t)}return""}async function V(o){if(await N(),!o)throw new Error("summaryHook requires input");let{session_id:t}=o,e=_(),n=B(o.transcript_path||""),r=K(o.transcript_path||"");c.dataIn("HOOK","Stop: Requesting summary",{workerPort:e,hasLastUserMessage:!!n,hasLastAssistantMessage:!!r});try{let s=await fetch(`http://127.0.0.1:${e}/api/sessions/summarize`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({claudeSessionId:t,last_user_message:n,last_assistant_message:r}),signal:AbortSignal.timeout(2e3)});if(!s.ok){let i=await s.text();throw c.failure("HOOK","Failed to generate summary",{status:s.status},i),new Error(`Failed to request summary from worker: ${s.status} ${i}`)}c.debug("HOOK","Summary request sent successfully")}catch(s){throw s.cause?.code==="ECONNREFUSED"||s.name==="TimeoutError"||s.message.includes("fetch failed")?new Error("There's a problem with the worker. If you just updated, type `pm2 restart claude-mem-worker` in your terminal to continue"):s}finally{fetch(`http://127.0.0.1:${e}/api/processing`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({isProcessing:!1})}).catch(()=>{})}console.log(d("Stop",!0))}var m="";D.on("data",o=>m+=o);D.on("end",async()=>{let o=m?JSON.parse(m):void 0;await V(o)});
+7 -7
View File
@@ -1,11 +1,11 @@
#!/usr/bin/env node #!/usr/bin/env node
import{join as M,basename as B}from"path";import{homedir as j}from"os";import{existsSync as G}from"fs";import l from"path";import{existsSync as A}from"fs";import{homedir as b}from"os";import{spawnSync as W}from"child_process";import{join as r,dirname as R,basename as Z}from"path";import{homedir as g}from"os";import{fileURLToPath as y}from"url";function I(){return typeof __dirname<"u"?__dirname:R(y(import.meta.url))}var w=I(),a=process.env.CLAUDE_MEM_DATA_DIR||r(g(),".claude-mem"),p=process.env.CLAUDE_CONFIG_DIR||r(g(),".claude"),et=r(a,"archives"),ot=r(a,"logs"),rt=r(a,"trash"),nt=r(a,"backups"),st=r(a,"settings.json"),it=r(a,"claude-mem.db"),at=r(a,"vector-db"),ct=r(p,"settings.json"),_t=r(p,"commands"),Et=r(p,"CLAUDE.md");function m(){return r(w,"..","..")}import{readFileSync as k,existsSync as v}from"fs";var x=["bugfix","feature","refactor","discovery","decision","change"],P=["how-it-works","why-it-exists","what-changed","problem-solution","gotcha","pattern","trade-off"];var O=x.join(","),f=P.join(",");var E=class{static DEFAULTS={CLAUDE_MEM_MODEL:"claude-haiku-4-5",CLAUDE_MEM_CONTEXT_OBSERVATIONS:"50",CLAUDE_MEM_WORKER_PORT:"37777",CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS:"true",CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS:"true",CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT:"true",CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT:"true",CLAUDE_MEM_CONTEXT_OBSERVATION_TYPES:O,CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS:f,CLAUDE_MEM_CONTEXT_FULL_COUNT:"5",CLAUDE_MEM_CONTEXT_FULL_FIELD:"narrative",CLAUDE_MEM_CONTEXT_SESSION_COUNT:"10",CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY:"true",CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE:"false"};static getAllDefaults(){return{...this.DEFAULTS}}static get(t){return process.env[t]||this.DEFAULTS[t]}static getInt(t){let o=this.get(t);return parseInt(o,10)}static getBool(t){return this.get(t)==="true"}static loadFromFile(t){if(!v(t))return this.getAllDefaults();let o=k(t,"utf-8"),n=JSON.parse(o).env||{},i={...this.DEFAULTS};for(let s of Object.keys(this.DEFAULTS))n[s]!==void 0&&(i[s]=n[s]);return i}};var H=100,F=500,X=10;function u(){let e=l.join(b(),".claude-mem","settings.json"),t=E.loadFromFile(e);return parseInt(t.CLAUDE_MEM_WORKER_PORT,10)}async function C(){try{let e=u();return(await fetch(`http://127.0.0.1:${e}/health`,{signal:AbortSignal.timeout(H)})).ok}catch{return!1}}async function V(){try{let e=m(),t=l.join(e,"ecosystem.config.cjs");if(!A(t))throw new Error(`Ecosystem config not found at ${t}`);let o=l.join(e,"node_modules",".bin","pm2"),c=process.platform==="win32"?o+".cmd":o,n=A(c)?c:"pm2",i=W(n,["start",t],{cwd:e,stdio:"pipe",encoding:"utf-8",windowsHide:!0});if(i.status!==0)throw new Error(i.stderr||"PM2 start failed");for(let s=0;s<X;s++)if(await new Promise(_=>setTimeout(_,F)),await C())return!0;return!1}catch{return!1}}async function D(){if(await C())return;if(!await V()){let t=u(),o=m();throw new Error(`Worker service failed to start on port ${t}. import{join as M,basename as k}from"path";import{homedir as v}from"os";import{existsSync as x}from"fs";import c from"path";import{existsSync as m}from"fs";import{homedir as C}from"os";import{spawnSync as R}from"child_process";import{readFileSync as L,existsSync as y}from"fs";var h=["bugfix","feature","refactor","discovery","decision","change"],U=["how-it-works","why-it-exists","what-changed","problem-solution","gotcha","pattern","trade-off"];var p=h.join(","),S=U.join(",");var a=class{static DEFAULTS={CLAUDE_MEM_MODEL:"claude-haiku-4-5",CLAUDE_MEM_CONTEXT_OBSERVATIONS:"50",CLAUDE_MEM_WORKER_PORT:"37777",CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS:"true",CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS:"true",CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT:"true",CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT:"true",CLAUDE_MEM_CONTEXT_OBSERVATION_TYPES:p,CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS:S,CLAUDE_MEM_CONTEXT_FULL_COUNT:"5",CLAUDE_MEM_CONTEXT_FULL_FIELD:"narrative",CLAUDE_MEM_CONTEXT_SESSION_COUNT:"10",CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY:"true",CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE:"false"};static getAllDefaults(){return{...this.DEFAULTS}}static get(t){return process.env[t]||this.DEFAULTS[t]}static getInt(t){let n=this.get(t);return parseInt(n,10)}static getBool(t){return this.get(t)==="true"}static loadFromFile(t){if(!y(t))return this.getAllDefaults();let n=L(t,"utf-8"),o=JSON.parse(n).env||{},r={...this.DEFAULTS};for(let s of Object.keys(this.DEFAULTS))o[s]!==void 0&&(r[s]=o[s]);return r}};var E=c.join(C(),".claude","plugins","marketplaces","thedotmack"),w=100,I=500,P=10;function _(){let e=c.join(C(),".claude-mem","settings.json"),t=a.loadFromFile(e);return parseInt(t.CLAUDE_MEM_WORKER_PORT,10)}async function f(){try{let e=_();return(await fetch(`http://127.0.0.1:${e}/health`,{signal:AbortSignal.timeout(w)})).ok}catch{return!1}}async function W(){try{let e=c.join(E,"ecosystem.config.cjs");if(!m(e))throw new Error(`Ecosystem config not found at ${e}`);let t=c.join(E,"node_modules",".bin","pm2"),n=process.platform==="win32"?t+".cmd":t,i=m(n)?n:"pm2",o=R(i,["start",e],{cwd:E,stdio:"pipe",encoding:"utf-8",windowsHide:!0});if(o.status!==0)throw new Error(o.stderr||"PM2 start failed");for(let r=0;r<P;r++)if(await new Promise(s=>setTimeout(s,I)),await f())return!0;return!1}catch{return!1}}async function A(){if(await f())return;if(!await W()){let t=_();throw new Error(`Worker service failed to start on port ${t}.
To start manually, run: To start manually, run:
cd ${o} cd ${E}
npx pm2 start ecosystem.config.cjs npx pm2 start ecosystem.config.cjs
If already running, try: npx pm2 restart claude-mem-worker`)}}var K=M(j(),".claude","plugins","marketplaces","thedotmack"),Y=M(K,"node_modules");G(Y)||(console.error(` If already running, try: npx pm2 restart claude-mem-worker`)}}var b=M(v(),".claude","plugins","marketplaces","thedotmack"),X=M(b,"node_modules");x(X)||(console.error(`
--- ---
\u{1F389} Note: This appears under Plugin Hook Error, but it's not an error. That's the only option for \u{1F389} Note: This appears under Plugin Hook Error, but it's not an error. That's the only option for
user messages in Claude Code UI until a better method is provided. user messages in Claude Code UI until a better method is provided.
@@ -23,7 +23,7 @@ Dependencies have been installed in the background. This only happens once.
Thank you for installing Claude-Mem! Thank you for installing Claude-Mem!
This message was not added to your startup context, so you can continue working as normal. This message was not added to your startup context, so you can continue working as normal.
`),process.exit(3));try{await D();let e=u(),t=B(process.cwd()),o=await fetch(`http://127.0.0.1:${e}/api/context/inject?project=${encodeURIComponent(t)}&colors=true`,{method:"GET",signal:AbortSignal.timeout(5e3)});if(!o.ok)throw new Error(`Worker error ${o.status}`);let c=await o.text(),n=new Date,i=new Date("2025-12-06T00:00:00Z"),s=new Date("2025-12-05T05:00:00Z"),_="";n<s&&(_=` `),process.exit(3));try{await A();let e=_(),t=k(process.cwd()),n=await fetch(`http://127.0.0.1:${e}/api/context/inject?project=${encodeURIComponent(t)}&colors=true`,{method:"GET",signal:AbortSignal.timeout(5e3)});if(!n.ok)throw new Error(`Worker error ${n.status}`);let i=await n.text(),o=new Date,r=new Date("2025-12-06T00:00:00Z"),s=new Date("2025-12-05T05:00:00Z"),u="";o<s&&(u=`
\u{1F680} \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501 \u{1F680} \u{1F680} \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501 \u{1F680}
@@ -33,7 +33,7 @@ This message was not added to your startup context, so you can continue working
\u2B50 Your upvote means the world - thank you! \u2B50 Your upvote means the world - thank you!
\u{1F680} \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501 \u{1F680} \u{1F680} \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501 \u{1F680}
`);let T="";if(n<i){let h=n.getUTCHours()*60+n.getUTCMinutes(),S=Math.floor((h-300+1440)%1440/60),d=n.getUTCDate(),N=n.getUTCMonth(),U=n.getUTCFullYear()===2025&&N===11&&d>=1&&d<=5,L=S>=17&&S<19;U&&L?T=` `);let T="";if(o<r){let d=o.getUTCHours()*60+o.getUTCMinutes(),l=Math.floor((d-300+1440)%1440/60),O=o.getUTCDate(),g=o.getUTCMonth(),N=o.getUTCFullYear()===2025&&g===11&&O>=1&&O<=5,D=l>=17&&l<19;N&&D?T=`
\u{1F534} LIVE NOW: AMA w/ Dev (@thedotmack) until 7pm EST \u{1F534} LIVE NOW: AMA w/ Dev (@thedotmack) until 7pm EST
`:T=` `:T=`
\u2013 LIVE AMA w/ Dev (@thedotmack) Dec 1st\u20135th, 5pm to 7pm EST \u2013 LIVE AMA w/ Dev (@thedotmack) Dec 1st\u20135th, 5pm to 7pm EST
@@ -42,10 +42,10 @@ This message was not added to your startup context, so you can continue working
\u{1F4DD} Claude-Mem Context Loaded \u{1F4DD} Claude-Mem Context Loaded
\u2139\uFE0F Note: This appears as stderr but is informational only \u2139\uFE0F Note: This appears as stderr but is informational only
`+c+` `+i+`
\u{1F4A1} New! Wrap all or part of any message with <private> ... </private> to prevent storing sensitive information in your observation history. \u{1F4A1} New! Wrap all or part of any message with <private> ... </private> to prevent storing sensitive information in your observation history.
\u{1F4AC} Community https://discord.gg/J4wttp9vDu`+_+T+` \u{1F4AC} Community https://discord.gg/J4wttp9vDu`+u+T+`
\u{1F4FA} Watch live in browser http://localhost:${e}/ \u{1F4FA} Watch live in browser http://localhost:${e}/
`)}catch(e){console.error(`\u274C Failed to load context display: ${e}`)}process.exit(3); `)}catch(e){console.error(`\u274C Failed to load context display: ${e}`)}process.exit(3);
File diff suppressed because one or more lines are too long
+10 -4
View File
@@ -15,6 +15,7 @@ import { existsSync, readFileSync, writeFileSync } from 'fs';
import { execSync, spawnSync } from 'child_process'; import { execSync, spawnSync } from 'child_process';
import { join, dirname } from 'path'; import { join, dirname } from 'path';
import { fileURLToPath } from 'url'; import { fileURLToPath } from 'url';
import { homedir } from 'os';
const __filename = fileURLToPath(import.meta.url); const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename); const __dirname = dirname(__filename);
@@ -26,6 +27,10 @@ const VERSION_MARKER_PATH = join(PLUGIN_ROOT, '.install-version');
const NODE_MODULES_PATH = join(PLUGIN_ROOT, 'node_modules'); const NODE_MODULES_PATH = join(PLUGIN_ROOT, 'node_modules');
const BETTER_SQLITE3_PATH = join(NODE_MODULES_PATH, 'better-sqlite3'); const BETTER_SQLITE3_PATH = join(NODE_MODULES_PATH, 'better-sqlite3');
// CRITICAL: Always use marketplace directory for PM2/ecosystem
// This ensures cross-platform compatibility and avoids cache directory confusion
const MARKETPLACE_ROOT = join(homedir(), '.claude', 'plugins', 'marketplaces', 'thedotmack');
// Colors for output // Colors for output
const colors = { const colors = {
reset: '\x1b[0m', reset: '\x1b[0m',
@@ -367,15 +372,16 @@ async function main() {
// Try to start the PM2 worker after fresh install // Try to start the PM2 worker after fresh install
try { try {
log('🚀 Starting worker service...', colors.cyan); log('🚀 Starting worker service...', colors.cyan);
// On Windows, PM2 executable is pm2.cmd, not pm2 // CRITICAL: Always use marketplace directory for PM2/ecosystem
const localPm2Base = join(NODE_MODULES_PATH, '.bin', 'pm2'); // This ensures PM2 starts from the correct location regardless of where this script runs from
const localPm2Base = join(MARKETPLACE_ROOT, 'node_modules', '.bin', 'pm2');
const localPm2Cmd = process.platform === 'win32' ? localPm2Base + '.cmd' : localPm2Base; const localPm2Cmd = process.platform === 'win32' ? localPm2Base + '.cmd' : localPm2Base;
const pm2Command = existsSync(localPm2Cmd) ? localPm2Cmd : 'pm2'; const pm2Command = existsSync(localPm2Cmd) ? localPm2Cmd : 'pm2';
const ecosystemPath = join(PLUGIN_ROOT, 'ecosystem.config.cjs'); const ecosystemPath = join(MARKETPLACE_ROOT, 'ecosystem.config.cjs');
// Using spawnSync with array args to avoid command injection risks // Using spawnSync with array args to avoid command injection risks
const result = spawnSync(pm2Command, ['start', ecosystemPath], { const result = spawnSync(pm2Command, ['start', ecosystemPath], {
cwd: PLUGIN_ROOT, cwd: MARKETPLACE_ROOT,
stdio: 'pipe', stdio: 'pipe',
encoding: 'utf-8' encoding: 'utf-8'
}); });
+11 -9
View File
@@ -2,9 +2,12 @@ import path from "path";
import { existsSync } from "fs"; import { existsSync } from "fs";
import { homedir } from "os"; import { homedir } from "os";
import { spawnSync } from "child_process"; import { spawnSync } from "child_process";
import { getPackageRoot } from "./paths.js";
import { SettingsDefaultsManager } from "../services/worker/settings/SettingsDefaultsManager.js"; import { SettingsDefaultsManager } from "../services/worker/settings/SettingsDefaultsManager.js";
// CRITICAL: Always use marketplace directory for PM2/ecosystem
// This ensures cross-platform compatibility and avoids cache directory confusion
const MARKETPLACE_ROOT = path.join(homedir(), '.claude', 'plugins', 'marketplaces', 'thedotmack');
// Named constants for health checks // Named constants for health checks
const HEALTH_CHECK_TIMEOUT_MS = 100; const HEALTH_CHECK_TIMEOUT_MS = 100;
const WORKER_STARTUP_WAIT_MS = 500; const WORKER_STARTUP_WAIT_MS = 500;
@@ -40,9 +43,9 @@ async function isWorkerHealthy(): Promise<boolean> {
*/ */
async function startWorker(): Promise<boolean> { async function startWorker(): Promise<boolean> {
try { try {
// Find the ecosystem config file (built version in plugin/) // CRITICAL: Always use marketplace directory for ecosystem.config.cjs
const pluginRoot = getPackageRoot(); // This ensures PM2 starts from the correct location regardless of where hooks run from
const ecosystemPath = path.join(pluginRoot, 'ecosystem.config.cjs'); const ecosystemPath = path.join(MARKETPLACE_ROOT, 'ecosystem.config.cjs');
if (!existsSync(ecosystemPath)) { if (!existsSync(ecosystemPath)) {
throw new Error(`Ecosystem config not found at ${ecosystemPath}`); throw new Error(`Ecosystem config not found at ${ecosystemPath}`);
@@ -50,15 +53,15 @@ async function startWorker(): Promise<boolean> {
// Try to use local PM2 from node_modules first, fall back to global PM2 // Try to use local PM2 from node_modules first, fall back to global PM2
// On Windows, PM2 executable is pm2.cmd, not pm2 // On Windows, PM2 executable is pm2.cmd, not pm2
const localPm2Base = path.join(pluginRoot, 'node_modules', '.bin', 'pm2'); const localPm2Base = path.join(MARKETPLACE_ROOT, 'node_modules', '.bin', 'pm2');
const localPm2Cmd = process.platform === 'win32' ? localPm2Base + '.cmd' : localPm2Base; const localPm2Cmd = process.platform === 'win32' ? localPm2Base + '.cmd' : localPm2Base;
const pm2Command = existsSync(localPm2Cmd) ? localPm2Cmd : 'pm2'; const pm2Command = existsSync(localPm2Cmd) ? localPm2Cmd : 'pm2';
// Start using PM2 with the ecosystem config // Start using PM2 with the ecosystem config
// CRITICAL: Must set cwd to pluginRoot so PM2 starts from marketplace directory // CRITICAL: Must set cwd to MARKETPLACE_ROOT so PM2 starts from marketplace directory
// Using spawnSync with array args to avoid command injection risks // Using spawnSync with array args to avoid command injection risks
const result = spawnSync(pm2Command, ['start', ecosystemPath], { const result = spawnSync(pm2Command, ['start', ecosystemPath], {
cwd: pluginRoot, cwd: MARKETPLACE_ROOT,
stdio: 'pipe', stdio: 'pipe',
encoding: 'utf-8', encoding: 'utf-8',
windowsHide: true windowsHide: true
@@ -97,11 +100,10 @@ export async function ensureWorkerRunning(): Promise<void> {
if (!started) { if (!started) {
const port = getWorkerPort(); const port = getWorkerPort();
const pluginRoot = getPackageRoot();
throw new Error( throw new Error(
`Worker service failed to start on port ${port}.\n\n` + `Worker service failed to start on port ${port}.\n\n` +
`To start manually, run:\n` + `To start manually, run:\n` +
` cd ${pluginRoot}\n` + ` cd ${MARKETPLACE_ROOT}\n` +
` npx pm2 start ecosystem.config.cjs\n\n` + ` npx pm2 start ecosystem.config.cjs\n\n` +
`If already running, try: npx pm2 restart claude-mem-worker` `If already running, try: npx pm2 restart claude-mem-worker`
); );