diff --git a/plugin/scripts/context-generator.cjs b/plugin/scripts/context-generator.cjs index c0a7b55d..f4264238 100644 --- a/plugin/scripts/context-generator.cjs +++ b/plugin/scripts/context-generator.cjs @@ -6,7 +6,7 @@ ${o.stack}`:` ${o.message}`:this.getLevel()===0&&typeof o=="object"?m=` `,"utf8")}catch(T){process.stderr.write(`[LOGGER] Failed to write to log file: ${T} `)}else process.stderr.write(E+` `)}debug(e,t,s,n){this.log(0,e,t,s,n)}info(e,t,s,n){this.log(1,e,t,s,n)}warn(e,t,s,n){this.log(2,e,t,s,n)}error(e,t,s,n){this.log(3,e,t,s,n)}dataIn(e,t,s,n){this.info(e,`\u2192 ${t}`,s,n)}dataOut(e,t,s,n){this.info(e,`\u2190 ${t}`,s,n)}success(e,t,s,n){this.info(e,`\u2713 ${t}`,s,n)}failure(e,t,s,n){this.error(e,`\u2717 ${t}`,s,n)}timing(e,t,s,n){this.info(e,`\u23F1 ${t}`,n,{duration:`${s}ms`})}happyPathError(e,t,s,n,o=""){let u=((new Error().stack||"").split(` -`)[2]||"").match(/at\s+(?:.*\s+)?\(?([^:]+):(\d+):(\d+)\)?/),m=u?`${u[1].split("/").pop()}:${u[2]}`:"unknown",l={...s,location:m};return this.warn(e,`[HAPPY-PATH] ${t}`,l,n),o}},_=new Z;var wt={};function kt(){return typeof __dirname<"u"?__dirname:(0,f.dirname)((0,Se.fileURLToPath)(wt.url))}var $t=kt();function Ft(){if(process.env.CLAUDE_MEM_DATA_DIR)return process.env.CLAUDE_MEM_DATA_DIR;let r=(0,f.join)((0,ee.homedir)(),".claude-mem"),e=(0,f.join)(r,"settings.json");try{if((0,P.existsSync)(e)){let{readFileSync:t}=require("fs"),s=JSON.parse(t(e,"utf-8")),n=s.env??s;if(n.CLAUDE_MEM_DATA_DIR)return n.CLAUDE_MEM_DATA_DIR}}catch{}return r}var N=Ft(),y=process.env.CLAUDE_CONFIG_DIR||(0,f.join)((0,ee.homedir)(),".claude"),os=(0,f.join)(y,"plugins","marketplaces","thedotmack"),is=(0,f.join)(N,"archives"),as=(0,f.join)(N,"logs"),ds=(0,f.join)(N,"trash"),cs=(0,f.join)(N,"backups"),us=(0,f.join)(N,"modes"),ms=(0,f.join)(N,"settings.json"),be=(0,f.join)(N,"claude-mem.db"),_s=(0,f.join)(N,"vector-db"),ps=(0,f.join)(N,"observer-sessions"),ls=(0,f.join)(y,"settings.json"),Es=(0,f.join)(y,"commands"),gs=(0,f.join)(y,"CLAUDE.md");function he(r){(0,P.mkdirSync)(r,{recursive:!0})}function Oe(){return(0,f.join)($t,"..")}var Ae=require("crypto");var Pt=3e4;function j(r,e,t){return(0,Ae.createHash)("sha256").update([r||"",e||"",t||""].join("\0")).digest("hex").slice(0,16)}function H(r,e,t){let s=t-Pt;return r.prepare("SELECT id, created_at_epoch FROM observations WHERE content_hash = ? AND created_at_epoch > ?").get(e,s)}function te(r){if(!r)return[];try{let e=JSON.parse(r);return Array.isArray(e)?e:[String(e)]}catch{return[r]}}var h="claude";function jt(r){return r.trim().toLowerCase().replace(/\s+/g,"-")}function D(r){if(!r)return h;let e=jt(r);return e?e==="transcript"||e.includes("codex")?"codex":e.includes("cursor")?"cursor":e.includes("claude")?"claude":e:h}function Re(r){let e=["claude","codex","cursor"];return[...r].sort((t,s)=>{let n=e.indexOf(t),o=e.indexOf(s);return n!==-1||o!==-1?n===-1?1:o===-1?-1:n-o:t.localeCompare(s)})}function Ht(r,e){return{customTitle:r,platformSource:e?D(e):void 0}}var X=class{db;constructor(e=be){e!==":memory:"&&he(N),this.db=new Ne.Database(e),this.db.run("PRAGMA journal_mode = WAL"),this.db.run("PRAGMA synchronous = NORMAL"),this.db.run("PRAGMA foreign_keys = ON"),this.initializeSchema(),this.ensureWorkerPortColumn(),this.ensurePromptTrackingColumns(),this.removeSessionSummariesUniqueConstraint(),this.addObservationHierarchicalFields(),this.makeObservationsTextNullable(),this.createUserPromptsTable(),this.ensureDiscoveryTokensColumn(),this.createPendingMessagesTable(),this.renameSessionIdColumns(),this.repairSessionIdColumnRename(),this.addFailedAtEpochColumn(),this.addOnUpdateCascadeToForeignKeys(),this.addObservationContentHashColumn(),this.addSessionCustomTitleColumn(),this.addSessionPlatformSourceColumn(),this.addObservationModelColumns()}initializeSchema(){this.db.run(` +`)[2]||"").match(/at\s+(?:.*\s+)?\(?([^:]+):(\d+):(\d+)\)?/),m=u?`${u[1].split("/").pop()}:${u[2]}`:"unknown",l={...s,location:m};return this.warn(e,`[HAPPY-PATH] ${t}`,l,n),o}},_=new Z;var wt={};function kt(){return typeof __dirname<"u"?__dirname:(0,f.dirname)((0,Se.fileURLToPath)(wt.url))}var $t=kt();function Ft(){if(process.env.CLAUDE_MEM_DATA_DIR)return process.env.CLAUDE_MEM_DATA_DIR;let r=(0,f.join)((0,ee.homedir)(),".claude-mem"),e=(0,f.join)(r,"settings.json");try{if((0,P.existsSync)(e)){let{readFileSync:t}=require("fs"),s=JSON.parse(t(e,"utf-8")),n=s.env??s;if(n.CLAUDE_MEM_DATA_DIR)return n.CLAUDE_MEM_DATA_DIR}}catch{}return r}var N=Ft(),y=process.env.CLAUDE_CONFIG_DIR||(0,f.join)((0,ee.homedir)(),".claude"),os=(0,f.join)(y,"plugins","marketplaces","thedotmack"),is=(0,f.join)(N,"archives"),as=(0,f.join)(N,"logs"),ds=(0,f.join)(N,"trash"),cs=(0,f.join)(N,"backups"),us=(0,f.join)(N,"modes"),ms=(0,f.join)(N,"settings.json"),be=(0,f.join)(N,"claude-mem.db"),_s=(0,f.join)(N,"vector-db"),ps=(0,f.join)(N,"observer-sessions"),ls=(0,f.join)(y,"settings.json"),Es=(0,f.join)(y,"commands"),gs=(0,f.join)(y,"CLAUDE.md");function he(r){(0,P.mkdirSync)(r,{recursive:!0})}function Oe(){return(0,f.join)($t,"..")}var Ae=require("crypto");var Pt=3e4;function H(r,e,t){return(0,Ae.createHash)("sha256").update([r||"",e||"",t||""].join("\0")).digest("hex").slice(0,16)}function j(r,e,t){let s=t-Pt;return r.prepare("SELECT id, created_at_epoch FROM observations WHERE content_hash = ? AND created_at_epoch > ?").get(e,s)}function te(r){if(!r)return[];try{let e=JSON.parse(r);return Array.isArray(e)?e:[String(e)]}catch{return[r]}}var h="claude";function Ht(r){return r.trim().toLowerCase().replace(/\s+/g,"-")}function D(r){if(!r)return h;let e=Ht(r);return e?e==="transcript"||e.includes("codex")?"codex":e.includes("cursor")?"cursor":e.includes("claude")?"claude":e:h}function Re(r){let e=["claude","codex","cursor"];return[...r].sort((t,s)=>{let n=e.indexOf(t),o=e.indexOf(s);return n!==-1||o!==-1?n===-1?1:o===-1?-1:n-o:t.localeCompare(s)})}function jt(r,e){return{customTitle:r,platformSource:e?D(e):void 0}}var X=class{db;constructor(e=be){e!==":memory:"&&he(N),this.db=new Ne.Database(e),this.db.run("PRAGMA journal_mode = WAL"),this.db.run("PRAGMA synchronous = NORMAL"),this.db.run("PRAGMA foreign_keys = ON"),this.initializeSchema(),this.ensureWorkerPortColumn(),this.ensurePromptTrackingColumns(),this.removeSessionSummariesUniqueConstraint(),this.addObservationHierarchicalFields(),this.makeObservationsTextNullable(),this.createUserPromptsTable(),this.ensureDiscoveryTokensColumn(),this.createPendingMessagesTable(),this.renameSessionIdColumns(),this.repairSessionIdColumnRename(),this.addFailedAtEpochColumn(),this.addOnUpdateCascadeToForeignKeys(),this.addObservationContentHashColumn(),this.addSessionCustomTitleColumn(),this.addSessionPlatformSourceColumn(),this.addObservationModelColumns()}initializeSchema(){this.db.run(` CREATE TABLE IF NOT EXISTS schema_versions ( id INTEGER PRIMARY KEY, version INTEGER UNIQUE NOT NULL, @@ -461,7 +461,7 @@ ${o.stack}`:` ${o.message}`:this.getLevel()===0&&typeof o=="object"?m=` ORDER BY started_at_epoch DESC `).all(...e)}getPromptNumberFromUserPrompts(e){return this.db.prepare(` SELECT COUNT(*) as count FROM user_prompts WHERE content_session_id = ? - `).get(e).count}createSDKSession(e,t,s,n,o){let i=new Date,a=i.getTime(),d=Ht(n,o),u=d.platformSource??h,m=this.db.prepare(` + `).get(e).count}createSDKSession(e,t,s,n,o){let i=new Date,a=i.getTime(),d=jt(n,o),u=d.platformSource??h,m=this.db.prepare(` SELECT id, platform_source FROM sdk_sessions WHERE content_session_id = ? `).get(e);if(m){if(t&&this.db.prepare(` UPDATE sdk_sessions SET project = ? @@ -486,7 +486,7 @@ ${o.stack}`:` ${o.message}`:this.getLevel()===0&&typeof o=="object"?m=` FROM user_prompts WHERE content_session_id = ? AND prompt_number = ? LIMIT 1 - `).get(e,t)?.prompt_text??null}storeObservation(e,t,s,n,o=0,i,a){let d=i??Date.now(),u=new Date(d).toISOString(),m=j(e,s.title,s.narrative),l=H(this.db,m,d);if(l)return{id:l.id,createdAtEpoch:l.created_at_epoch};let T=this.db.prepare(` + `).get(e,t)?.prompt_text??null}storeObservation(e,t,s,n,o=0,i,a){let d=i??Date.now(),u=new Date(d).toISOString(),m=H(e,s.title,s.narrative),l=j(this.db,m,d);if(l)return{id:l.id,createdAtEpoch:l.created_at_epoch};let T=this.db.prepare(` INSERT INTO observations (memory_session_id, project, type, title, subtitle, facts, narrative, concepts, files_read, files_modified, prompt_number, discovery_tokens, content_hash, created_at, created_at_epoch, @@ -503,7 +503,7 @@ ${o.stack}`:` ${o.message}`:this.getLevel()===0&&typeof o=="object"?m=` files_read, files_modified, prompt_number, discovery_tokens, content_hash, created_at, created_at_epoch, generated_by_model) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) - `);for(let S of s){let p=j(e,S.title,S.narrative),R=H(this.db,p,u);if(R){E.push(R.id);continue}let g=T.run(e,t,S.type,S.title,S.subtitle,JSON.stringify(S.facts),S.narrative,JSON.stringify(S.concepts),JSON.stringify(S.files_read),JSON.stringify(S.files_modified),o||null,i,p,m,u,d||null);E.push(Number(g.lastInsertRowid))}let O=null;if(n){let p=this.db.prepare(` + `);for(let S of s){let p=H(e,S.title,S.narrative),R=j(this.db,p,u);if(R){E.push(R.id);continue}let g=T.run(e,t,S.type,S.title,S.subtitle,JSON.stringify(S.facts),S.narrative,JSON.stringify(S.concepts),JSON.stringify(S.files_read),JSON.stringify(S.files_modified),o||null,i,p,m,u,d||null);E.push(Number(g.lastInsertRowid))}let O=null;if(n){let p=this.db.prepare(` INSERT INTO session_summaries (memory_session_id, project, request, investigated, learned, completed, next_steps, notes, prompt_number, discovery_tokens, created_at, created_at_epoch) @@ -514,7 +514,7 @@ ${o.stack}`:` ${o.message}`:this.getLevel()===0&&typeof o=="object"?m=` files_read, files_modified, prompt_number, discovery_tokens, content_hash, created_at, created_at_epoch, generated_by_model) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) - `);for(let g of s){let b=j(e,g.title,g.narrative),Ee=H(this.db,b,l);if(Ee){O.push(Ee.id);continue}let It=S.run(e,t,g.type,g.title,g.subtitle,JSON.stringify(g.facts),g.narrative,JSON.stringify(g.concepts),JSON.stringify(g.files_read),JSON.stringify(g.files_modified),a||null,d,b,E,l,m||null);O.push(Number(It.lastInsertRowid))}let p;if(n){let b=this.db.prepare(` + `);for(let g of s){let b=H(e,g.title,g.narrative),Ee=j(this.db,b,l);if(Ee){O.push(Ee.id);continue}let It=S.run(e,t,g.type,g.title,g.subtitle,JSON.stringify(g.facts),g.narrative,JSON.stringify(g.concepts),JSON.stringify(g.files_read),JSON.stringify(g.files_modified),a||null,d,b,E,l,m||null);O.push(Number(It.lastInsertRowid))}let p;if(n){let b=this.db.prepare(` INSERT INTO session_summaries (memory_session_id, project, request, investigated, learned, completed, next_steps, notes, prompt_number, discovery_tokens, created_at, created_at_epoch) @@ -654,7 +654,7 @@ ${o.stack}`:` ${o.message}`:this.getLevel()===0&&typeof o=="object"?m=` content_session_id, prompt_number, prompt_text, created_at, created_at_epoch ) VALUES (?, ?, ?, ?, ?) - `).run(e.content_session_id,e.prompt_number,e.prompt_text,e.created_at,e.created_at_epoch).lastInsertRowid}}};var Ie=require("os"),Le=L(require("path"),1);var B=require("fs"),G=L(require("path"),1),v={isWorktree:!1,worktreeName:null,parentRepoPath:null,parentProjectName:null};function Ce(r){let e=G.default.join(r,".git"),t;try{t=(0,B.statSync)(e)}catch{return v}if(!t.isFile())return v;let s;try{s=(0,B.readFileSync)(e,"utf-8").trim()}catch{return v}let n=s.match(/^gitdir:\s*(.+)$/);if(!n)return v;let i=n[1].match(/^(.+)[/\\]\.git[/\\]worktrees[/\\]([^/\\]+)$/);if(!i)return v;let a=i[1],d=G.default.basename(r),u=G.default.basename(a);return{isWorktree:!0,worktreeName:d,parentRepoPath:a,parentProjectName:u}}function ye(r){return r==="~"||r.startsWith("~/")?r.replace(/^~/,(0,Ie.homedir)()):r}function Xt(r){if(!r||r.trim()==="")return _.warn("PROJECT_NAME","Empty cwd provided, using fallback",{cwd:r}),"unknown-project";let e=ye(r),t=Le.default.basename(e);if(t===""){if(process.platform==="win32"){let n=r.match(/^([A-Z]):\\/i);if(n){let i=`drive-${n[1].toUpperCase()}`;return _.info("PROJECT_NAME","Drive root detected",{cwd:r,projectName:i}),i}}return _.warn("PROJECT_NAME","Root directory detected, using fallback",{cwd:r}),"unknown-project"}return t}function De(r){let e=Xt(r);if(!r)return{primary:e,parent:null,isWorktree:!1,allProjects:[e]};let t=ye(r),s=Ce(t);if(s.isWorktree&&s.parentProjectName){let n=Array.from(new Set([s.parentProjectName,e]));return{primary:s.parentProjectName,parent:s.parentProjectName,isWorktree:!0,allProjects:n}}return{primary:e,parent:null,isWorktree:!1,allProjects:[e]}}var Me=L(require("path"),1),ve=require("os");var C=require("fs"),U=require("path"),se=require("os"),W=class{static DEFAULTS={CLAUDE_MEM_MODEL:"claude-sonnet-4-6",CLAUDE_MEM_CONTEXT_OBSERVATIONS:"50",CLAUDE_MEM_WORKER_PORT:"37777",CLAUDE_MEM_WORKER_HOST:"127.0.0.1",CLAUDE_MEM_SKIP_TOOLS:"ListMcpResourcesTool,SlashCommand,Skill,TodoWrite,AskUserQuestion",CLAUDE_MEM_PROVIDER:"claude",CLAUDE_MEM_CLAUDE_AUTH_METHOD:"cli",CLAUDE_MEM_GEMINI_API_KEY:"",CLAUDE_MEM_GEMINI_MODEL:"gemini-2.5-flash-lite",CLAUDE_MEM_GEMINI_RATE_LIMITING_ENABLED:"true",CLAUDE_MEM_GEMINI_MAX_CONTEXT_MESSAGES:"20",CLAUDE_MEM_GEMINI_MAX_TOKENS:"100000",CLAUDE_MEM_OPENROUTER_API_KEY:"",CLAUDE_MEM_OPENROUTER_MODEL:"xiaomi/mimo-v2-flash:free",CLAUDE_MEM_OPENROUTER_SITE_URL:"",CLAUDE_MEM_OPENROUTER_APP_NAME:"claude-mem",CLAUDE_MEM_OPENROUTER_MAX_CONTEXT_MESSAGES:"20",CLAUDE_MEM_OPENROUTER_MAX_TOKENS:"100000",CLAUDE_MEM_DATA_DIR:(0,U.join)((0,se.homedir)(),".claude-mem"),CLAUDE_MEM_LOG_LEVEL:"INFO",CLAUDE_MEM_PYTHON_VERSION:"3.13",CLAUDE_CODE_PATH:"",CLAUDE_MEM_MODE:"code",CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS:"false",CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS:"false",CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT:"false",CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT:"true",CLAUDE_MEM_CONTEXT_FULL_COUNT:"0",CLAUDE_MEM_CONTEXT_FULL_FIELD:"narrative",CLAUDE_MEM_CONTEXT_SESSION_COUNT:"10",CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY:"true",CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE:"false",CLAUDE_MEM_CONTEXT_SHOW_TERMINAL_OUTPUT:"true",CLAUDE_MEM_FOLDER_CLAUDEMD_ENABLED:"false",CLAUDE_MEM_FOLDER_USE_LOCAL_MD:"false",CLAUDE_MEM_TRANSCRIPTS_ENABLED:"true",CLAUDE_MEM_TRANSCRIPTS_CONFIG_PATH:(0,U.join)((0,se.homedir)(),".claude-mem","transcript-watch.json"),CLAUDE_MEM_MAX_CONCURRENT_AGENTS:"2",CLAUDE_MEM_EXCLUDED_PROJECTS:"",CLAUDE_MEM_FOLDER_MD_EXCLUDE:"[]",CLAUDE_MEM_SEMANTIC_INJECT:"false",CLAUDE_MEM_SEMANTIC_INJECT_LIMIT:"5",CLAUDE_MEM_TIER_ROUTING_ENABLED:"true",CLAUDE_MEM_TIER_SIMPLE_MODEL:"haiku",CLAUDE_MEM_TIER_SUMMARY_MODEL:"",CLAUDE_MEM_CHROMA_ENABLED:"true",CLAUDE_MEM_CHROMA_MODE:"local",CLAUDE_MEM_CHROMA_HOST:"127.0.0.1",CLAUDE_MEM_CHROMA_PORT:"8000",CLAUDE_MEM_CHROMA_SSL:"false",CLAUDE_MEM_CHROMA_API_KEY:"",CLAUDE_MEM_CHROMA_TENANT:"default_tenant",CLAUDE_MEM_CHROMA_DATABASE:"default_database"};static getAllDefaults(){return{...this.DEFAULTS}}static get(e){return process.env[e]??this.DEFAULTS[e]}static getInt(e){let t=this.get(e);return parseInt(t,10)}static getBool(e){let t=this.get(e);return t==="true"||t===!0}static applyEnvOverrides(e){let t={...e};for(let s of Object.keys(this.DEFAULTS))process.env[s]!==void 0&&(t[s]=process.env[s]);return t}static loadFromFile(e){try{if(!(0,C.existsSync)(e)){let i=this.getAllDefaults();try{let a=(0,U.dirname)(e);(0,C.existsSync)(a)||(0,C.mkdirSync)(a,{recursive:!0}),(0,C.writeFileSync)(e,JSON.stringify(i,null,2),"utf-8"),console.log("[SETTINGS] Created settings file with defaults:",e)}catch(a){console.warn("[SETTINGS] Failed to create settings file, using in-memory defaults:",e,a)}return this.applyEnvOverrides(i)}let t=(0,C.readFileSync)(e,"utf-8"),s=JSON.parse(t),n=s;if(s.env&&typeof s.env=="object"){n=s.env;try{(0,C.writeFileSync)(e,JSON.stringify(n,null,2),"utf-8"),console.log("[SETTINGS] Migrated settings file from nested to flat schema:",e)}catch(i){console.warn("[SETTINGS] Failed to auto-migrate settings file:",e,i)}}let o={...this.DEFAULTS};for(let i of Object.keys(this.DEFAULTS))n[i]!==void 0&&(o[i]=n[i]);return this.applyEnvOverrides(o)}catch(t){return console.warn("[SETTINGS] Failed to load settings, using defaults:",e,t),this.applyEnvOverrides(this.getAllDefaults())}}};var x=require("fs"),Y=require("path");var A=class r{static instance=null;activeMode=null;modesDir;constructor(){let e=Oe(),t=[(0,Y.join)(e,"modes"),(0,Y.join)(e,"..","plugin","modes")],s=t.find(n=>(0,x.existsSync)(n));this.modesDir=s||t[0]}static getInstance(){return r.instance||(r.instance=new r),r.instance}parseInheritance(e){let t=e.split("--");if(t.length===1)return{hasParent:!1,parentId:"",overrideId:""};if(t.length>2)throw new Error(`Invalid mode inheritance: ${e}. Only one level of inheritance supported (parent--override)`);return{hasParent:!0,parentId:t[0],overrideId:e}}isPlainObject(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}deepMerge(e,t){let s={...e};for(let n in t){let o=t[n],i=e[n];this.isPlainObject(o)&&this.isPlainObject(i)?s[n]=this.deepMerge(i,o):s[n]=o}return s}loadModeFile(e){let t=(0,Y.join)(this.modesDir,`${e}.json`);if(!(0,x.existsSync)(t))throw new Error(`Mode file not found: ${t}`);let s=(0,x.readFileSync)(t,"utf-8");return JSON.parse(s)}loadMode(e){let t=this.parseInheritance(e);if(!t.hasParent)try{let d=this.loadModeFile(e);return this.activeMode=d,_.debug("SYSTEM",`Loaded mode: ${d.name} (${e})`,void 0,{types:d.observation_types.map(u=>u.id),concepts:d.observation_concepts.map(u=>u.id)}),d}catch{if(_.warn("SYSTEM",`Mode file not found: ${e}, falling back to 'code'`),e==="code")throw new Error("Critical: code.json mode file missing");return this.loadMode("code")}let{parentId:s,overrideId:n}=t,o;try{o=this.loadMode(s)}catch{_.warn("SYSTEM",`Parent mode '${s}' not found for ${e}, falling back to 'code'`),o=this.loadMode("code")}let i;try{i=this.loadModeFile(n),_.debug("SYSTEM",`Loaded override file: ${n} for parent ${s}`)}catch{return _.warn("SYSTEM",`Override file '${n}' not found, using parent mode '${s}' only`),this.activeMode=o,o}if(!i)return _.warn("SYSTEM",`Invalid override file: ${n}, using parent mode '${s}' only`),this.activeMode=o,o;let a=this.deepMerge(o,i);return this.activeMode=a,_.debug("SYSTEM",`Loaded mode with inheritance: ${a.name} (${e} = ${s} + ${n})`,void 0,{parent:s,override:n,types:a.observation_types.map(d=>d.id),concepts:a.observation_concepts.map(d=>d.id)}),a}getActiveMode(){if(!this.activeMode)throw new Error("No mode loaded. Call loadMode() first.");return this.activeMode}getObservationTypes(){return this.getActiveMode().observation_types}getObservationConcepts(){return this.getActiveMode().observation_concepts}getTypeIcon(e){return this.getObservationTypes().find(s=>s.id===e)?.emoji||"\u{1F4DD}"}getWorkEmoji(e){return this.getObservationTypes().find(s=>s.id===e)?.work_emoji||"\u{1F4DD}"}validateType(e){return this.getObservationTypes().some(t=>t.id===e)}getTypeLabel(e){return this.getObservationTypes().find(s=>s.id===e)?.label||e}};function re(){let r=Me.default.join((0,ve.homedir)(),".claude-mem","settings.json"),e=W.loadFromFile(r),t=A.getInstance().getActiveMode(),s=new Set(t.observation_types.map(o=>o.id)),n=new Set(t.observation_concepts.map(o=>o.id));return{totalObservationCount:parseInt(e.CLAUDE_MEM_CONTEXT_OBSERVATIONS,10),fullObservationCount:parseInt(e.CLAUDE_MEM_CONTEXT_FULL_COUNT,10),sessionCount:parseInt(e.CLAUDE_MEM_CONTEXT_SESSION_COUNT,10),showReadTokens:e.CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS==="true",showWorkTokens:e.CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS==="true",showSavingsAmount:e.CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT==="true",showSavingsPercent:e.CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT==="true",observationTypes:s,observationConcepts:n,fullObservationField:e.CLAUDE_MEM_CONTEXT_FULL_FIELD,showLastSummary:e.CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY==="true",showLastMessage:e.CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE==="true"}}var c={reset:"\x1B[0m",bright:"\x1B[1m",dim:"\x1B[2m",cyan:"\x1B[36m",green:"\x1B[32m",yellow:"\x1B[33m",blue:"\x1B[34m",magenta:"\x1B[35m",gray:"\x1B[90m",red:"\x1B[31m"},Ue=4,ne=1;function oe(r){let e=(r.title?.length||0)+(r.subtitle?.length||0)+(r.narrative?.length||0)+JSON.stringify(r.facts||[]).length;return Math.ceil(e/Ue)}function ie(r){let e=r.length,t=r.reduce((i,a)=>i+oe(a),0),s=r.reduce((i,a)=>i+(a.discovery_tokens||0),0),n=s-t,o=s>0?Math.round(n/s*100):0;return{totalObservations:e,totalReadTokens:t,totalDiscoveryTokens:s,savings:n,savingsPercent:o}}function Gt(r){return A.getInstance().getWorkEmoji(r)}function k(r,e){let t=oe(r),s=r.discovery_tokens||0,n=Gt(r.type),o=s>0?`${n} ${s.toLocaleString()}`:"-";return{readTokens:t,discoveryTokens:s,discoveryDisplay:o,workEmoji:n}}function q(r){return r.showReadTokens||r.showWorkTokens||r.showSavingsAmount||r.showSavingsPercent}var ke=L(require("path"),1),V=require("fs");var xe=/[\s\S]*?<\/system-reminder>/g;function ae(r,e,t,s){let n=Array.from(t.observationTypes),o=n.map(()=>"?").join(","),i=Array.from(t.observationConcepts),a=i.map(()=>"?").join(",");return r.db.prepare(` + `).run(e.content_session_id,e.prompt_number,e.prompt_text,e.created_at,e.created_at_epoch).lastInsertRowid}}};var Ie=require("os"),Le=L(require("path"),1);var B=require("fs"),G=L(require("path"),1),v={isWorktree:!1,worktreeName:null,parentRepoPath:null,parentProjectName:null};function Ce(r){let e=G.default.join(r,".git"),t;try{t=(0,B.statSync)(e)}catch{return v}if(!t.isFile())return v;let s;try{s=(0,B.readFileSync)(e,"utf-8").trim()}catch{return v}let n=s.match(/^gitdir:\s*(.+)$/);if(!n)return v;let i=n[1].match(/^(.+)[/\\]\.git[/\\]worktrees[/\\]([^/\\]+)$/);if(!i)return v;let a=i[1],d=G.default.basename(r),u=G.default.basename(a);return{isWorktree:!0,worktreeName:d,parentRepoPath:a,parentProjectName:u}}function ye(r){return r==="~"||r.startsWith("~/")?r.replace(/^~/,(0,Ie.homedir)()):r}function Xt(r){if(!r||r.trim()==="")return _.warn("PROJECT_NAME","Empty cwd provided, using fallback",{cwd:r}),"unknown-project";let e=ye(r),t=Le.default.basename(e);if(t===""){if(process.platform==="win32"){let n=r.match(/^([A-Z]):\\/i);if(n){let i=`drive-${n[1].toUpperCase()}`;return _.info("PROJECT_NAME","Drive root detected",{cwd:r,projectName:i}),i}}return _.warn("PROJECT_NAME","Root directory detected, using fallback",{cwd:r}),"unknown-project"}return t}function De(r){let e=Xt(r);if(!r)return{primary:e,parent:null,isWorktree:!1,allProjects:[e]};let t=ye(r),s=Ce(t);if(s.isWorktree&&s.parentProjectName){let n=`${s.parentProjectName}/${e}`;return{primary:n,parent:s.parentProjectName,isWorktree:!0,allProjects:[n]}}return{primary:e,parent:null,isWorktree:!1,allProjects:[e]}}var Me=L(require("path"),1),ve=require("os");var C=require("fs"),U=require("path"),se=require("os"),W=class{static DEFAULTS={CLAUDE_MEM_MODEL:"claude-sonnet-4-6",CLAUDE_MEM_CONTEXT_OBSERVATIONS:"50",CLAUDE_MEM_WORKER_PORT:"37777",CLAUDE_MEM_WORKER_HOST:"127.0.0.1",CLAUDE_MEM_SKIP_TOOLS:"ListMcpResourcesTool,SlashCommand,Skill,TodoWrite,AskUserQuestion",CLAUDE_MEM_PROVIDER:"claude",CLAUDE_MEM_CLAUDE_AUTH_METHOD:"cli",CLAUDE_MEM_GEMINI_API_KEY:"",CLAUDE_MEM_GEMINI_MODEL:"gemini-2.5-flash-lite",CLAUDE_MEM_GEMINI_RATE_LIMITING_ENABLED:"true",CLAUDE_MEM_GEMINI_MAX_CONTEXT_MESSAGES:"20",CLAUDE_MEM_GEMINI_MAX_TOKENS:"100000",CLAUDE_MEM_OPENROUTER_API_KEY:"",CLAUDE_MEM_OPENROUTER_MODEL:"xiaomi/mimo-v2-flash:free",CLAUDE_MEM_OPENROUTER_SITE_URL:"",CLAUDE_MEM_OPENROUTER_APP_NAME:"claude-mem",CLAUDE_MEM_OPENROUTER_MAX_CONTEXT_MESSAGES:"20",CLAUDE_MEM_OPENROUTER_MAX_TOKENS:"100000",CLAUDE_MEM_DATA_DIR:(0,U.join)((0,se.homedir)(),".claude-mem"),CLAUDE_MEM_LOG_LEVEL:"INFO",CLAUDE_MEM_PYTHON_VERSION:"3.13",CLAUDE_CODE_PATH:"",CLAUDE_MEM_MODE:"code",CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS:"false",CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS:"false",CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT:"false",CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT:"true",CLAUDE_MEM_CONTEXT_FULL_COUNT:"0",CLAUDE_MEM_CONTEXT_FULL_FIELD:"narrative",CLAUDE_MEM_CONTEXT_SESSION_COUNT:"10",CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY:"true",CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE:"false",CLAUDE_MEM_CONTEXT_SHOW_TERMINAL_OUTPUT:"true",CLAUDE_MEM_FOLDER_CLAUDEMD_ENABLED:"false",CLAUDE_MEM_FOLDER_USE_LOCAL_MD:"false",CLAUDE_MEM_TRANSCRIPTS_ENABLED:"true",CLAUDE_MEM_TRANSCRIPTS_CONFIG_PATH:(0,U.join)((0,se.homedir)(),".claude-mem","transcript-watch.json"),CLAUDE_MEM_MAX_CONCURRENT_AGENTS:"2",CLAUDE_MEM_EXCLUDED_PROJECTS:"",CLAUDE_MEM_FOLDER_MD_EXCLUDE:"[]",CLAUDE_MEM_SEMANTIC_INJECT:"false",CLAUDE_MEM_SEMANTIC_INJECT_LIMIT:"5",CLAUDE_MEM_TIER_ROUTING_ENABLED:"true",CLAUDE_MEM_TIER_SIMPLE_MODEL:"haiku",CLAUDE_MEM_TIER_SUMMARY_MODEL:"",CLAUDE_MEM_CHROMA_ENABLED:"true",CLAUDE_MEM_CHROMA_MODE:"local",CLAUDE_MEM_CHROMA_HOST:"127.0.0.1",CLAUDE_MEM_CHROMA_PORT:"8000",CLAUDE_MEM_CHROMA_SSL:"false",CLAUDE_MEM_CHROMA_API_KEY:"",CLAUDE_MEM_CHROMA_TENANT:"default_tenant",CLAUDE_MEM_CHROMA_DATABASE:"default_database"};static getAllDefaults(){return{...this.DEFAULTS}}static get(e){return process.env[e]??this.DEFAULTS[e]}static getInt(e){let t=this.get(e);return parseInt(t,10)}static getBool(e){let t=this.get(e);return t==="true"||t===!0}static applyEnvOverrides(e){let t={...e};for(let s of Object.keys(this.DEFAULTS))process.env[s]!==void 0&&(t[s]=process.env[s]);return t}static loadFromFile(e){try{if(!(0,C.existsSync)(e)){let i=this.getAllDefaults();try{let a=(0,U.dirname)(e);(0,C.existsSync)(a)||(0,C.mkdirSync)(a,{recursive:!0}),(0,C.writeFileSync)(e,JSON.stringify(i,null,2),"utf-8"),console.log("[SETTINGS] Created settings file with defaults:",e)}catch(a){console.warn("[SETTINGS] Failed to create settings file, using in-memory defaults:",e,a)}return this.applyEnvOverrides(i)}let t=(0,C.readFileSync)(e,"utf-8"),s=JSON.parse(t),n=s;if(s.env&&typeof s.env=="object"){n=s.env;try{(0,C.writeFileSync)(e,JSON.stringify(n,null,2),"utf-8"),console.log("[SETTINGS] Migrated settings file from nested to flat schema:",e)}catch(i){console.warn("[SETTINGS] Failed to auto-migrate settings file:",e,i)}}let o={...this.DEFAULTS};for(let i of Object.keys(this.DEFAULTS))n[i]!==void 0&&(o[i]=n[i]);return this.applyEnvOverrides(o)}catch(t){return console.warn("[SETTINGS] Failed to load settings, using defaults:",e,t),this.applyEnvOverrides(this.getAllDefaults())}}};var x=require("fs"),Y=require("path");var A=class r{static instance=null;activeMode=null;modesDir;constructor(){let e=Oe(),t=[(0,Y.join)(e,"modes"),(0,Y.join)(e,"..","plugin","modes")],s=t.find(n=>(0,x.existsSync)(n));this.modesDir=s||t[0]}static getInstance(){return r.instance||(r.instance=new r),r.instance}parseInheritance(e){let t=e.split("--");if(t.length===1)return{hasParent:!1,parentId:"",overrideId:""};if(t.length>2)throw new Error(`Invalid mode inheritance: ${e}. Only one level of inheritance supported (parent--override)`);return{hasParent:!0,parentId:t[0],overrideId:e}}isPlainObject(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}deepMerge(e,t){let s={...e};for(let n in t){let o=t[n],i=e[n];this.isPlainObject(o)&&this.isPlainObject(i)?s[n]=this.deepMerge(i,o):s[n]=o}return s}loadModeFile(e){let t=(0,Y.join)(this.modesDir,`${e}.json`);if(!(0,x.existsSync)(t))throw new Error(`Mode file not found: ${t}`);let s=(0,x.readFileSync)(t,"utf-8");return JSON.parse(s)}loadMode(e){let t=this.parseInheritance(e);if(!t.hasParent)try{let d=this.loadModeFile(e);return this.activeMode=d,_.debug("SYSTEM",`Loaded mode: ${d.name} (${e})`,void 0,{types:d.observation_types.map(u=>u.id),concepts:d.observation_concepts.map(u=>u.id)}),d}catch{if(_.warn("SYSTEM",`Mode file not found: ${e}, falling back to 'code'`),e==="code")throw new Error("Critical: code.json mode file missing");return this.loadMode("code")}let{parentId:s,overrideId:n}=t,o;try{o=this.loadMode(s)}catch{_.warn("SYSTEM",`Parent mode '${s}' not found for ${e}, falling back to 'code'`),o=this.loadMode("code")}let i;try{i=this.loadModeFile(n),_.debug("SYSTEM",`Loaded override file: ${n} for parent ${s}`)}catch{return _.warn("SYSTEM",`Override file '${n}' not found, using parent mode '${s}' only`),this.activeMode=o,o}if(!i)return _.warn("SYSTEM",`Invalid override file: ${n}, using parent mode '${s}' only`),this.activeMode=o,o;let a=this.deepMerge(o,i);return this.activeMode=a,_.debug("SYSTEM",`Loaded mode with inheritance: ${a.name} (${e} = ${s} + ${n})`,void 0,{parent:s,override:n,types:a.observation_types.map(d=>d.id),concepts:a.observation_concepts.map(d=>d.id)}),a}getActiveMode(){if(!this.activeMode)throw new Error("No mode loaded. Call loadMode() first.");return this.activeMode}getObservationTypes(){return this.getActiveMode().observation_types}getObservationConcepts(){return this.getActiveMode().observation_concepts}getTypeIcon(e){return this.getObservationTypes().find(s=>s.id===e)?.emoji||"\u{1F4DD}"}getWorkEmoji(e){return this.getObservationTypes().find(s=>s.id===e)?.work_emoji||"\u{1F4DD}"}validateType(e){return this.getObservationTypes().some(t=>t.id===e)}getTypeLabel(e){return this.getObservationTypes().find(s=>s.id===e)?.label||e}};function re(){let r=Me.default.join((0,ve.homedir)(),".claude-mem","settings.json"),e=W.loadFromFile(r),t=A.getInstance().getActiveMode(),s=new Set(t.observation_types.map(o=>o.id)),n=new Set(t.observation_concepts.map(o=>o.id));return{totalObservationCount:parseInt(e.CLAUDE_MEM_CONTEXT_OBSERVATIONS,10),fullObservationCount:parseInt(e.CLAUDE_MEM_CONTEXT_FULL_COUNT,10),sessionCount:parseInt(e.CLAUDE_MEM_CONTEXT_SESSION_COUNT,10),showReadTokens:e.CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS==="true",showWorkTokens:e.CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS==="true",showSavingsAmount:e.CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT==="true",showSavingsPercent:e.CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT==="true",observationTypes:s,observationConcepts:n,fullObservationField:e.CLAUDE_MEM_CONTEXT_FULL_FIELD,showLastSummary:e.CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY==="true",showLastMessage:e.CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE==="true"}}var c={reset:"\x1B[0m",bright:"\x1B[1m",dim:"\x1B[2m",cyan:"\x1B[36m",green:"\x1B[32m",yellow:"\x1B[33m",blue:"\x1B[34m",magenta:"\x1B[35m",gray:"\x1B[90m",red:"\x1B[31m"},Ue=4,ne=1;function oe(r){let e=(r.title?.length||0)+(r.subtitle?.length||0)+(r.narrative?.length||0)+JSON.stringify(r.facts||[]).length;return Math.ceil(e/Ue)}function ie(r){let e=r.length,t=r.reduce((i,a)=>i+oe(a),0),s=r.reduce((i,a)=>i+(a.discovery_tokens||0),0),n=s-t,o=s>0?Math.round(n/s*100):0;return{totalObservations:e,totalReadTokens:t,totalDiscoveryTokens:s,savings:n,savingsPercent:o}}function Gt(r){return A.getInstance().getWorkEmoji(r)}function k(r,e){let t=oe(r),s=r.discovery_tokens||0,n=Gt(r.type),o=s>0?`${n} ${s.toLocaleString()}`:"-";return{readTokens:t,discoveryTokens:s,discoveryDisplay:o,workEmoji:n}}function q(r){return r.showReadTokens||r.showWorkTokens||r.showSavingsAmount||r.showSavingsPercent}var ke=L(require("path"),1),V=require("fs");var xe=/[\s\S]*?<\/system-reminder>/g;function ae(r,e,t,s){let n=Array.from(t.observationTypes),o=n.map(()=>"?").join(","),i=Array.from(t.observationConcepts),a=i.map(()=>"?").join(",");return r.db.prepare(` SELECT o.id, o.memory_session_id, @@ -747,13 +747,13 @@ ${o.stack}`:` ${o.message}`:this.getLevel()===0&&typeof o=="object"?m=` ORDER BY ss.created_at_epoch DESC LIMIT ? `).all(...e,...s?[s]:[],t.sessionCount+ne)}function Bt(r){return r.replace(/\//g,"-")}function Wt(r){try{if(!(0,V.existsSync)(r))return{userMessage:"",assistantMessage:""};let e=(0,V.readFileSync)(r,"utf-8").trim();if(!e)return{userMessage:"",assistantMessage:""};let t=e.split(` -`).filter(n=>n.trim()),s="";for(let n=t.length-1;n>=0;n--)try{let o=t[n];if(!o.includes('"type":"assistant"'))continue;let i=JSON.parse(o);if(i.type==="assistant"&&i.message?.content&&Array.isArray(i.message.content)){let a="";for(let d of i.message.content)d.type==="text"&&(a+=d.text);if(a=a.replace(xe,"").trim(),a){s=a;break}}}catch(o){_.debug("PARSER","Skipping malformed transcript line",{lineIndex:n},o);continue}return{userMessage:"",assistantMessage:s}}catch(e){return _.failure("WORKER","Failed to extract prior messages from transcript",{transcriptPath:r},e),{userMessage:"",assistantMessage:""}}}function ce(r,e,t,s){if(!e.showLastMessage||r.length===0)return{userMessage:"",assistantMessage:""};let n=r.find(d=>d.memory_session_id!==t);if(!n)return{userMessage:"",assistantMessage:""};let o=n.memory_session_id,i=Bt(s),a=ke.default.join(y,"projects",i,`${o}.jsonl`);return Wt(a)}function we(r,e){let t=e[0]?.id;return r.map((s,n)=>{let o=n===0?null:e[n+1];return{...s,displayEpoch:o?o.created_at_epoch:s.created_at_epoch,displayTime:o?o.created_at:s.created_at,shouldShowLink:s.id!==t}})}function ue(r,e){let t=[...r.map(s=>({type:"observation",data:s})),...e.map(s=>({type:"summary",data:s}))];return t.sort((s,n)=>{let o=s.type==="observation"?s.data.created_at_epoch:s.data.displayEpoch,i=n.type==="observation"?n.data.created_at_epoch:n.data.displayEpoch;return o-i}),t}function Pe(r,e){return new Set(r.slice(0,e).map(t=>t.id))}function je(){let r=new Date,e=r.toLocaleDateString("en-CA"),t=r.toLocaleTimeString("en-US",{hour:"numeric",minute:"2-digit",hour12:!0}).toLowerCase().replace(" ",""),s=r.toLocaleTimeString("en-US",{timeZoneName:"short"}).split(" ").pop();return`${e} ${t} ${s}`}function He(r){return[`# [${r}] recent context, ${je()}`,""]}function Xe(){return[`Legend: \u{1F3AF}session ${A.getInstance().getActiveMode().observation_types.map(t=>`${t.emoji}${t.id}`).join(" ")}`,"Format: ID TIME TYPE TITLE","Fetch details: get_observations([IDs]) | Search: mem-search skill",""]}function Ge(){return[]}function Be(){return[]}function We(r,e){let t=[],s=[`${r.totalObservations} obs (${r.totalReadTokens.toLocaleString()}t read)`,`${r.totalDiscoveryTokens.toLocaleString()}t work`];return r.totalDiscoveryTokens>0&&(e.showSavingsAmount||e.showSavingsPercent)&&(e.showSavingsPercent?s.push(`${r.savingsPercent}% savings`):e.showSavingsAmount&&s.push(`${r.savings.toLocaleString()}t saved`)),t.push(`Stats: ${s.join(" | ")}`),t.push(""),t}function Ye(r){return[`### ${r}`]}function qe(r){return r.toLowerCase().replace(" am","a").replace(" pm","p")}function Ve(r,e,t){let s=r.title||"Untitled",n=A.getInstance().getTypeIcon(r.type),o=e?qe(e):'"';return`${r.id} ${o} ${n} ${s}`}function Ke(r,e,t,s){let n=[],o=r.title||"Untitled",i=A.getInstance().getTypeIcon(r.type),a=e?qe(e):'"',{readTokens:d,discoveryDisplay:u}=k(r,s);n.push(`**${r.id}** ${a} ${i} **${o}**`),t&&n.push(t);let m=[];return s.showReadTokens&&m.push(`~${d}t`),s.showWorkTokens&&m.push(u),m.length>0&&n.push(m.join(" ")),n.push(""),n}function Je(r,e){return[`S${r.id} ${r.request||"Session started"} (${e})`]}function $(r,e){return e?[`**${r}**: ${e}`,""]:[]}function ze(r){return r.assistantMessage?["","---","","**Previously**","",`A: ${r.assistantMessage}`,""]:[]}function Qe(r,e){return["",`Access ${Math.round(r/1e3)}k tokens of past work via get_observations([IDs]) or mem-search skill.`]}function Ze(r){return`# [${r}] recent context, ${je()} +`).filter(n=>n.trim()),s="";for(let n=t.length-1;n>=0;n--)try{let o=t[n];if(!o.includes('"type":"assistant"'))continue;let i=JSON.parse(o);if(i.type==="assistant"&&i.message?.content&&Array.isArray(i.message.content)){let a="";for(let d of i.message.content)d.type==="text"&&(a+=d.text);if(a=a.replace(xe,"").trim(),a){s=a;break}}}catch(o){_.debug("PARSER","Skipping malformed transcript line",{lineIndex:n},o);continue}return{userMessage:"",assistantMessage:s}}catch(e){return _.failure("WORKER","Failed to extract prior messages from transcript",{transcriptPath:r},e),{userMessage:"",assistantMessage:""}}}function ce(r,e,t,s){if(!e.showLastMessage||r.length===0)return{userMessage:"",assistantMessage:""};let n=r.find(d=>d.memory_session_id!==t);if(!n)return{userMessage:"",assistantMessage:""};let o=n.memory_session_id,i=Bt(s),a=ke.default.join(y,"projects",i,`${o}.jsonl`);return Wt(a)}function we(r,e){let t=e[0]?.id;return r.map((s,n)=>{let o=n===0?null:e[n+1];return{...s,displayEpoch:o?o.created_at_epoch:s.created_at_epoch,displayTime:o?o.created_at:s.created_at,shouldShowLink:s.id!==t}})}function ue(r,e){let t=[...r.map(s=>({type:"observation",data:s})),...e.map(s=>({type:"summary",data:s}))];return t.sort((s,n)=>{let o=s.type==="observation"?s.data.created_at_epoch:s.data.displayEpoch,i=n.type==="observation"?n.data.created_at_epoch:n.data.displayEpoch;return o-i}),t}function Pe(r,e){return new Set(r.slice(0,e).map(t=>t.id))}function He(){let r=new Date,e=r.toLocaleDateString("en-CA"),t=r.toLocaleTimeString("en-US",{hour:"numeric",minute:"2-digit",hour12:!0}).toLowerCase().replace(" ",""),s=r.toLocaleTimeString("en-US",{timeZoneName:"short"}).split(" ").pop();return`${e} ${t} ${s}`}function je(r){return[`# [${r}] recent context, ${He()}`,""]}function Xe(){return[`Legend: \u{1F3AF}session ${A.getInstance().getActiveMode().observation_types.map(t=>`${t.emoji}${t.id}`).join(" ")}`,"Format: ID TIME TYPE TITLE","Fetch details: get_observations([IDs]) | Search: mem-search skill",""]}function Ge(){return[]}function Be(){return[]}function We(r,e){let t=[],s=[`${r.totalObservations} obs (${r.totalReadTokens.toLocaleString()}t read)`,`${r.totalDiscoveryTokens.toLocaleString()}t work`];return r.totalDiscoveryTokens>0&&(e.showSavingsAmount||e.showSavingsPercent)&&(e.showSavingsPercent?s.push(`${r.savingsPercent}% savings`):e.showSavingsAmount&&s.push(`${r.savings.toLocaleString()}t saved`)),t.push(`Stats: ${s.join(" | ")}`),t.push(""),t}function Ye(r){return[`### ${r}`]}function qe(r){return r.toLowerCase().replace(" am","a").replace(" pm","p")}function Ve(r,e,t){let s=r.title||"Untitled",n=A.getInstance().getTypeIcon(r.type),o=e?qe(e):'"';return`${r.id} ${o} ${n} ${s}`}function Ke(r,e,t,s){let n=[],o=r.title||"Untitled",i=A.getInstance().getTypeIcon(r.type),a=e?qe(e):'"',{readTokens:d,discoveryDisplay:u}=k(r,s);n.push(`**${r.id}** ${a} ${i} **${o}**`),t&&n.push(t);let m=[];return s.showReadTokens&&m.push(`~${d}t`),s.showWorkTokens&&m.push(u),m.length>0&&n.push(m.join(" ")),n.push(""),n}function Je(r,e){return[`S${r.id} ${r.request||"Session started"} (${e})`]}function $(r,e){return e?[`**${r}**: ${e}`,""]:[]}function ze(r){return r.assistantMessage?["","---","","**Previously**","",`A: ${r.assistantMessage}`,""]:[]}function Qe(r,e){return["",`Access ${Math.round(r/1e3)}k tokens of past work via get_observations([IDs]) or mem-search skill.`]}function Ze(r){return`# [${r}] recent context, ${He()} No previous sessions found.`}function et(){let r=new Date,e=r.toLocaleDateString("en-CA"),t=r.toLocaleTimeString("en-US",{hour:"numeric",minute:"2-digit",hour12:!0}).toLowerCase().replace(" ",""),s=r.toLocaleTimeString("en-US",{timeZoneName:"short"}).split(" ").pop();return`${e} ${t} ${s}`}function tt(r){return["",`${c.bright}${c.cyan}[${r}] recent context, ${et()}${c.reset}`,`${c.gray}${"\u2500".repeat(60)}${c.reset}`,""]}function st(){let e=A.getInstance().getActiveMode().observation_types.map(t=>`${t.emoji} ${t.id}`).join(" | ");return[`${c.dim}Legend: session-request | ${e}${c.reset}`,""]}function rt(){return[`${c.bright}Column Key${c.reset}`,`${c.dim} Read: Tokens to read this observation (cost to learn it now)${c.reset}`,`${c.dim} Work: Tokens spent on work that produced this record ( research, building, deciding)${c.reset}`,""]}function nt(){return[`${c.dim}Context Index: This semantic index (titles, types, files, tokens) is usually sufficient to understand past work.${c.reset}`,"",`${c.dim}When you need implementation details, rationale, or debugging context:${c.reset}`,`${c.dim} - Fetch by ID: get_observations([IDs]) for observations visible in this index${c.reset}`,`${c.dim} - Search history: Use the mem-search skill for past decisions, bugs, and deeper research${c.reset}`,`${c.dim} - Trust this index over re-reading code for past decisions and learnings${c.reset}`,""]}function ot(r,e){let t=[];if(t.push(`${c.bright}${c.cyan}Context Economics${c.reset}`),t.push(`${c.dim} Loading: ${r.totalObservations} observations (${r.totalReadTokens.toLocaleString()} tokens to read)${c.reset}`),t.push(`${c.dim} Work investment: ${r.totalDiscoveryTokens.toLocaleString()} tokens spent on research, building, and decisions${c.reset}`),r.totalDiscoveryTokens>0&&(e.showSavingsAmount||e.showSavingsPercent)){let s=" Your savings: ";e.showSavingsAmount&&e.showSavingsPercent?s+=`${r.savings.toLocaleString()} tokens (${r.savingsPercent}% reduction from reuse)`:e.showSavingsAmount?s+=`${r.savings.toLocaleString()} tokens`:s+=`${r.savingsPercent}% reduction from reuse`,t.push(`${c.green}${s}${c.reset}`)}return t.push(""),t}function it(r){return[`${c.bright}${c.cyan}${r}${c.reset}`,""]}function at(r){return[`${c.dim}${r}${c.reset}`]}function dt(r,e,t,s){let n=r.title||"Untitled",o=A.getInstance().getTypeIcon(r.type),{readTokens:i,discoveryTokens:a,workEmoji:d}=k(r,s),u=t?`${c.dim}${e}${c.reset}`:" ".repeat(e.length),m=s.showReadTokens&&i>0?`${c.dim}(~${i}t)${c.reset}`:"",l=s.showWorkTokens&&a>0?`${c.dim}(${d} ${a.toLocaleString()}t)${c.reset}`:"";return` ${c.dim}#${r.id}${c.reset} ${u} ${o} ${n} ${m} ${l}`}function ct(r,e,t,s,n){let o=[],i=r.title||"Untitled",a=A.getInstance().getTypeIcon(r.type),{readTokens:d,discoveryTokens:u,workEmoji:m}=k(r,n),l=t?`${c.dim}${e}${c.reset}`:" ".repeat(e.length),E=n.showReadTokens&&d>0?`${c.dim}(~${d}t)${c.reset}`:"",T=n.showWorkTokens&&u>0?`${c.dim}(${m} ${u.toLocaleString()}t)${c.reset}`:"";return o.push(` ${c.dim}#${r.id}${c.reset} ${l} ${a} ${c.bright}${i}${c.reset}`),s&&o.push(` ${c.dim}${s}${c.reset}`),(E||T)&&o.push(` ${E} ${T}`),o.push(""),o}function ut(r,e){let t=`${r.request||"Session started"} (${e})`;return[`${c.yellow}#S${r.id}${c.reset} ${t}`,""]}function F(r,e,t){return e?[`${t}${r}:${c.reset} ${e}`,""]:[]}function mt(r){return r.assistantMessage?["","---","",`${c.bright}${c.magenta}Previously${c.reset}`,"",`${c.dim}A: ${r.assistantMessage}${c.reset}`,""]:[]}function _t(r,e){let t=Math.round(r/1e3);return["",`${c.dim}Access ${t}k tokens of past research & decisions for just ${e.toLocaleString()}t. Use the claude-mem skill to access memories by ID.${c.reset}`]}function pt(r){return` ${c.bright}${c.cyan}[${r}] recent context, ${et()}${c.reset} ${c.gray}${"\u2500".repeat(60)}${c.reset} ${c.dim}No previous sessions found for this project yet.${c.reset} -`}function lt(r,e,t,s){let n=[];return s?n.push(...tt(r)):n.push(...He(r)),s?n.push(...st()):n.push(...Xe()),s?n.push(...rt()):n.push(...Ge()),s?n.push(...nt()):n.push(...Be()),q(t)&&(s?n.push(...ot(e,t)):n.push(...We(e,t))),n}var me=L(require("path"),1);function z(r){if(!r)return[];try{let e=JSON.parse(r);return Array.isArray(e)?e:[]}catch(e){return _.debug("PARSER","Failed to parse JSON array, using empty fallback",{preview:r?.substring(0,50)},e),[]}}function _e(r){return new Date(r).toLocaleString("en-US",{month:"short",day:"numeric",hour:"numeric",minute:"2-digit",hour12:!0})}function pe(r){return new Date(r).toLocaleString("en-US",{hour:"numeric",minute:"2-digit",hour12:!0})}function gt(r){return new Date(r).toLocaleString("en-US",{month:"short",day:"numeric",year:"numeric"})}function Et(r,e){return me.default.isAbsolute(r)?me.default.relative(e,r):r}function Tt(r,e,t){let s=z(r);if(s.length>0)return Et(s[0],e);if(t){let n=z(t);if(n.length>0)return Et(n[0],e)}return"General"}function Yt(r){let e=new Map;for(let s of r){let n=s.type==="observation"?s.data.created_at:s.data.displayTime,o=gt(n);e.has(o)||e.set(o,[]),e.get(o).push(s)}let t=Array.from(e.entries()).sort((s,n)=>{let o=new Date(s[0]).getTime(),i=new Date(n[0]).getTime();return o-i});return new Map(t)}function ft(r,e){return e.fullObservationField==="narrative"?r.narrative:r.facts?z(r.facts).join(` +`}function lt(r,e,t,s){let n=[];return s?n.push(...tt(r)):n.push(...je(r)),s?n.push(...st()):n.push(...Xe()),s?n.push(...rt()):n.push(...Ge()),s?n.push(...nt()):n.push(...Be()),q(t)&&(s?n.push(...ot(e,t)):n.push(...We(e,t))),n}var me=L(require("path"),1);function z(r){if(!r)return[];try{let e=JSON.parse(r);return Array.isArray(e)?e:[]}catch(e){return _.debug("PARSER","Failed to parse JSON array, using empty fallback",{preview:r?.substring(0,50)},e),[]}}function _e(r){return new Date(r).toLocaleString("en-US",{month:"short",day:"numeric",hour:"numeric",minute:"2-digit",hour12:!0})}function pe(r){return new Date(r).toLocaleString("en-US",{hour:"numeric",minute:"2-digit",hour12:!0})}function gt(r){return new Date(r).toLocaleString("en-US",{month:"short",day:"numeric",year:"numeric"})}function Et(r,e){return me.default.isAbsolute(r)?me.default.relative(e,r):r}function Tt(r,e,t){let s=z(r);if(s.length>0)return Et(s[0],e);if(t){let n=z(t);if(n.length>0)return Et(n[0],e)}return"General"}function Yt(r){let e=new Map;for(let s of r){let n=s.type==="observation"?s.data.created_at:s.data.displayTime,o=gt(n);e.has(o)||e.set(o,[]),e.get(o).push(s)}let t=Array.from(e.entries()).sort((s,n)=>{let o=new Date(s[0]).getTime(),i=new Date(n[0]).getTime();return o-i});return new Map(t)}function ft(r,e){return e.fullObservationField==="narrative"?r.narrative:r.facts?z(r.facts).join(` `):null}function qt(r,e,t,s){let n=[];n.push(...Ye(r));let o="";for(let i of e)if(i.type==="summary"){let a=i.data,d=_e(a.displayTime);n.push(...Je(a,d))}else{let a=i.data,d=pe(a.created_at),m=d!==o?d:"";if(o=d,t.has(a.id)){let E=ft(a,s);n.push(...Ke(a,m,E,s))}else n.push(Ve(a,m,s))}return n}function Vt(r,e,t,s,n){let o=[];o.push(...it(r));let i=null,a="";for(let d of e)if(d.type==="summary"){i=null,a="";let u=d.data,m=_e(u.displayTime);o.push(...ut(u,m))}else{let u=d.data,m=Tt(u.files_modified,n,u.files_read),l=pe(u.created_at),E=l!==a;a=l;let T=t.has(u.id);if(m!==i&&(o.push(...at(m)),i=m),T){let O=ft(u,s);o.push(...ct(u,l,E,O,s))}else o.push(dt(u,l,E,s))}return o.push(""),o}function Kt(r,e,t,s,n,o){return o?Vt(r,e,t,s,n):qt(r,e,t,s)}function St(r,e,t,s,n){let o=[],i=Yt(r);for(let[a,d]of i)o.push(...Kt(a,d,e,t,s,n));return o}function bt(r,e,t){return!(!r.showLastSummary||!e||!!!(e.investigated||e.learned||e.completed||e.next_steps)||t&&e.created_at_epoch<=t.created_at_epoch)}function ht(r,e){let t=[];return e?(t.push(...F("Investigated",r.investigated,c.blue)),t.push(...F("Learned",r.learned,c.yellow)),t.push(...F("Completed",r.completed,c.green)),t.push(...F("Next Steps",r.next_steps,c.magenta))):(t.push(...$("Investigated",r.investigated)),t.push(...$("Learned",r.learned)),t.push(...$("Completed",r.completed)),t.push(...$("Next Steps",r.next_steps))),t}function Ot(r,e){return e?mt(r):ze(r)}function At(r,e,t){return!q(e)||r.totalDiscoveryTokens<=0||r.savings<=0?[]:t?_t(r.totalDiscoveryTokens,r.totalReadTokens):Qe(r.totalDiscoveryTokens,r.totalReadTokens)}var Jt=Rt.default.join((0,Nt.homedir)(),".claude","plugins","marketplaces","thedotmack","plugin",".install-version");function zt(){try{return new X}catch(r){if(r.code==="ERR_DLOPEN_FAILED"){try{(0,Ct.unlinkSync)(Jt)}catch(e){_.debug("SYSTEM","Marker file cleanup failed (may not exist)",{},e)}return _.error("SYSTEM","Native module rebuild needed - restart Claude Code to auto-fix"),null}throw r}}function Qt(r,e){return e?pt(r):Ze(r)}function Zt(r,e,t,s,n,o,i){let a=[],d=ie(e);a.push(...lt(r,d,s,i));let u=t.slice(0,s.sessionCount),m=we(u,t),l=ue(e,m),E=Pe(e,s.fullObservationCount);a.push(...St(l,E,s,n,i));let T=t[0],O=e[0];bt(s,T,O)&&a.push(...ht(T,i));let S=ce(e,s,o,n);return a.push(...Ot(S,i)),a.push(...At(d,s,i)),a.join(` `).trimEnd()}async function le(r,e=!1){let t=re(),s=r?.cwd??process.cwd(),n=De(s),o=n.primary,i=r?.platform_source,a=r?.projects??n.allProjects;r?.full&&(t.totalObservationCount=999999,t.sessionCount=999999);let d=zt();if(!d)return"";try{let u=a.length>1?$e(d,a,t,i):ae(d,o,t,i),m=a.length>1?Fe(d,a,t,i):de(d,o,t,i);return u.length===0&&m.length===0?Qt(o,e):Zt(o,u,m,t,s,r?.session_id,e)}finally{d.close()}}0&&(module.exports={generateContext}); diff --git a/plugin/scripts/worker-service.cjs b/plugin/scripts/worker-service.cjs index e8a141ff..3590ff6e 100755 --- a/plugin/scripts/worker-service.cjs +++ b/plugin/scripts/worker-service.cjs @@ -846,7 +846,7 @@ Tips: - Filter by type: obs_type="bugfix,feature" - Filter by date: dateStart="2025-01-01" - Sort: orderBy="date_desc" or "date_asc"`}}});var ja,_I=he(()=>{"use strict";en();zs();ja=class{buildTimeline(e){let r=[...e.observations.map(n=>({type:"observation",data:n,epoch:n.created_at_epoch})),...e.sessions.map(n=>({type:"session",data:n,epoch:n.created_at_epoch})),...e.prompts.map(n=>({type:"prompt",data:n,epoch:n.created_at_epoch}))];return r.sort((n,i)=>n.epoch-i.epoch),r}filterByDepth(e,r,n,i,s){if(e.length===0)return e;let o=this.findAnchorIndex(e,r,n);if(o===-1)return e;let a=Math.max(0,o-i),c=Math.min(e.length,o+s+1);return e.slice(a,c)}findAnchorIndex(e,r,n){if(typeof r=="number")return e.findIndex(s=>s.type==="observation"&&s.data.id===r);if(typeof r=="string"&&r.startsWith("S")){let s=parseInt(r.slice(1),10);return e.findIndex(o=>o.type==="session"&&o.data.id===s)}let i=e.findIndex(s=>s.epoch>=n);return i===-1?e.length-1:i}formatTimeline(e,r,n={}){let{query:i,depthBefore:s,depthAfter:o,cwd:a=process.cwd()}=n;if(e.length===0)return i?`Found observation matching "${i}", but no timeline context available.`:"No timeline items found";let c=[];if(i&&r){let d=e.find(m=>m.type==="observation"&&m.data.id===r),p=d?d.data.title||"Untitled":"Unknown";c.push(`# Timeline for query: "${i}"`),c.push(`**Anchor:** Observation #${r} - ${p}`)}else r?c.push(`# Timeline around anchor: ${r}`):c.push("# Timeline");s!==void 0&&o!==void 0?c.push(`**Window:** ${s} records before -> ${o} records after | **Items:** ${e.length}`):c.push(`**Items:** ${e.length}`),c.push("");let u=this.groupByDay(e),l=this.sortDaysChronologically(u);for(let[d,p]of l){c.push(`### ${d}`),c.push("");let m=null,f="",h=!1;for(let g of p){let v=this.isAnchorItem(g,r);if(g.type==="session"){h&&(c.push(""),h=!1,m=null,f="");let y=g.data,b=y.request||"Session summary",S=v?" <- **ANCHOR**":"";c.push(`**\u{1F3AF} #S${y.id}** ${b} (${Nn(g.epoch)})${S}`),c.push("")}else if(g.type==="prompt"){h&&(c.push(""),h=!1,m=null,f="");let y=g.data,b=y.prompt_text.length>100?y.prompt_text.substring(0,100)+"...":y.prompt_text;c.push(`**\u{1F4AC} User Prompt #${y.prompt_number}** (${Nn(g.epoch)})`),c.push(`> ${b}`),c.push("")}else if(g.type==="observation"){let y=g.data,b=Ti(y.files_modified,a,y.files_read);b!==m&&(h&&c.push(""),c.push(`**${b}**`),c.push("| ID | Time | T | Title | Tokens |"),c.push("|----|------|---|-------|--------|"),m=b,h=!0,f="");let S=He.getInstance().getTypeIcon(y.type),x=vr(g.epoch),w=y.title||"Untitled",E=Ds(y.narrative),I=x!==f?x:'"';f=x;let P=v?" <- **ANCHOR**":"";c.push(`| #${y.id} | ${I} | ${S} | ${w}${P} | ~${E} |`)}}h&&c.push("")}return c.join(` -`)}groupByDay(e){let r=new Map;for(let n of e){let i=Ms(n.epoch);r.has(i)||r.set(i,[]),r.get(i).push(n)}return r}sortDaysChronologically(e){return Array.from(e.entries()).sort((r,n)=>{let i=new Date(r[0]).getTime(),s=new Date(n[0]).getTime();return i-s})}isAnchorItem(e,r){return r===null?!1:typeof r=="number"&&e.type==="observation"?e.data.id===r:typeof r=="string"&&r.startsWith("S")&&e.type==="session"?`S${e.data.id}`===r:!1}}});var j9={};cn(j9,{SearchOrchestrator:()=>Xu});var Xu,bI=he(()=>{"use strict";hI();gI();vI();yI();_I();Q();Xu=class{constructor(e,r,n){this.sessionSearch=e;this.sessionStore=r;this.chromaSync=n;this.sqliteStrategy=new _m(e),n&&(this.chromaStrategy=new ym(n,r),this.hybridStrategy=new bm(n,r,e)),this.resultFormatter=new Sm,this.timelineBuilder=new ja}sessionSearch;sessionStore;chromaSync;chromaStrategy=null;sqliteStrategy;hybridStrategy=null;resultFormatter;timelineBuilder;async search(e){let r=this.normalizeParams(e);return await this.executeWithFallback(r)}async executeWithFallback(e){if(!e.query)return _.debug("SEARCH","Orchestrator: Filter-only query, using SQLite",{}),await this.sqliteStrategy.search(e);if(this.chromaStrategy){_.debug("SEARCH","Orchestrator: Using Chroma semantic search",{});let r=await this.chromaStrategy.search(e);return r.usedChroma?r:(_.debug("SEARCH","Orchestrator: Chroma failed, falling back to SQLite",{}),{...await this.sqliteStrategy.search({...e,query:void 0}),fellBack:!0})}return _.debug("SEARCH","Orchestrator: Chroma not available",{}),{results:{observations:[],sessions:[],prompts:[]},usedChroma:!1,fellBack:!1,strategy:"sqlite"}}async findByConcept(e,r){let n=this.normalizeParams(r);return this.hybridStrategy?await this.hybridStrategy.findByConcept(e,n):{results:{observations:this.sqliteStrategy.findByConcept(e,n),sessions:[],prompts:[]},usedChroma:!1,fellBack:!1,strategy:"sqlite"}}async findByType(e,r){let n=this.normalizeParams(r);return this.hybridStrategy?await this.hybridStrategy.findByType(e,n):{results:{observations:this.sqliteStrategy.findByType(e,n),sessions:[],prompts:[]},usedChroma:!1,fellBack:!1,strategy:"sqlite"}}async findByFile(e,r){let n=this.normalizeParams(r);return this.hybridStrategy?await this.hybridStrategy.findByFile(e,n):{...this.sqliteStrategy.findByFile(e,n),usedChroma:!1}}getTimeline(e,r,n,i,s){let o=this.timelineBuilder.buildTimeline(e);return this.timelineBuilder.filterByDepth(o,r,n,i,s)}formatTimeline(e,r,n={}){return this.timelineBuilder.formatTimeline(e,r,n)}formatSearchResults(e,r,n=!1){return this.resultFormatter.formatSearchResults(e,r,n)}getFormatter(){return this.resultFormatter}getTimelineBuilder(){return this.timelineBuilder}normalizeParams(e){let r={...e};return r.concepts&&typeof r.concepts=="string"&&(r.concepts=r.concepts.split(",").map(n=>n.trim()).filter(Boolean)),r.files&&typeof r.files=="string"&&(r.files=r.files.split(",").map(n=>n.trim()).filter(Boolean)),r.obs_type&&typeof r.obs_type=="string"&&(r.obsType=r.obs_type.split(",").map(n=>n.trim()).filter(Boolean),delete r.obs_type),r.type&&typeof r.type=="string"&&r.type.includes(",")&&(r.type=r.type.split(",").map(n=>n.trim()).filter(Boolean)),r.type&&!r.searchType&&["observations","sessions","prompts"].includes(r.type)&&(r.searchType=r.type,delete r.type),(r.dateStart||r.dateEnd)&&(r.dateRange={start:r.dateStart,end:r.dateEnd},delete r.dateStart,delete r.dateEnd),r}isChromaAvailable(){return!!this.chromaSync}}});function eH(t){let e=Uy.default.join(t,".git"),r;try{r=(0,Fy.statSync)(e)}catch{return Nm}if(!r.isFile())return Nm;let n;try{n=(0,Fy.readFileSync)(e,"utf-8").trim()}catch{return Nm}let i=n.match(/^gitdir:\s*(.+)$/);if(!i)return Nm;let o=i[1].match(/^(.+)[/\\]\.git[/\\]worktrees[/\\]([^/\\]+)$/);if(!o)return Nm;let a=o[1],c=Uy.default.basename(t),u=Uy.default.basename(a);return{isWorktree:!0,worktreeName:c,parentRepoPath:a,parentProjectName:u}}var Fy,Uy,Nm,tH=he(()=>{"use strict";Fy=require("fs"),Uy=Oe(require("path"),1),Nm={isWorktree:!1,worktreeName:null,parentRepoPath:null,parentProjectName:null}});function iH(t){return t==="~"||t.startsWith("~/")?t.replace(/^~/,(0,rH.homedir)()):t}function JSe(t){if(!t||t.trim()==="")return _.warn("PROJECT_NAME","Empty cwd provided, using fallback",{cwd:t}),"unknown-project";let e=iH(t),r=nH.default.basename(e);if(r===""){if(process.platform==="win32"){let i=t.match(/^([A-Z]):\\/i);if(i){let o=`drive-${i[1].toUpperCase()}`;return _.info("PROJECT_NAME","Drive root detected",{cwd:t,projectName:o}),o}}return _.warn("PROJECT_NAME","Root directory detected, using fallback",{cwd:t}),"unknown-project"}return r}function zn(t){let e=JSe(t);if(!t)return{primary:e,parent:null,isWorktree:!1,allProjects:[e]};let r=iH(t),n=eH(r);if(n.isWorktree&&n.parentProjectName){let i=Array.from(new Set([n.parentProjectName,e]));return{primary:n.parentProjectName,parent:n.parentProjectName,isWorktree:!0,allProjects:i}}return{primary:e,parent:null,isWorktree:!1,allProjects:[e]}}var rH,nH,Fa=he(()=>{"use strict";rH=require("os"),nH=Oe(require("path"),1);Q();tH()});function XSe(t){let e=t.startsWith("~")?(0,sH.homedir)()+t.slice(1):t;e=e.replace(/\\/g,"/");let r=e.replace(/[.+^${}()|[\]\\]/g,"\\$&");return r=r.replace(/\*\*/g,"<<>>").replace(/\*/g,"[^/]*").replace(/\?/g,"[^/]").replace(/<<>>/g,".*"),new RegExp(`^${r}$`)}function nl(t,e){if(!e||!e.trim())return!1;let r=t.replace(/\\/g,"/"),n=e.split(",").map(i=>i.trim()).filter(Boolean);for(let i of n)try{if(XSe(i).test(r))return!0}catch{continue}return!1}var sH,qy=he(()=>{"use strict";sH=require("os")});var Mm,Hy=he(()=>{"use strict";Rr();Fa();Q();fn();qy();Yt();$t();_i();Mm={async execute(t){if(!await or())return{continue:!0,suppressOutput:!0,exitCode:nt.SUCCESS};let{sessionId:r,cwd:n,prompt:i}=t;if(!r)return _.warn("HOOK","session-init: No sessionId provided, skipping (Codex CLI or unknown platform)"),{continue:!0,suppressOutput:!0,exitCode:nt.SUCCESS};let s=ge.loadFromFile(lt);if(n&&nl(n,s.CLAUDE_MEM_EXCLUDED_PROJECTS))return _.info("HOOK","Project excluded from tracking",{cwd:n}),{continue:!0,suppressOutput:!0};let o=!i||!i.trim()?"[media prompt]":i,a=zn(n).primary,c=bt(t.platform);_.debug("HOOK","session-init: Calling /api/sessions/init",{contentSessionId:r,project:a});let u=await ct("/api/sessions/init",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({contentSessionId:r,project:a,prompt:o,platformSource:c})});if(!u.ok)return _.failure("HOOK",`Session initialization failed: ${u.status}`,{contentSessionId:r,project:a}),{continue:!0,suppressOutput:!0,exitCode:nt.SUCCESS};let l=await u.json(),d=l.sessionDbId,p=l.promptNumber;if(_.debug("HOOK","session-init: Received from /api/sessions/init",{sessionDbId:d,promptNumber:p,skipped:l.skipped,contextInjected:l.contextInjected}),_.debug("HOOK",`[ALIGNMENT] Hook Entry | contentSessionId=${r} | prompt#=${p} | sessionDbId=${d}`),l.skipped&&l.reason==="private")return _.info("HOOK",`INIT_COMPLETE | sessionDbId=${d} | promptNumber=${p} | skipped=true | reason=private`,{sessionId:d}),{continue:!0,suppressOutput:!0};let m=!!l.contextInjected;if(m&&_.info("HOOK",`INIT_COMPLETE | sessionDbId=${d} | promptNumber=${p} | skipped_agent_init=true | reason=context_already_injected`,{sessionId:d}),!m&&t.platform!=="cursor"&&d){let g=o.startsWith("/")?o.substring(1):o;_.debug("HOOK","session-init: Calling /sessions/{sessionDbId}/init",{sessionDbId:d,promptNumber:p});let v=await ct(`/sessions/${d}/init`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({userPrompt:g,promptNumber:p})});v.ok||_.failure("HOOK",`SDK agent start failed: ${v.status}`,{sessionDbId:d,promptNumber:p})}else!m&&t.platform==="cursor"&&_.debug("HOOK","session-init: Skipping SDK agent init for Cursor platform",{sessionDbId:d,promptNumber:p});let f=String(s.CLAUDE_MEM_SEMANTIC_INJECT).toLowerCase()==="true",h="";if(f&&o&&o.length>=20&&o!=="[media prompt]")try{let g=s.CLAUDE_MEM_SEMANTIC_INJECT_LIMIT||"5",v=await ct("/api/context/semantic",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({q:o,project:a,limit:g})});if(v.ok){let y=await v.json();y.context&&(h=y.context,_.debug("HOOK",`Semantic injection: ${y.count} observations for prompt`,{sessionId:d,count:y.count}))}}catch(g){_.debug("HOOK","Semantic injection unavailable",{error:g instanceof Error?g.message:String(g)})}return _.info("HOOK",`INIT_COMPLETE | sessionDbId=${d} | promptNumber=${p} | project=${a}`,{sessionId:d}),h?{continue:!0,suppressOutput:!0,hookSpecificOutput:{hookEventName:"UserPromptSubmit",additionalContext:h}}:{continue:!0,suppressOutput:!0}}}});var Dm,Zy=he(()=>{"use strict";Rr();Q();fn();qy();Yt();$t();_i();Dm={async execute(t){if(!await or())return{continue:!0,suppressOutput:!0,exitCode:nt.SUCCESS};let{sessionId:r,cwd:n,toolName:i,toolInput:s,toolResponse:o}=t,a=bt(t.platform);if(!i)return{continue:!0,suppressOutput:!0,exitCode:nt.SUCCESS};let c=_.formatTool(i,s);if(_.dataIn("HOOK",`PostToolUse: ${c}`,{}),!n)throw new Error(`Missing cwd in PostToolUse hook input for session ${r}, tool ${i}`);let u=ge.loadFromFile(lt);if(nl(n,u.CLAUDE_MEM_EXCLUDED_PROJECTS))return _.debug("HOOK","Project excluded from tracking, skipping observation",{cwd:n,toolName:i}),{continue:!0,suppressOutput:!0};try{let l=await ct("/api/sessions/observations",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({contentSessionId:r,platformSource:a,tool_name:i,tool_input:s,tool_response:o,cwd:n})});if(!l.ok)return _.warn("HOOK","Observation storage failed, skipping",{status:l.status,toolName:i}),{continue:!0,suppressOutput:!0,exitCode:nt.SUCCESS};_.debug("HOOK","Observation sent successfully",{toolName:i})}catch(l){return _.warn("HOOK","Observation fetch error, skipping",{error:l instanceof Error?l.message:String(l)}),{continue:!0,suppressOutput:!0,exitCode:nt.SUCCESS}}return{continue:!0,suppressOutput:!0}}}});var jm,By=he(()=>{"use strict";Rr();Q();fn();_i();jm={async execute(t){if(!await or())return{continue:!0,suppressOutput:!0,exitCode:nt.SUCCESS};let{sessionId:r,cwd:n,filePath:i,edits:s}=t,o=bt(t.platform);if(!i)throw new Error("fileEditHandler requires filePath");if(_.dataIn("HOOK",`FileEdit: ${i}`,{editCount:s?.length??0}),!n)throw new Error(`Missing cwd in FileEdit hook input for session ${r}, file ${i}`);try{let a=await ct("/api/sessions/observations",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({contentSessionId:r,platformSource:o,tool_name:"write_file",tool_input:{filePath:i,edits:s},tool_response:{success:!0},cwd:n})});if(!a.ok)return _.warn("HOOK","File edit observation storage failed, skipping",{status:a.status,filePath:i}),{continue:!0,suppressOutput:!0,exitCode:nt.SUCCESS};_.debug("HOOK","File edit observation sent successfully",{filePath:i})}catch(a){return _.warn("HOOK","File edit observation fetch error, skipping",{error:a instanceof Error?a.message:String(a)}),{continue:!0,suppressOutput:!0,exitCode:nt.SUCCESS}}return{continue:!0,suppressOutput:!0}}}});var zm,Gy=he(()=>{"use strict";Rr();Q();_i();zm={async execute(t){if(!await or())return{continue:!0,suppressOutput:!0};let{sessionId:r}=t,n=bt(t.platform);if(!r)return _.warn("HOOK","session-complete: Missing sessionId, skipping"),{continue:!0,suppressOutput:!0};_.info("HOOK","\u2192 session-complete: Removing session from active map",{contentSessionId:r});try{let i=await ct("/api/sessions/complete",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({contentSessionId:r,platformSource:n})});if(i.ok)_.info("HOOK","Session completed successfully",{contentSessionId:r});else{let s=await i.text();_.warn("HOOK","session-complete: Failed to complete session",{status:i.status,body:s})}}catch(i){_.warn("HOOK","session-complete: Error completing session",{error:i.message})}return{continue:!0,suppressOutput:!0}}}});function QSe(t){let e=(t.match(//g)||[]).length,r=(t.match(//g)||[]).length,n=(t.match(//g)||[]).length,i=(t.match(//g)||[]).length,s=(t.match(//g)||[]).length,o=(t.match(//g)||[]).length;return e+r+n+i+s+o}function mH(t){let e=QSe(t);return e>pH&&_.warn("SYSTEM","tag count exceeds limit",void 0,{tagCount:e,maxAllowed:pH,contentLength:t.length}),t.replace(/[\s\S]*?<\/claude-mem-context>/g,"").replace(/[\s\S]*?<\/private>/g,"").replace(/[\s\S]*?<\/system_instruction>/g,"").replace(/[\s\S]*?<\/system-instruction>/g,"").replace(/[\s\S]*?<\/persisted-output>/g,"").replace(sl,"").trim()}function jI(t){return mH(t)}function fH(t){return mH(t)}var sl,pH,e_=he(()=>{"use strict";Q();sl=/[\s\S]*?<\/system-reminder>/g,pH=100});function LI(){let t=vH.default.join((0,yH.homedir)(),".claude-mem","settings.json"),e=ge.loadFromFile(t),r=He.getInstance().getActiveMode(),n=new Set(r.observation_types.map(s=>s.id)),i=new Set(r.observation_concepts.map(s=>s.id));return{totalObservationCount:parseInt(e.CLAUDE_MEM_CONTEXT_OBSERVATIONS,10),fullObservationCount:parseInt(e.CLAUDE_MEM_CONTEXT_FULL_COUNT,10),sessionCount:parseInt(e.CLAUDE_MEM_CONTEXT_SESSION_COUNT,10),showReadTokens:e.CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS==="true",showWorkTokens:e.CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS==="true",showSavingsAmount:e.CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT==="true",showSavingsPercent:e.CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT==="true",observationTypes:n,observationConcepts:i,fullObservationField:e.CLAUDE_MEM_CONTEXT_FULL_FIELD,showLastSummary:e.CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY==="true",showLastMessage:e.CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE==="true"}}var vH,yH,UI=he(()=>{"use strict";vH=Oe(require("path"),1),yH=require("os");Yt();en()});var Y,_H,FI,Um=he(()=>{"use strict";Y={reset:"\x1B[0m",bright:"\x1B[1m",dim:"\x1B[2m",cyan:"\x1B[36m",green:"\x1B[32m",yellow:"\x1B[33m",blue:"\x1B[34m",magenta:"\x1B[35m",gray:"\x1B[90m",red:"\x1B[31m"},_H=4,FI=1});function qI(t){let e=(t.title?.length||0)+(t.subtitle?.length||0)+(t.narrative?.length||0)+JSON.stringify(t.facts||[]).length;return Math.ceil(e/_H)}function HI(t){let e=t.length,r=t.reduce((o,a)=>o+qI(a),0),n=t.reduce((o,a)=>o+(a.discovery_tokens||0),0),i=n-r,s=n>0?Math.round(i/n*100):0;return{totalObservations:e,totalReadTokens:r,totalDiscoveryTokens:n,savings:i,savingsPercent:s}}function exe(t){return He.getInstance().getWorkEmoji(t)}function Fm(t,e){let r=qI(t),n=t.discovery_tokens||0,i=exe(t.type),s=n>0?`${i} ${n.toLocaleString()}`:"-";return{readTokens:r,discoveryTokens:n,discoveryDisplay:s,workEmoji:i}}function i_(t){return t.showReadTokens||t.showWorkTokens||t.showSavingsAmount||t.showSavingsPercent}var qa=he(()=>{"use strict";Um();en()});function ZI(t,e,r,n){let i=Array.from(r.observationTypes),s=i.map(()=>"?").join(","),o=Array.from(r.observationConcepts),a=o.map(()=>"?").join(",");return t.db.prepare(` +`)}groupByDay(e){let r=new Map;for(let n of e){let i=Ms(n.epoch);r.has(i)||r.set(i,[]),r.get(i).push(n)}return r}sortDaysChronologically(e){return Array.from(e.entries()).sort((r,n)=>{let i=new Date(r[0]).getTime(),s=new Date(n[0]).getTime();return i-s})}isAnchorItem(e,r){return r===null?!1:typeof r=="number"&&e.type==="observation"?e.data.id===r:typeof r=="string"&&r.startsWith("S")&&e.type==="session"?`S${e.data.id}`===r:!1}}});var j9={};cn(j9,{SearchOrchestrator:()=>Xu});var Xu,bI=he(()=>{"use strict";hI();gI();vI();yI();_I();Q();Xu=class{constructor(e,r,n){this.sessionSearch=e;this.sessionStore=r;this.chromaSync=n;this.sqliteStrategy=new _m(e),n&&(this.chromaStrategy=new ym(n,r),this.hybridStrategy=new bm(n,r,e)),this.resultFormatter=new Sm,this.timelineBuilder=new ja}sessionSearch;sessionStore;chromaSync;chromaStrategy=null;sqliteStrategy;hybridStrategy=null;resultFormatter;timelineBuilder;async search(e){let r=this.normalizeParams(e);return await this.executeWithFallback(r)}async executeWithFallback(e){if(!e.query)return _.debug("SEARCH","Orchestrator: Filter-only query, using SQLite",{}),await this.sqliteStrategy.search(e);if(this.chromaStrategy){_.debug("SEARCH","Orchestrator: Using Chroma semantic search",{});let r=await this.chromaStrategy.search(e);return r.usedChroma?r:(_.debug("SEARCH","Orchestrator: Chroma failed, falling back to SQLite",{}),{...await this.sqliteStrategy.search({...e,query:void 0}),fellBack:!0})}return _.debug("SEARCH","Orchestrator: Chroma not available",{}),{results:{observations:[],sessions:[],prompts:[]},usedChroma:!1,fellBack:!1,strategy:"sqlite"}}async findByConcept(e,r){let n=this.normalizeParams(r);return this.hybridStrategy?await this.hybridStrategy.findByConcept(e,n):{results:{observations:this.sqliteStrategy.findByConcept(e,n),sessions:[],prompts:[]},usedChroma:!1,fellBack:!1,strategy:"sqlite"}}async findByType(e,r){let n=this.normalizeParams(r);return this.hybridStrategy?await this.hybridStrategy.findByType(e,n):{results:{observations:this.sqliteStrategy.findByType(e,n),sessions:[],prompts:[]},usedChroma:!1,fellBack:!1,strategy:"sqlite"}}async findByFile(e,r){let n=this.normalizeParams(r);return this.hybridStrategy?await this.hybridStrategy.findByFile(e,n):{...this.sqliteStrategy.findByFile(e,n),usedChroma:!1}}getTimeline(e,r,n,i,s){let o=this.timelineBuilder.buildTimeline(e);return this.timelineBuilder.filterByDepth(o,r,n,i,s)}formatTimeline(e,r,n={}){return this.timelineBuilder.formatTimeline(e,r,n)}formatSearchResults(e,r,n=!1){return this.resultFormatter.formatSearchResults(e,r,n)}getFormatter(){return this.resultFormatter}getTimelineBuilder(){return this.timelineBuilder}normalizeParams(e){let r={...e};return r.concepts&&typeof r.concepts=="string"&&(r.concepts=r.concepts.split(",").map(n=>n.trim()).filter(Boolean)),r.files&&typeof r.files=="string"&&(r.files=r.files.split(",").map(n=>n.trim()).filter(Boolean)),r.obs_type&&typeof r.obs_type=="string"&&(r.obsType=r.obs_type.split(",").map(n=>n.trim()).filter(Boolean),delete r.obs_type),r.type&&typeof r.type=="string"&&r.type.includes(",")&&(r.type=r.type.split(",").map(n=>n.trim()).filter(Boolean)),r.type&&!r.searchType&&["observations","sessions","prompts"].includes(r.type)&&(r.searchType=r.type,delete r.type),(r.dateStart||r.dateEnd)&&(r.dateRange={start:r.dateStart,end:r.dateEnd},delete r.dateStart,delete r.dateEnd),r}isChromaAvailable(){return!!this.chromaSync}}});function eH(t){let e=Uy.default.join(t,".git"),r;try{r=(0,Fy.statSync)(e)}catch{return Nm}if(!r.isFile())return Nm;let n;try{n=(0,Fy.readFileSync)(e,"utf-8").trim()}catch{return Nm}let i=n.match(/^gitdir:\s*(.+)$/);if(!i)return Nm;let o=i[1].match(/^(.+)[/\\]\.git[/\\]worktrees[/\\]([^/\\]+)$/);if(!o)return Nm;let a=o[1],c=Uy.default.basename(t),u=Uy.default.basename(a);return{isWorktree:!0,worktreeName:c,parentRepoPath:a,parentProjectName:u}}var Fy,Uy,Nm,tH=he(()=>{"use strict";Fy=require("fs"),Uy=Oe(require("path"),1),Nm={isWorktree:!1,worktreeName:null,parentRepoPath:null,parentProjectName:null}});function iH(t){return t==="~"||t.startsWith("~/")?t.replace(/^~/,(0,rH.homedir)()):t}function JSe(t){if(!t||t.trim()==="")return _.warn("PROJECT_NAME","Empty cwd provided, using fallback",{cwd:t}),"unknown-project";let e=iH(t),r=nH.default.basename(e);if(r===""){if(process.platform==="win32"){let i=t.match(/^([A-Z]):\\/i);if(i){let o=`drive-${i[1].toUpperCase()}`;return _.info("PROJECT_NAME","Drive root detected",{cwd:t,projectName:o}),o}}return _.warn("PROJECT_NAME","Root directory detected, using fallback",{cwd:t}),"unknown-project"}return r}function zn(t){let e=JSe(t);if(!t)return{primary:e,parent:null,isWorktree:!1,allProjects:[e]};let r=iH(t),n=eH(r);if(n.isWorktree&&n.parentProjectName){let i=`${n.parentProjectName}/${e}`;return{primary:i,parent:n.parentProjectName,isWorktree:!0,allProjects:[i]}}return{primary:e,parent:null,isWorktree:!1,allProjects:[e]}}var rH,nH,Fa=he(()=>{"use strict";rH=require("os"),nH=Oe(require("path"),1);Q();tH()});function XSe(t){let e=t.startsWith("~")?(0,sH.homedir)()+t.slice(1):t;e=e.replace(/\\/g,"/");let r=e.replace(/[.+^${}()|[\]\\]/g,"\\$&");return r=r.replace(/\*\*/g,"<<>>").replace(/\*/g,"[^/]*").replace(/\?/g,"[^/]").replace(/<<>>/g,".*"),new RegExp(`^${r}$`)}function nl(t,e){if(!e||!e.trim())return!1;let r=t.replace(/\\/g,"/"),n=e.split(",").map(i=>i.trim()).filter(Boolean);for(let i of n)try{if(XSe(i).test(r))return!0}catch{continue}return!1}var sH,qy=he(()=>{"use strict";sH=require("os")});var Mm,Hy=he(()=>{"use strict";Rr();Fa();Q();fn();qy();Yt();$t();_i();Mm={async execute(t){if(!await or())return{continue:!0,suppressOutput:!0,exitCode:nt.SUCCESS};let{sessionId:r,cwd:n,prompt:i}=t;if(!r)return _.warn("HOOK","session-init: No sessionId provided, skipping (Codex CLI or unknown platform)"),{continue:!0,suppressOutput:!0,exitCode:nt.SUCCESS};let s=ge.loadFromFile(lt);if(n&&nl(n,s.CLAUDE_MEM_EXCLUDED_PROJECTS))return _.info("HOOK","Project excluded from tracking",{cwd:n}),{continue:!0,suppressOutput:!0};let o=!i||!i.trim()?"[media prompt]":i,a=zn(n).primary,c=bt(t.platform);_.debug("HOOK","session-init: Calling /api/sessions/init",{contentSessionId:r,project:a});let u=await ct("/api/sessions/init",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({contentSessionId:r,project:a,prompt:o,platformSource:c})});if(!u.ok)return _.failure("HOOK",`Session initialization failed: ${u.status}`,{contentSessionId:r,project:a}),{continue:!0,suppressOutput:!0,exitCode:nt.SUCCESS};let l=await u.json(),d=l.sessionDbId,p=l.promptNumber;if(_.debug("HOOK","session-init: Received from /api/sessions/init",{sessionDbId:d,promptNumber:p,skipped:l.skipped,contextInjected:l.contextInjected}),_.debug("HOOK",`[ALIGNMENT] Hook Entry | contentSessionId=${r} | prompt#=${p} | sessionDbId=${d}`),l.skipped&&l.reason==="private")return _.info("HOOK",`INIT_COMPLETE | sessionDbId=${d} | promptNumber=${p} | skipped=true | reason=private`,{sessionId:d}),{continue:!0,suppressOutput:!0};let m=!!l.contextInjected;if(m&&_.info("HOOK",`INIT_COMPLETE | sessionDbId=${d} | promptNumber=${p} | skipped_agent_init=true | reason=context_already_injected`,{sessionId:d}),!m&&t.platform!=="cursor"&&d){let g=o.startsWith("/")?o.substring(1):o;_.debug("HOOK","session-init: Calling /sessions/{sessionDbId}/init",{sessionDbId:d,promptNumber:p});let v=await ct(`/sessions/${d}/init`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({userPrompt:g,promptNumber:p})});v.ok||_.failure("HOOK",`SDK agent start failed: ${v.status}`,{sessionDbId:d,promptNumber:p})}else!m&&t.platform==="cursor"&&_.debug("HOOK","session-init: Skipping SDK agent init for Cursor platform",{sessionDbId:d,promptNumber:p});let f=String(s.CLAUDE_MEM_SEMANTIC_INJECT).toLowerCase()==="true",h="";if(f&&o&&o.length>=20&&o!=="[media prompt]")try{let g=s.CLAUDE_MEM_SEMANTIC_INJECT_LIMIT||"5",v=await ct("/api/context/semantic",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({q:o,project:a,limit:g})});if(v.ok){let y=await v.json();y.context&&(h=y.context,_.debug("HOOK",`Semantic injection: ${y.count} observations for prompt`,{sessionId:d,count:y.count}))}}catch(g){_.debug("HOOK","Semantic injection unavailable",{error:g instanceof Error?g.message:String(g)})}return _.info("HOOK",`INIT_COMPLETE | sessionDbId=${d} | promptNumber=${p} | project=${a}`,{sessionId:d}),h?{continue:!0,suppressOutput:!0,hookSpecificOutput:{hookEventName:"UserPromptSubmit",additionalContext:h}}:{continue:!0,suppressOutput:!0}}}});var Dm,Zy=he(()=>{"use strict";Rr();Q();fn();qy();Yt();$t();_i();Dm={async execute(t){if(!await or())return{continue:!0,suppressOutput:!0,exitCode:nt.SUCCESS};let{sessionId:r,cwd:n,toolName:i,toolInput:s,toolResponse:o}=t,a=bt(t.platform);if(!i)return{continue:!0,suppressOutput:!0,exitCode:nt.SUCCESS};let c=_.formatTool(i,s);if(_.dataIn("HOOK",`PostToolUse: ${c}`,{}),!n)throw new Error(`Missing cwd in PostToolUse hook input for session ${r}, tool ${i}`);let u=ge.loadFromFile(lt);if(nl(n,u.CLAUDE_MEM_EXCLUDED_PROJECTS))return _.debug("HOOK","Project excluded from tracking, skipping observation",{cwd:n,toolName:i}),{continue:!0,suppressOutput:!0};try{let l=await ct("/api/sessions/observations",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({contentSessionId:r,platformSource:a,tool_name:i,tool_input:s,tool_response:o,cwd:n})});if(!l.ok)return _.warn("HOOK","Observation storage failed, skipping",{status:l.status,toolName:i}),{continue:!0,suppressOutput:!0,exitCode:nt.SUCCESS};_.debug("HOOK","Observation sent successfully",{toolName:i})}catch(l){return _.warn("HOOK","Observation fetch error, skipping",{error:l instanceof Error?l.message:String(l)}),{continue:!0,suppressOutput:!0,exitCode:nt.SUCCESS}}return{continue:!0,suppressOutput:!0}}}});var jm,By=he(()=>{"use strict";Rr();Q();fn();_i();jm={async execute(t){if(!await or())return{continue:!0,suppressOutput:!0,exitCode:nt.SUCCESS};let{sessionId:r,cwd:n,filePath:i,edits:s}=t,o=bt(t.platform);if(!i)throw new Error("fileEditHandler requires filePath");if(_.dataIn("HOOK",`FileEdit: ${i}`,{editCount:s?.length??0}),!n)throw new Error(`Missing cwd in FileEdit hook input for session ${r}, file ${i}`);try{let a=await ct("/api/sessions/observations",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({contentSessionId:r,platformSource:o,tool_name:"write_file",tool_input:{filePath:i,edits:s},tool_response:{success:!0},cwd:n})});if(!a.ok)return _.warn("HOOK","File edit observation storage failed, skipping",{status:a.status,filePath:i}),{continue:!0,suppressOutput:!0,exitCode:nt.SUCCESS};_.debug("HOOK","File edit observation sent successfully",{filePath:i})}catch(a){return _.warn("HOOK","File edit observation fetch error, skipping",{error:a instanceof Error?a.message:String(a)}),{continue:!0,suppressOutput:!0,exitCode:nt.SUCCESS}}return{continue:!0,suppressOutput:!0}}}});var zm,Gy=he(()=>{"use strict";Rr();Q();_i();zm={async execute(t){if(!await or())return{continue:!0,suppressOutput:!0};let{sessionId:r}=t,n=bt(t.platform);if(!r)return _.warn("HOOK","session-complete: Missing sessionId, skipping"),{continue:!0,suppressOutput:!0};_.info("HOOK","\u2192 session-complete: Removing session from active map",{contentSessionId:r});try{let i=await ct("/api/sessions/complete",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({contentSessionId:r,platformSource:n})});if(i.ok)_.info("HOOK","Session completed successfully",{contentSessionId:r});else{let s=await i.text();_.warn("HOOK","session-complete: Failed to complete session",{status:i.status,body:s})}}catch(i){_.warn("HOOK","session-complete: Error completing session",{error:i.message})}return{continue:!0,suppressOutput:!0}}}});function QSe(t){let e=(t.match(//g)||[]).length,r=(t.match(//g)||[]).length,n=(t.match(//g)||[]).length,i=(t.match(//g)||[]).length,s=(t.match(//g)||[]).length,o=(t.match(//g)||[]).length;return e+r+n+i+s+o}function mH(t){let e=QSe(t);return e>pH&&_.warn("SYSTEM","tag count exceeds limit",void 0,{tagCount:e,maxAllowed:pH,contentLength:t.length}),t.replace(/[\s\S]*?<\/claude-mem-context>/g,"").replace(/[\s\S]*?<\/private>/g,"").replace(/[\s\S]*?<\/system_instruction>/g,"").replace(/[\s\S]*?<\/system-instruction>/g,"").replace(/[\s\S]*?<\/persisted-output>/g,"").replace(sl,"").trim()}function jI(t){return mH(t)}function fH(t){return mH(t)}var sl,pH,e_=he(()=>{"use strict";Q();sl=/[\s\S]*?<\/system-reminder>/g,pH=100});function LI(){let t=vH.default.join((0,yH.homedir)(),".claude-mem","settings.json"),e=ge.loadFromFile(t),r=He.getInstance().getActiveMode(),n=new Set(r.observation_types.map(s=>s.id)),i=new Set(r.observation_concepts.map(s=>s.id));return{totalObservationCount:parseInt(e.CLAUDE_MEM_CONTEXT_OBSERVATIONS,10),fullObservationCount:parseInt(e.CLAUDE_MEM_CONTEXT_FULL_COUNT,10),sessionCount:parseInt(e.CLAUDE_MEM_CONTEXT_SESSION_COUNT,10),showReadTokens:e.CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS==="true",showWorkTokens:e.CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS==="true",showSavingsAmount:e.CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT==="true",showSavingsPercent:e.CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT==="true",observationTypes:n,observationConcepts:i,fullObservationField:e.CLAUDE_MEM_CONTEXT_FULL_FIELD,showLastSummary:e.CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY==="true",showLastMessage:e.CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE==="true"}}var vH,yH,UI=he(()=>{"use strict";vH=Oe(require("path"),1),yH=require("os");Yt();en()});var Y,_H,FI,Um=he(()=>{"use strict";Y={reset:"\x1B[0m",bright:"\x1B[1m",dim:"\x1B[2m",cyan:"\x1B[36m",green:"\x1B[32m",yellow:"\x1B[33m",blue:"\x1B[34m",magenta:"\x1B[35m",gray:"\x1B[90m",red:"\x1B[31m"},_H=4,FI=1});function qI(t){let e=(t.title?.length||0)+(t.subtitle?.length||0)+(t.narrative?.length||0)+JSON.stringify(t.facts||[]).length;return Math.ceil(e/_H)}function HI(t){let e=t.length,r=t.reduce((o,a)=>o+qI(a),0),n=t.reduce((o,a)=>o+(a.discovery_tokens||0),0),i=n-r,s=n>0?Math.round(i/n*100):0;return{totalObservations:e,totalReadTokens:r,totalDiscoveryTokens:n,savings:i,savingsPercent:s}}function exe(t){return He.getInstance().getWorkEmoji(t)}function Fm(t,e){let r=qI(t),n=t.discovery_tokens||0,i=exe(t.type),s=n>0?`${i} ${n.toLocaleString()}`:"-";return{readTokens:r,discoveryTokens:n,discoveryDisplay:s,workEmoji:i}}function i_(t){return t.showReadTokens||t.showWorkTokens||t.showSavingsAmount||t.showSavingsPercent}var qa=he(()=>{"use strict";Um();en()});function ZI(t,e,r,n){let i=Array.from(r.observationTypes),s=i.map(()=>"?").join(","),o=Array.from(r.observationConcepts),a=o.map(()=>"?").join(",");return t.db.prepare(` SELECT o.id, o.memory_session_id, diff --git a/scripts/worktree-remap.ts b/scripts/worktree-remap.ts new file mode 100644 index 00000000..2cecc253 --- /dev/null +++ b/scripts/worktree-remap.ts @@ -0,0 +1,170 @@ +#!/usr/bin/env bun +/** + * worktree-remap — Retroactively reattribute past sessions that were written + * with a plain project name (e.g. `claude-mem`) to the `parent/worktree` + * composite name when the original worktree can be inferred from the paths + * in the session's observations or user prompt. + * + * Only sessions with HIGH-CONFIDENCE worktree path signatures are remapped. + * Everything else is left alone. + * + * Usage: + * bun scripts/worktree-remap.ts # dry-run (default) + * bun scripts/worktree-remap.ts --apply # write changes in a transaction + */ + +import { Database } from 'bun:sqlite'; +import { homedir } from 'os'; +import { join } from 'path'; +import { existsSync, copyFileSync } from 'fs'; + +const DB_PATH = join(homedir(), '.claude-mem', 'claude-mem.db'); +const APPLY = process.argv.includes('--apply'); + +const WORKTREE_PATTERNS: Array<{ name: string; regex: RegExp }> = [ + { name: 'conductor', regex: /\/conductor\/workspaces\/([^/]+)\/([^/"'\s)]+)/ }, + { name: 'superset', regex: /\/\.superset\/worktrees\/([^/]+)\/([^/"'\s)]+)/ }, +]; + +interface SessionRow { + id: number; + memory_session_id: string | null; + project: string; + user_prompt: string | null; +} + +function allMatches(text: string | null | undefined): Array<{ parent: string; worktree: string }> { + if (!text) return []; + const results: Array<{ parent: string; worktree: string }> = []; + for (const p of WORKTREE_PATTERNS) { + const global = new RegExp(p.regex.source, 'g'); + let m: RegExpExecArray | null; + while ((m = global.exec(text)) !== null) { + results.push({ parent: m[1], worktree: m[2] }); + } + } + return results; +} + +/** + * Collects every worktree path match across the session's observations + user prompt, + * then picks the inference using this priority: + * 1. A match whose worktree basename === the session's current plain project name. + * (Pre-#1820 sessions stored the worktree basename as `project` — these are trusted.) + * 2. If none match the current project, and there's a single unambiguous (parent, worktree) + * across ALL signals, use it. + * 3. Otherwise skip (ambiguous — likely cross-worktree reads). + */ +function inferWorktree( + db: Database, + memorySessionId: string | null, + userPrompt: string | null, + currentProject: string +): { parent: string; worktree: string } | null { + const matches: Array<{ parent: string; worktree: string }> = []; + + if (memorySessionId) { + const rows = db.prepare(` + SELECT files_read, files_modified, source_input_summary, metadata + FROM observations + WHERE memory_session_id = ? + AND (files_read LIKE '%/conductor/workspaces/%' OR files_modified LIKE '%/conductor/workspaces/%' + OR source_input_summary LIKE '%/conductor/workspaces/%' OR metadata LIKE '%/conductor/workspaces/%' + OR files_read LIKE '%.superset/worktrees/%' OR files_modified LIKE '%.superset/worktrees/%' + OR source_input_summary LIKE '%.superset/worktrees/%' OR metadata LIKE '%.superset/worktrees/%') + `).all(memorySessionId) as Array<{ files_read: string | null; files_modified: string | null; source_input_summary: string | null; metadata: string | null }>; + + for (const r of rows) { + matches.push(...allMatches(r.files_read)); + matches.push(...allMatches(r.files_modified)); + matches.push(...allMatches(r.source_input_summary)); + matches.push(...allMatches(r.metadata)); + } + } + + matches.push(...allMatches(userPrompt)); + if (matches.length === 0) return null; + + const wtMatch = matches.find(m => m.worktree === currentProject); + if (wtMatch) return wtMatch; + + const signatures = new Set(matches.map(m => `${m.parent}/${m.worktree}`)); + if (signatures.size === 1) return matches[0]; + + return null; +} + +function main() { + if (!existsSync(DB_PATH)) { + console.error(`DB not found at ${DB_PATH}`); + process.exit(1); + } + + if (APPLY) { + const backup = `${DB_PATH}.bak-worktree-remap-${Date.now()}`; + copyFileSync(DB_PATH, backup); + console.log(`Backup created: ${backup}`); + } + + const db = new Database(DB_PATH); + + const sessions = db.prepare(` + SELECT id, memory_session_id, project, user_prompt + FROM sdk_sessions + WHERE project NOT LIKE '%/%' AND project != '' + `).all() as SessionRow[]; + + console.log(`Scanning ${sessions.length} plain-project sessions...`); + + type Remap = { sessionId: number; memorySessionId: string | null; oldProject: string; newProject: string }; + const remaps: Remap[] = []; + const summary = new Map(); + + for (const s of sessions) { + const hit = inferWorktree(db, s.memory_session_id, s.user_prompt, s.project); + if (!hit) continue; + + const newProject = `${hit.parent}/${hit.worktree}`; + if (newProject === s.project) continue; + + remaps.push({ sessionId: s.id, memorySessionId: s.memory_session_id, oldProject: s.project, newProject }); + const key = `${s.project} → ${newProject}`; + const entry = summary.get(key); + if (entry) entry.count++; + else summary.set(key, { count: 1, firstExample: s.id }); + } + + const rows = Array.from(summary.entries()) + .map(([mapping, v]) => ({ mapping, sessions: v.count, exampleSessionId: v.firstExample })) + .sort((a, b) => b.sessions - a.sessions); + + console.log('\nRemap summary:'); + console.table(rows); + console.log(`\nTotal sessions to remap: ${remaps.length}`); + + if (!APPLY) { + console.log('\nDry-run only. Re-run with --apply to perform UPDATEs.'); + return; + } + + console.log('\nApplying updates in a single transaction...'); + const updateSession = db.prepare('UPDATE sdk_sessions SET project=? WHERE id=?'); + const updateObs = db.prepare('UPDATE observations SET project=? WHERE memory_session_id=?'); + const updateSum = db.prepare('UPDATE session_summaries SET project=? WHERE memory_session_id=?'); + + let sessionUpdates = 0, obsUpdates = 0, sumUpdates = 0; + const tx = db.transaction(() => { + for (const r of remaps) { + sessionUpdates += updateSession.run(r.newProject, r.sessionId).changes; + if (r.memorySessionId) { + obsUpdates += updateObs.run(r.newProject, r.memorySessionId).changes; + sumUpdates += updateSum.run(r.newProject, r.memorySessionId).changes; + } + } + }); + tx(); + + console.log(`Done. sessions=${sessionUpdates} observations=${obsUpdates} session_summaries=${sumUpdates}`); +} + +main(); diff --git a/src/utils/project-name.ts b/src/utils/project-name.ts index eb52edf4..7c05e9b8 100644 --- a/src/utils/project-name.ts +++ b/src/utils/project-name.ts @@ -58,21 +58,24 @@ export function getProjectName(cwd: string | null | undefined): string { * Project context with worktree awareness */ export interface ProjectContext { - /** Canonical project name for writes/queries (parent repo in worktrees) */ + /** Canonical project name for writes/queries; `parent/worktree` when in a worktree */ primary: string; /** Parent project name if in a worktree, null otherwise */ parent: string | null; /** True if currently in a worktree */ isWorktree: boolean; - /** All projects to query: [primary] for main repo, [parentRepo, worktreeName] for worktree */ + /** Projects to query — always `[primary]` so observations don't cross worktrees */ allProjects: string[]; } /** * Get project context with worktree detection. * - * When in a worktree, returns both the worktree project name and parent project name - * for unified timeline queries. + * Each worktree is its own bucket. When in a worktree, `primary` is the + * composite `parent/worktree` (e.g. `claude-mem/dar-es-salaam`) so worktrees + * are uniquely identified and grouped under their parent project without + * mixing observations across them. In the main repo, `primary` is just the + * project basename. * * @param cwd - Current working directory (absolute path) * @returns ProjectContext with worktree info @@ -88,14 +91,12 @@ export function getProjectContext(cwd: string | null | undefined): ProjectContex const worktreeInfo = detectWorktree(expandedCwd); if (worktreeInfo.isWorktree && worktreeInfo.parentProjectName) { - // In a worktree: use parent project name as primary so observations - // are stored under the same project as the main repo (#1081, #1500, #1819) - const allProjects = Array.from(new Set([worktreeInfo.parentProjectName, cwdProjectName])); + const composite = `${worktreeInfo.parentProjectName}/${cwdProjectName}`; return { - primary: worktreeInfo.parentProjectName, + primary: composite, parent: worktreeInfo.parentProjectName, isWorktree: true, - allProjects + allProjects: [composite] }; } diff --git a/tests/utils/project-name.test.ts b/tests/utils/project-name.test.ts index 435d5701..cd52c939 100644 --- a/tests/utils/project-name.test.ts +++ b/tests/utils/project-name.test.ts @@ -97,7 +97,7 @@ describe('getProjectContext', () => { expect(ctx.parent).toBeNull(); }); - describe('worktree regression (#1081, #1500, #1819)', () => { + describe('worktree isolation', () => { let tmp: string; let mainRepo: string; let worktreeCheckout: string; @@ -125,21 +125,18 @@ describe('getProjectContext', () => { rmSync(tmp, { recursive: true, force: true }); }); - it('uses parent project name as primary when in a worktree', () => { + it('uses parent/worktree composite as primary when in a worktree', () => { const ctx = getProjectContext(worktreeCheckout); expect(ctx.isWorktree).toBe(true); - expect(ctx.primary).toBe('main-repo'); + expect(ctx.primary).toBe('main-repo/my-worktree'); expect(ctx.parent).toBe('main-repo'); - expect(ctx.allProjects).toEqual(['main-repo', 'my-worktree']); + expect(ctx.allProjects).toEqual(['main-repo/my-worktree']); }); - it('write-path call sites resolve to parent project in worktrees', () => { - // Mirrors the pattern used by session-init.ts and SessionRoutes.ts: - // const project = getProjectContext(cwd).primary; - // This must resolve to the parent repo, not the worktree name, - // so observations are stored under the correct project. + it('write-path call sites resolve to composite name in worktrees', () => { const project = getProjectContext(worktreeCheckout).primary; - expect(project).toBe('main-repo'); + expect(project).toBe('main-repo/my-worktree'); + expect(project).not.toBe('main-repo'); expect(project).not.toBe('my-worktree'); }); });