Files
claude-mem/plugin/scripts/cleanup-hook.js
T
Alex Newman fc5c2d5e07 Refactor settings management to use ~/.claude-mem/settings.json
- Updated paths in troubleshooting documentation to reflect new settings file location.
- Modified diagnostics and reference files to read from ~/.claude-mem/settings.json.
- Introduced getWorkerPort utility for cleaner worker port retrieval.
- Enhanced ChromaSync and SDKAgent to load Python version and Claude path from settings.
- Updated SettingsRoutes to validate new settings: CLAUDE_MEM_LOG_LEVEL and CLAUDE_MEM_PYTHON_VERSION.
- Added early-settings module to load settings for logger and other early-stage modules.
- Adjusted logger to use early-loaded log level setting.
- Refactored paths to utilize early-loaded data directory setting.
2025-12-09 12:23:33 -05:00

12 lines
4.6 KiB
JavaScript
Executable File

#!/usr/bin/env node
import{stdin as p}from"process";import a from"path";import{existsSync as u}from"fs";import{homedir as A}from"os";import{spawnSync as g}from"child_process";import{readFileSync as U,existsSync as h}from"fs";import{join as R}from"path";import{homedir as y}from"os";var N=["bugfix","feature","refactor","discovery","decision","change"],D=["how-it-works","why-it-exists","what-changed","problem-solution","gotcha","pattern","trade-off"];var d=N.join(","),f=D.join(",");var T=class{static DEFAULTS={CLAUDE_MEM_MODEL:"claude-haiku-4-5",CLAUDE_MEM_CONTEXT_OBSERVATIONS:"50",CLAUDE_MEM_WORKER_PORT:"37777",CLAUDE_MEM_DATA_DIR:R(y(),".claude-mem"),CLAUDE_MEM_LOG_LEVEL:"INFO",CLAUDE_MEM_PYTHON_VERSION:"3.13",CLAUDE_CODE_PATH:"",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:d,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 r=this.get(t);return parseInt(r,10)}static getBool(t){return this.get(t)==="true"}static loadFromFile(t){if(!h(t))return this.getAllDefaults();let r=U(t,"utf-8"),o=JSON.parse(r).env||{},i={...this.DEFAULTS};for(let _ of Object.keys(this.DEFAULTS))o[_]!==void 0&&(i[_]=o[_]);return i}};var n=a.join(A(),".claude","plugins","marketplaces","thedotmack"),I=500,w=1e3,P=15;function l(){let e=a.join(A(),".claude-mem","settings.json"),t=T.loadFromFile(e);return parseInt(t.CLAUDE_MEM_WORKER_PORT,10)}async function C(){try{let e=l();return(await fetch(`http://127.0.0.1:${e}/health`,{signal:AbortSignal.timeout(I)})).ok}catch{return!1}}async function k(){try{let e=a.join(n,"plugin","scripts","worker-service.cjs");if(!u(e))throw new Error(`Worker script not found at ${e}`);if(process.platform==="win32"){let t=g("powershell.exe",["-NoProfile","-NonInteractive","-Command",`Start-Process -FilePath 'node' -ArgumentList '${e}' -WorkingDirectory '${n}' -WindowStyle Hidden`],{cwd:n,stdio:"pipe",encoding:"utf-8",windowsHide:!0});if(t.status!==0)throw new Error(t.stderr||"PowerShell Start-Process failed")}else{let t=a.join(n,"ecosystem.config.cjs");if(!u(t))throw new Error(`Ecosystem config not found at ${t}`);let r=a.join(n,"node_modules",".bin","pm2"),s=u(r)?r:"pm2",o=g(s,["start",t],{cwd:n,stdio:"pipe",encoding:"utf-8"});if(o.status!==0)throw new Error(o.stderr||"PM2 start failed")}for(let t=0;t<P;t++)if(await new Promise(r=>setTimeout(r,w)),await C())return!0;return!1}catch{return!1}}async function M(){if(await C())return;if(!await k()){let t=l();throw new Error(`Worker service failed to start on port ${t}.
To start manually, run:
cd ${n}
npx pm2 start ecosystem.config.cjs
If already running, try: npx pm2 restart claude-mem-worker`)}}import{appendFileSync as W}from"fs";import{homedir as x}from"os";import{join as F}from"path";var b=F(x(),".claude-mem","silent.log");function E(e,t,r=""){let s=new Date().toISOString(),O=((new Error().stack||"").split(`
`)[2]||"").match(/at\s+(?:.*\s+)?\(?([^:]+):(\d+):(\d+)\)?/),L=O?`${O[1].split("/").pop()}:${O[2]}`:"unknown",c=`[${s}] [${L}] ${e}`;if(t!==void 0)try{c+=` ${JSON.stringify(t)}`}catch(S){c+=` [stringify error: ${S}]`}c+=`
`;try{W(b,c)}catch(S){console.error("[silent-debug] Failed to write to log:",S)}return r}async function m(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(`
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,s=l();try{let o=await fetch(`http://127.0.0.1:${s}/api/sessions/complete`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({claudeSessionId:t,reason:r}),signal:AbortSignal.timeout(2e3)});if(o.ok){let i=await o.json();E("[cleanup-hook] Session cleanup completed",i)}else E("[cleanup-hook] Session not found or already cleaned up")}catch(o){E("[cleanup-hook] Worker not reachable (non-critical)",{error:o.message})}console.log('{"continue": true, "suppressOutput": true}'),process.exit(0)}if(p.isTTY)m(void 0);else{let e="";p.on("data",t=>e+=t),p.on("end",async()=>{let t=e?JSON.parse(e):void 0;await m(t)})}