fix: update scripts and hooks for improved worker management and synchronization

This commit is contained in:
Alex Newman
2025-12-09 00:25:53 -05:00
parent 9a27f380c3
commit 5550ecf623
8 changed files with 63 additions and 20 deletions
+2 -1
View File
@@ -35,7 +35,8 @@
"test:parser": "npx tsx src/sdk/parser.test.ts", "test:parser": "npx tsx src/sdk/parser.test.ts",
"test:context": "echo '{\"session_id\":\"test-'$(date +%s)'\",\"cwd\":\"'$(pwd)'\",\"source\":\"startup\"}' | node plugin/scripts/context-hook.js 2>/dev/null", "test:context": "echo '{\"session_id\":\"test-'$(date +%s)'\",\"cwd\":\"'$(pwd)'\",\"source\":\"startup\"}' | node plugin/scripts/context-hook.js 2>/dev/null",
"test:context:verbose": "echo '{\"session_id\":\"test-'$(date +%s)'\",\"cwd\":\"'$(pwd)'\",\"source\":\"startup\"}' | node plugin/scripts/context-hook.js", "test:context:verbose": "echo '{\"session_id\":\"test-'$(date +%s)'\",\"cwd\":\"'$(pwd)'\",\"source\":\"startup\"}' | node plugin/scripts/context-hook.js",
"sync-marketplace": "rsync -av --delete --exclude=.git ./ ~/.claude/plugins/marketplaces/thedotmack/ && cd ~/.claude/plugins/marketplaces/thedotmack/ && npm install", "sync-marketplace": "node scripts/sync-marketplace.cjs",
"sync-marketplace:force": "node scripts/sync-marketplace.cjs --force",
"worker:start": "pm2 start ecosystem.config.cjs", "worker:start": "pm2 start ecosystem.config.cjs",
"worker:stop": "pm2 stop claude-mem-worker", "worker:stop": "pm2 stop claude-mem-worker",
"worker:restart": "pm2 restart claude-mem-worker", "worker:restart": "pm2 restart claude-mem-worker",
+2 -2
View File
@@ -8,12 +8,12 @@
{ {
"type": "command", "type": "command",
"command": "node \"${CLAUDE_PLUGIN_ROOT}/../scripts/smart-install.js\" && node ${CLAUDE_PLUGIN_ROOT}/scripts/context-hook.js", "command": "node \"${CLAUDE_PLUGIN_ROOT}/../scripts/smart-install.js\" && node ${CLAUDE_PLUGIN_ROOT}/scripts/context-hook.js",
"timeout": 5 "timeout": 300
}, },
{ {
"type": "command", "type": "command",
"command": "node ${CLAUDE_PLUGIN_ROOT}/scripts/user-message-hook.js", "command": "node ${CLAUDE_PLUGIN_ROOT}/scripts/user-message-hook.js",
"timeout": 5 "timeout": 10
} }
] ]
} }
+10 -4
View File
@@ -1,5 +1,11 @@
#!/usr/bin/env node #!/usr/bin/env node
import{stdin as S}from"process";import h from"path";import{homedir as y}from"os";import{join as o,dirname as C,basename as v}from"path";import{homedir as g}from"os";import{fileURLToPath as D}from"url";function M(){return typeof __dirname<"u"?__dirname:C(D(import.meta.url))}var H=M(),s=process.env.CLAUDE_MEM_DATA_DIR||o(g(),".claude-mem"),l=process.env.CLAUDE_CONFIG_DIR||o(g(),".claude"),X=o(s,"archives"),B=o(s,"logs"),V=o(s,"trash"),$=o(s,"backups"),j=o(s,"settings.json"),G=o(s,"claude-mem.db"),K=o(s,"vector-db"),Y=o(l,"settings.json"),J=o(l,"commands"),q=o(l,"CLAUDE.md");import{readFileSync as R,existsSync as U}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 m=N.join(","),d=L.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:m,CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS:d,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(!U(t))return this.getAllDefaults();let r=R(t,"utf-8"),n=JSON.parse(r).env||{},i={...this.DEFAULTS};for(let _ of Object.keys(this.DEFAULTS))n[_]!==void 0&&(i[_]=n[_]);return i}};function O(){let e=h.join(y(),".claude-mem","settings.json"),t=p.loadFromFile(e);return parseInt(t.CLAUDE_MEM_WORKER_PORT,10)}import{appendFileSync as I}from"fs";import{homedir as x}from"os";import{join as P}from"path";var k=P(x(),".claude-mem","silent.log");function c(e,t,r=""){let a=new Date().toISOString(),u=((new Error().stack||"").split(` import{stdin as d}from"process";import m from"path";import{homedir as k}from"os";import{spawnSync as w}from"child_process";import{join as r,dirname as L,basename as j}from"path";import{homedir as O}from"os";import{fileURLToPath as R}from"url";function U(){return typeof __dirname<"u"?__dirname:L(R(import.meta.url))}var h=U(),a=process.env.CLAUDE_MEM_DATA_DIR||r(O(),".claude-mem"),S=process.env.CLAUDE_CONFIG_DIR||r(O(),".claude"),J=r(a,"archives"),q=r(a,"logs"),z=r(a,"trash"),Q=r(a,"backups"),Z=r(a,"settings.json"),tt=r(a,"claude-mem.db"),et=r(a,"vector-db"),ot=r(S,"settings.json"),rt=r(S,"commands"),nt=r(S,"CLAUDE.md");function g(){return r(h,"..","..")}import{readFileSync as x,existsSync as P}from"fs";var y=["bugfix","feature","refactor","discovery","decision","change"],I=["how-it-works","why-it-exists","what-changed","problem-solution","gotcha","pattern","trade-off"];var f=y.join(","),A=I.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(!P(t))return this.getAllDefaults();let o=x(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 v=100,b=500,W=10;function T(){let e=m.join(k(),".claude-mem","settings.json"),t=u.loadFromFile(e);return parseInt(t.CLAUDE_MEM_WORKER_PORT,10)}async function C(){try{let e=T();return(await fetch(`http://127.0.0.1:${e}/health`,{signal:AbortSignal.timeout(v)})).ok}catch{return!1}}async function F(){try{let e=g(),t=m.join(e,"ecosystem.config.cjs");if(!existsSync(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=existsSync(i)?i:"pm2",s=w(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<W;c++)if(await new Promise(_=>setTimeout(_,b)),await C())return!0;return!1}catch{return!1}}async function D(){if(await C())return;if(!await F()){let t=T(),o=g();throw new Error(`Worker service failed to start on port ${t}.
`)[2]||"").match(/at\s+(?:.*\s+)?\(?([^:]+):(\d+):(\d+)\)?/),A=u?`${u[1].split("/").pop()}:${u[2]}`:"unknown",E=`[${a}] [${A}] ${e}`;if(t!==void 0)try{E+=` ${JSON.stringify(t)}`}catch(T){E+=` [stringify error: ${T}]`}E+=`
`;try{I(k,E)}catch(T){console.error("[silent-debug] Failed to write to log:",T)}return r}async function f(e){c("[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(` To start manually, run:
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:r}=e,a=O();try{let n=await fetch(`http://127.0.0.1:${a}/api/sessions/complete`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({claudeSessionId:t,reason:r}),signal:AbortSignal.timeout(2e3)});if(n.ok){let i=await n.json();c("[cleanup-hook] Session cleanup completed",i)}else c("[cleanup-hook] Session not found or already cleaned up")}catch(n){c("[cleanup-hook] Worker not reachable (non-critical)",{error:n.message})}console.log('{"continue": true, "suppressOutput": true}'),process.exit(0)}if(S.isTTY)f(void 0);else{let e="";S.on("data",t=>e+=t),S.on("end",async()=>{let t=e?JSON.parse(e):void 0;await f(t)})} cd ${o}
npx pm2 start ecosystem.config.cjs
If already running, try: npx pm2 restart claude-mem-worker`)}}import{appendFileSync as H}from"fs";import{homedir as X}from"os";import{join as B}from"path";var V=B(X(),".claude-mem","silent.log");function E(e,t,o=""){let i=new Date().toISOString(),_=((new Error().stack||"").split(`
`)[2]||"").match(/at\s+(?:.*\s+)?\(?([^:]+):(\d+):(\d+)\)?/),N=_?`${_[1].split("/").pop()}:${_[2]}`:"unknown",p=`[${i}] [${N}] ${e}`;if(t!==void 0)try{p+=` ${JSON.stringify(t)}`}catch(l){p+=` [stringify error: ${l}]`}p+=`
`;try{H(V,p)}catch(l){console.error("[silent-debug] Failed to write to log:",l)}return o}async function M(e){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(`
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;await D();let 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)M(void 0);else{let e="";d.on("data",t=>e+=t),d.on("end",async()=>{let t=e?JSON.parse(e):void 0;await M(t)})}
+14 -8
View File
@@ -1,5 +1,11 @@
#!/usr/bin/env node #!/usr/bin/env node
import{join as O,basename as x}from"path";import{homedir as P}from"os";import{existsSync as k}from"fs";import I from"path";import{homedir as w}from"os";import{join as e,dirname as M,basename as X}from"path";import{homedir as l}from"os";import{fileURLToPath as h}from"url";function N(){return typeof __dirname<"u"?__dirname:M(h(import.meta.url))}var G=N(),s=process.env.CLAUDE_MEM_DATA_DIR||e(l(),".claude-mem"),E=process.env.CLAUDE_CONFIG_DIR||e(l(),".claude"),K=e(s,"archives"),Y=e(s,"logs"),$=e(s,"trash"),q=e(s,"backups"),J=e(s,"settings.json"),Z=e(s,"claude-mem.db"),z=e(s,"vector-db"),Q=e(E,"settings.json"),tt=e(E,"commands"),et=e(E,"CLAUDE.md");import{readFileSync as R,existsSync as y}from"fs";var U=["bugfix","feature","refactor","discovery","decision","change"],L=["how-it-works","why-it-exists","what-changed","problem-solution","gotcha","pattern","trade-off"];var S=U.join(","),d=L.join(",");var c=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:S,CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS:d,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(!y(t))return this.getAllDefaults();let r=R(t,"utf-8"),o=JSON.parse(r).env||{},a={...this.DEFAULTS};for(let i of Object.keys(this.DEFAULTS))o[i]!==void 0&&(a[i]=o[i]);return a}};function g(){let n=I.join(w(),".claude-mem","settings.json"),t=c.loadFromFile(n);return parseInt(t.CLAUDE_MEM_WORKER_PORT,10)}var v=O(P(),".claude","plugins","marketplaces","thedotmack"),b=O(v,"node_modules");k(b)||(console.error(` import{join as D,basename as V}from"path";import{homedir as B}from"os";import{existsSync as j}from"fs";import l from"path";import{homedir as v}from"os";import{spawnSync as b}from"child_process";import{join as r,dirname as L,basename as J}from"path";import{homedir as g}from"os";import{fileURLToPath as R}from"url";function y(){return typeof __dirname<"u"?__dirname:L(R(import.meta.url))}var I=y(),a=process.env.CLAUDE_MEM_DATA_DIR||r(g(),".claude-mem"),p=process.env.CLAUDE_CONFIG_DIR||r(g(),".claude"),tt=r(a,"archives"),et=r(a,"logs"),ot=r(a,"trash"),rt=r(a,"backups"),nt=r(a,"settings.json"),st=r(a,"claude-mem.db"),it=r(a,"vector-db"),at=r(p,"settings.json"),ct=r(p,"commands"),_t=r(p,"CLAUDE.md");function m(){return r(I,"..","..")}import{readFileSync as P,existsSync as k}from"fs";var w=["bugfix","feature","refactor","discovery","decision","change"],x=["how-it-works","why-it-exists","what-changed","problem-solution","gotcha","pattern","trade-off"];var O=w.join(","),f=x.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(!k(t))return this.getAllDefaults();let o=P(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 W=100,H=500,F=10;function u(){let e=l.join(v(),".claude-mem","settings.json"),t=E.loadFromFile(e);return parseInt(t.CLAUDE_MEM_WORKER_PORT,10)}async function A(){try{let e=u();return(await fetch(`http://127.0.0.1:${e}/health`,{signal:AbortSignal.timeout(W)})).ok}catch{return!1}}async function X(){try{let e=m(),t=l.join(e,"ecosystem.config.cjs");if(!existsSync(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=existsSync(c)?c:"pm2",i=b(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<F;s++)if(await new Promise(_=>setTimeout(_,H)),await A())return!0;return!1}catch{return!1}}async function C(){if(await A())return;if(!await X()){let t=u(),o=m();throw new Error(`Worker service failed to start on port ${t}.
To start manually, run:
cd ${o}
npx pm2 start ecosystem.config.cjs
If already running, try: npx pm2 restart claude-mem-worker`)}}var G=D(B(),".claude","plugins","marketplaces","thedotmack"),K=D(G,"node_modules");j(K)||(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.
@@ -17,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{let n=g(),t=x(process.cwd()),r=await fetch(`http://127.0.0.1:${n}/api/context/inject?project=${encodeURIComponent(t)}&colors=true`,{method:"GET",signal:AbortSignal.timeout(5e3)});if(!r.ok)throw new Error(`Worker error ${r.status}`);let u=await r.text(),o=new Date,a=new Date("2025-12-06T00:00:00Z"),i=new Date("2025-12-05T05:00:00Z"),T="";o<i&&(T=` `),process.exit(3));try{await C();let e=u(),t=V(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&&(_=`
\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}
@@ -27,19 +33,19 @@ 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 _="";if(o<a){let f=o.getUTCHours()*60+o.getUTCMinutes(),p=Math.floor((f-300+1440)%1440/60),m=o.getUTCDate(),A=o.getUTCMonth(),C=o.getUTCFullYear()===2025&&A===11&&m>=1&&m<=5,D=p>=17&&p<19;C&&D?_=` `);let T="";if(n<i){let M=n.getUTCHours()*60+n.getUTCMinutes(),S=Math.floor((M-300+1440)%1440/60),d=n.getUTCDate(),h=n.getUTCMonth(),N=n.getUTCFullYear()===2025&&h===11&&d>=1&&d<=5,U=S>=17&&S<19;N&&U?T=`
\u{1F534} LIVE NOW: AMA w/ Dev (@thedotmack) until 7pm EST \u{1F534} LIVE NOW: AMA w/ Dev (@thedotmack) until 7pm EST
`:_=` `: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
`}console.error(` `}console.error(`
\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
`+u+` `+c+`
\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`+_+T+`
\u{1F4FA} Watch live in browser http://localhost:${n}/ \u{1F4FA} Watch live in browser http://localhost:${e}/
`)}catch(n){console.error(`\u274C Failed to load context display: ${n}`)}process.exit(3); `)}catch(e){console.error(`\u274C Failed to load context display: ${e}`)}process.exit(3);
+1 -1
View File
@@ -387,7 +387,7 @@ async function main() {
} catch (error) { } catch (error) {
// Worker might already be running or PM2 not available - that's okay // Worker might already be running or PM2 not available - that's okay
// The ensureWorkerRunning() function will handle auto-start when needed // The ensureWorkerRunning() function will handle auto-start when needed
log('️ Worker startup error', colors.dim); log(' Worker will start automatically when needed', colors.dim);
} }
// Success - dependencies installed (if needed) // Success - dependencies installed (if needed)
+26 -2
View File
@@ -7,11 +7,12 @@
*/ */
const { execSync } = require('child_process'); const { execSync } = require('child_process');
const { existsSync } = require('fs'); const { existsSync, readFileSync } = require('fs');
const path = require('path'); const path = require('path');
const os = require('os'); const os = require('os');
const INSTALLED_PATH = path.join(os.homedir(), '.claude', 'plugins', 'marketplaces', 'thedotmack'); const INSTALLED_PATH = path.join(os.homedir(), '.claude', 'plugins', 'marketplaces', 'thedotmack');
const CACHE_BASE_PATH = path.join(os.homedir(), '.claude', 'plugins', 'cache', 'thedotmack', 'claude-mem');
function getCurrentBranch() { function getCurrentBranch() {
try { try {
@@ -29,8 +30,9 @@ function getCurrentBranch() {
} }
const branch = getCurrentBranch(); const branch = getCurrentBranch();
const isForce = process.argv.includes('--force');
if (branch && branch !== 'main') { if (branch && branch !== 'main' && !isForce) {
console.log(''); console.log('');
console.log('\x1b[33m%s\x1b[0m', `WARNING: Installed plugin is on beta branch: ${branch}`); console.log('\x1b[33m%s\x1b[0m', `WARNING: Installed plugin is on beta branch: ${branch}`);
console.log('\x1b[33m%s\x1b[0m', 'Running rsync would overwrite beta code.'); console.log('\x1b[33m%s\x1b[0m', 'Running rsync would overwrite beta code.');
@@ -43,6 +45,18 @@ if (branch && branch !== 'main') {
process.exit(1); process.exit(1);
} }
// Get version from plugin.json
function getPluginVersion() {
try {
const pluginJsonPath = path.join(__dirname, '..', 'plugin', '.claude-plugin', 'plugin.json');
const pluginJson = JSON.parse(readFileSync(pluginJsonPath, 'utf-8'));
return pluginJson.version;
} catch (error) {
console.error('\x1b[31m%s\x1b[0m', 'Failed to read plugin version:', error.message);
process.exit(1);
}
}
// Normal rsync for main branch or fresh install // Normal rsync for main branch or fresh install
console.log('Syncing to marketplace...'); console.log('Syncing to marketplace...');
try { try {
@@ -57,6 +71,16 @@ try {
{ stdio: 'inherit' } { stdio: 'inherit' }
); );
// Sync to cache folder with version
const version = getPluginVersion();
const CACHE_VERSION_PATH = path.join(CACHE_BASE_PATH, version);
console.log(`Syncing to cache folder (version ${version})...`);
execSync(
`rsync -av --delete --exclude=.git plugin/ "${CACHE_VERSION_PATH}/"`,
{ stdio: 'inherit' }
);
console.log('\x1b[32m%s\x1b[0m', 'Sync complete!'); console.log('\x1b[32m%s\x1b[0m', 'Sync complete!');
} catch (error) { } catch (error) {
console.error('\x1b[31m%s\x1b[0m', 'Sync failed:', error.message); console.error('\x1b[31m%s\x1b[0m', 'Sync failed:', error.message);
+4 -1
View File
@@ -7,7 +7,7 @@
*/ */
import { stdin } from 'process'; import { stdin } from 'process';
import { getWorkerPort } from '../shared/worker-utils.js'; import { ensureWorkerRunning, getWorkerPort } from '../shared/worker-utils.js';
import { silentDebug } from '../utils/silent-debug.js'; import { silentDebug } from '../utils/silent-debug.js';
export interface SessionEndInput { export interface SessionEndInput {
@@ -44,6 +44,9 @@ async function cleanupHook(input?: SessionEndInput): Promise<void> {
const { session_id, reason } = input; const { session_id, reason } = input;
// Ensure worker is running
await ensureWorkerRunning();
const port = getWorkerPort(); const port = getWorkerPort();
try { try {
+4 -1
View File
@@ -9,7 +9,7 @@
import { join, basename } from "path"; import { join, basename } from "path";
import { homedir } from "os"; import { homedir } from "os";
import { existsSync } from "fs"; import { existsSync } from "fs";
import { getWorkerPort } from "../shared/worker-utils.js"; import { ensureWorkerRunning, getWorkerPort } from "../shared/worker-utils.js";
// Check if node_modules exists - if not, this is first run // Check if node_modules exists - if not, this is first run
const pluginDir = join(homedir(), '.claude', 'plugins', 'marketplaces', 'thedotmack'); const pluginDir = join(homedir(), '.claude', 'plugins', 'marketplaces', 'thedotmack');
@@ -40,6 +40,9 @@ This message was not added to your startup context, so you can continue working
} }
try { try {
// Ensure worker is running
await ensureWorkerRunning();
const port = getWorkerPort(); const port = getWorkerPort();
const project = basename(process.cwd()); const project = basename(process.cwd());