diff --git a/plugin/scripts/context-generator.cjs b/plugin/scripts/context-generator.cjs index beb8bcb1..a63f79db 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"?u=` `,"utf8")}catch(g){process.stderr.write(`[LOGGER] Failed to write to log file: ${g instanceof Error?g.message:String(g)} `)}else process.stderr.write(p+` `)}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 m=((new Error().stack||"").split(` -`)[2]||"").match(/at\s+(?:.*\s+)?\(?([^:]+):(\d+):(\d+)\)?/),u=m?`${m[1].split("/").pop()}:${m[2]}`:"unknown",E={...s,location:u};return this.warn(e,`[HAPPY-PATH] ${t}`,E,n),o}},c=new Z;var Ht={};function wt(){return typeof __dirname<"u"?__dirname:(0,S.dirname)((0,Ae.fileURLToPath)(Ht.url))}var Ft=wt();function $t(){if(process.env.CLAUDE_MEM_DATA_DIR)return process.env.CLAUDE_MEM_DATA_DIR;let r=(0,S.join)((0,ee.homedir)(),".claude-mem"),e=(0,S.join)(r,"settings.json");try{if((0,H.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 R=$t(),y=process.env.CLAUDE_CONFIG_DIR||(0,S.join)((0,ee.homedir)(),".claude"),us=(0,S.join)(y,"plugins","marketplaces","thedotmack"),ms=(0,S.join)(R,"archives"),cs=(0,S.join)(R,"logs"),ls=(0,S.join)(R,"trash"),ps=(0,S.join)(R,"backups"),Es=(0,S.join)(R,"modes"),gs=(0,S.join)(R,"settings.json"),Re=(0,S.join)(R,"claude-mem.db"),Ts=(0,S.join)(R,"vector-db"),Pt=(0,S.join)(R,"observer-sessions"),te=(0,S.basename)(Pt),fs=(0,S.join)(y,"settings.json"),Ss=(0,S.join)(y,"commands"),bs=(0,S.join)(y,"CLAUDE.md");function Ne(r){(0,H.mkdirSync)(r,{recursive:!0})}function Ce(){return(0,S.join)(Ft,"..")}var De=require("crypto");var Le=require("os"),ye=L(require("path"),1);var j=require("fs"),G=L(require("path"),1),U={isWorktree:!1,worktreeName:null,parentRepoPath:null,parentProjectName:null};function Ie(r){let e=G.default.join(r,".git"),t;try{t=(0,j.statSync)(e)}catch(u){return u instanceof Error&&u.code!=="ENOENT"&&console.warn("[worktree] Unexpected error checking .git:",u),U}if(!t.isFile())return U;let s;try{s=(0,j.readFileSync)(e,"utf-8").trim()}catch(u){return console.warn("[worktree] Failed to read .git file:",u instanceof Error?u.message:String(u)),U}let n=s.match(/^gitdir:\s*(.+)$/);if(!n)return U;let i=n[1].match(/^(.+)[/\\]\.git[/\\]worktrees[/\\]([^/\\]+)$/);if(!i)return U;let a=i[1],d=G.default.basename(r),m=G.default.basename(a);return{isWorktree:!0,worktreeName:d,parentRepoPath:a,parentProjectName:m}}function Me(r){return r==="~"||r.startsWith("~/")?r.replace(/^~/,(0,Le.homedir)()):r}function Gt(r){if(!r||r.trim()==="")return c.warn("PROJECT_NAME","Empty cwd provided, using fallback",{cwd:r}),"unknown-project";let e=Me(r),t=ye.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 c.info("PROJECT_NAME","Drive root detected",{cwd:r,projectName:i}),i}}return c.warn("PROJECT_NAME","Root directory detected, using fallback",{cwd:r}),"unknown-project"}return t}function se(r){let e=Gt(r);if(!r)return{primary:e,parent:null,isWorktree:!1,allProjects:[e]};let t=Me(r),s=Ie(t);if(s.isWorktree&&s.parentProjectName){let n=`${s.parentProjectName}/${e}`;return{primary:n,parent:s.parentProjectName,isWorktree:!0,allProjects:[s.parentProjectName,n]}}return{primary:e,parent:null,isWorktree:!1,allProjects:[e]}}function X(r,e,t){return(0,De.createHash)("sha256").update([r||"",e||"",t||""].join("\0")).digest("hex").slice(0,16)}function re(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 M(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 ve(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 Xt(r,e){return{customTitle:r,platformSource:e?M(e):void 0}}var B=class{db;constructor(e=Re){e instanceof ne.Database?this.db=e:(e!==":memory:"&&Ne(R),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.db.run("PRAGMA journal_size_limit = 4194304")),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(),this.ensureMergedIntoProjectColumns(),this.addObservationSubagentColumns(),this.addObservationsUniqueContentHashIndex()}initializeSchema(){this.db.run(` +`)[2]||"").match(/at\s+(?:.*\s+)?\(?([^:]+):(\d+):(\d+)\)?/),u=m?`${m[1].split("/").pop()}:${m[2]}`:"unknown",E={...s,location:u};return this.warn(e,`[HAPPY-PATH] ${t}`,E,n),o}},c=new Z;var Ht={};function wt(){return typeof __dirname<"u"?__dirname:(0,S.dirname)((0,Ae.fileURLToPath)(Ht.url))}var Ft=wt();function $t(){if(process.env.CLAUDE_MEM_DATA_DIR)return process.env.CLAUDE_MEM_DATA_DIR;let r=(0,S.join)((0,ee.homedir)(),".claude-mem"),e=(0,S.join)(r,"settings.json");try{if((0,H.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 R=$t(),y=process.env.CLAUDE_CONFIG_DIR||(0,S.join)((0,ee.homedir)(),".claude"),us=(0,S.join)(y,"plugins","marketplaces","thedotmack"),ms=(0,S.join)(R,"archives"),cs=(0,S.join)(R,"logs"),ls=(0,S.join)(R,"trash"),ps=(0,S.join)(R,"backups"),Es=(0,S.join)(R,"modes"),gs=(0,S.join)(R,"settings.json"),Re=(0,S.join)(R,"claude-mem.db"),Ts=(0,S.join)(R,"vector-db"),Pt=(0,S.join)(R,"observer-sessions"),te=(0,S.basename)(Pt),fs=(0,S.join)(y,"settings.json"),Ss=(0,S.join)(y,"commands"),bs=(0,S.join)(y,"CLAUDE.md");function Ne(r){(0,H.mkdirSync)(r,{recursive:!0})}function Ce(){return(0,S.join)(Ft,"..")}var De=require("crypto");var Le=require("os"),ye=L(require("path"),1);var j=require("fs"),G=L(require("path"),1),U={isWorktree:!1,worktreeName:null,parentRepoPath:null,parentProjectName:null};function Ie(r){let e=G.default.join(r,".git"),t;try{t=(0,j.statSync)(e)}catch(u){return u instanceof Error&&u.code!=="ENOENT"&&console.warn("[worktree] Unexpected error checking .git:",u),U}if(!t.isFile())return U;let s;try{s=(0,j.readFileSync)(e,"utf-8").trim()}catch(u){return console.warn("[worktree] Failed to read .git file:",u instanceof Error?u.message:String(u)),U}let n=s.match(/^gitdir:\s*(.+)$/);if(!n)return U;let i=n[1].match(/^(.+)[/\\]\.git[/\\]worktrees[/\\]([^/\\]+)$/);if(!i)return U;let a=i[1],d=G.default.basename(r),m=G.default.basename(a);return{isWorktree:!0,worktreeName:d,parentRepoPath:a,parentProjectName:m}}function Me(r){return r==="~"||r.startsWith("~/")?r.replace(/^~/,(0,Le.homedir)()):r}function Gt(r){if(!r||r.trim()==="")return c.warn("PROJECT_NAME","Empty cwd provided, using fallback",{cwd:r}),"unknown-project";let e=Me(r),t=ye.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 c.info("PROJECT_NAME","Drive root detected",{cwd:r,projectName:i}),i}}return c.warn("PROJECT_NAME","Root directory detected, using fallback",{cwd:r}),"unknown-project"}return t}function se(r){let e=Gt(r);if(!r)return{primary:e,parent:null,isWorktree:!1,allProjects:[e]};let t=Me(r),s=Ie(t);if(s.isWorktree&&s.parentProjectName){let n=`${s.parentProjectName}/${e}`;return{primary:n,parent:s.parentProjectName,isWorktree:!0,allProjects:[s.parentProjectName,n]}}return{primary:e,parent:null,isWorktree:!1,allProjects:[e]}}function X(r,e,t){return(0,De.createHash)("sha256").update([r||"",e||"",t||""].join("\0")).digest("hex").slice(0,16)}function re(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 M(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 ve(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 Xt(r,e){return{customTitle:r,platformSource:e?M(e):void 0}}var B=class{db;constructor(e=Re){e instanceof ne.Database?this.db=e:(e!==":memory:"&&Ne(R),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.db.run("PRAGMA journal_size_limit = 4194304")),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(),this.ensureMergedIntoProjectColumns(),this.addObservationSubagentColumns(),this.addPendingMessagesToolUseIdAndWorkerPidColumns(),this.addObservationsUniqueContentHashIndex()}initializeSchema(){this.db.run(` CREATE TABLE IF NOT EXISTS schema_versions ( id INTEGER PRIMARY KEY, version INTEGER UNIQUE NOT NULL, @@ -290,7 +290,19 @@ ${o.stack}`:` ${o.message}`:this.getLevel()===0&&typeof o=="object"?u=` UPDATE sdk_sessions SET platform_source = '${h}' WHERE platform_source IS NULL OR platform_source = '' - `),n||this.db.run("CREATE INDEX IF NOT EXISTS idx_sdk_sessions_platform_source ON sdk_sessions(platform_source)"),this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(24,new Date().toISOString()))}addObservationModelColumns(){let e=this.db.query("PRAGMA table_info(observations)").all(),t=e.some(n=>n.name==="generated_by_model"),s=e.some(n=>n.name==="relevance_count");t&&s||(t||this.db.run("ALTER TABLE observations ADD COLUMN generated_by_model TEXT"),s||this.db.run("ALTER TABLE observations ADD COLUMN relevance_count INTEGER DEFAULT 0"),this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(26,new Date().toISOString()))}ensureMergedIntoProjectColumns(){this.db.query("PRAGMA table_info(observations)").all().some(s=>s.name==="merged_into_project")||this.db.run("ALTER TABLE observations ADD COLUMN merged_into_project TEXT"),this.db.run("CREATE INDEX IF NOT EXISTS idx_observations_merged_into ON observations(merged_into_project)"),this.db.query("PRAGMA table_info(session_summaries)").all().some(s=>s.name==="merged_into_project")||this.db.run("ALTER TABLE session_summaries ADD COLUMN merged_into_project TEXT"),this.db.run("CREATE INDEX IF NOT EXISTS idx_summaries_merged_into ON session_summaries(merged_into_project)")}addObservationSubagentColumns(){let e=this.db.prepare("SELECT version FROM schema_versions WHERE version = ?").get(27),t=this.db.query("PRAGMA table_info(observations)").all(),s=t.some(i=>i.name==="agent_type"),n=t.some(i=>i.name==="agent_id");s||this.db.run("ALTER TABLE observations ADD COLUMN agent_type TEXT"),n||this.db.run("ALTER TABLE observations ADD COLUMN agent_id TEXT"),this.db.run("CREATE INDEX IF NOT EXISTS idx_observations_agent_type ON observations(agent_type)"),this.db.run("CREATE INDEX IF NOT EXISTS idx_observations_agent_id ON observations(agent_id)");let o=this.db.query("PRAGMA table_info(pending_messages)").all();if(o.length>0){let i=o.some(d=>d.name==="agent_type"),a=o.some(d=>d.name==="agent_id");i||this.db.run("ALTER TABLE pending_messages ADD COLUMN agent_type TEXT"),a||this.db.run("ALTER TABLE pending_messages ADD COLUMN agent_id TEXT")}e||this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(27,new Date().toISOString())}addObservationsUniqueContentHashIndex(){if(this.db.prepare("SELECT version FROM schema_versions WHERE version = ?").get(29))return;let t=this.db.query("PRAGMA table_info(observations)").all(),s=t.some(o=>o.name==="memory_session_id"),n=t.some(o=>o.name==="content_hash");if(!s||!n){this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(29,new Date().toISOString());return}this.db.run("BEGIN TRANSACTION");try{this.db.run(` + `),n||this.db.run("CREATE INDEX IF NOT EXISTS idx_sdk_sessions_platform_source ON sdk_sessions(platform_source)"),this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(24,new Date().toISOString()))}addObservationModelColumns(){let e=this.db.query("PRAGMA table_info(observations)").all(),t=e.some(n=>n.name==="generated_by_model"),s=e.some(n=>n.name==="relevance_count");t&&s||(t||this.db.run("ALTER TABLE observations ADD COLUMN generated_by_model TEXT"),s||this.db.run("ALTER TABLE observations ADD COLUMN relevance_count INTEGER DEFAULT 0"),this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(26,new Date().toISOString()))}ensureMergedIntoProjectColumns(){this.db.query("PRAGMA table_info(observations)").all().some(s=>s.name==="merged_into_project")||this.db.run("ALTER TABLE observations ADD COLUMN merged_into_project TEXT"),this.db.run("CREATE INDEX IF NOT EXISTS idx_observations_merged_into ON observations(merged_into_project)"),this.db.query("PRAGMA table_info(session_summaries)").all().some(s=>s.name==="merged_into_project")||this.db.run("ALTER TABLE session_summaries ADD COLUMN merged_into_project TEXT"),this.db.run("CREATE INDEX IF NOT EXISTS idx_summaries_merged_into ON session_summaries(merged_into_project)")}addObservationSubagentColumns(){let e=this.db.prepare("SELECT version FROM schema_versions WHERE version = ?").get(27),t=this.db.query("PRAGMA table_info(observations)").all(),s=t.some(i=>i.name==="agent_type"),n=t.some(i=>i.name==="agent_id");s||this.db.run("ALTER TABLE observations ADD COLUMN agent_type TEXT"),n||this.db.run("ALTER TABLE observations ADD COLUMN agent_id TEXT"),this.db.run("CREATE INDEX IF NOT EXISTS idx_observations_agent_type ON observations(agent_type)"),this.db.run("CREATE INDEX IF NOT EXISTS idx_observations_agent_id ON observations(agent_id)");let o=this.db.query("PRAGMA table_info(pending_messages)").all();if(o.length>0){let i=o.some(d=>d.name==="agent_type"),a=o.some(d=>d.name==="agent_id");i||this.db.run("ALTER TABLE pending_messages ADD COLUMN agent_type TEXT"),a||this.db.run("ALTER TABLE pending_messages ADD COLUMN agent_id TEXT")}e||this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(27,new Date().toISOString())}addPendingMessagesToolUseIdAndWorkerPidColumns(){if(this.db.query("SELECT name FROM sqlite_master WHERE type='table' AND name='pending_messages'").all().length===0){this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(28,new Date().toISOString());return}let t=this.db.query("PRAGMA table_info(pending_messages)").all(),s=t.some(o=>o.name==="tool_use_id"),n=t.some(o=>o.name==="worker_pid");s||this.db.run("ALTER TABLE pending_messages ADD COLUMN tool_use_id TEXT"),n||this.db.run("ALTER TABLE pending_messages ADD COLUMN worker_pid INTEGER"),this.db.run("BEGIN TRANSACTION");try{this.db.run("CREATE INDEX IF NOT EXISTS idx_pending_messages_worker_pid ON pending_messages(worker_pid)"),this.db.run(` + DELETE FROM pending_messages + WHERE tool_use_id IS NOT NULL + AND id NOT IN ( + SELECT MIN(id) FROM pending_messages + WHERE tool_use_id IS NOT NULL + GROUP BY content_session_id, tool_use_id + ) + `),this.db.run(` + CREATE UNIQUE INDEX IF NOT EXISTS ux_pending_session_tool + ON pending_messages(content_session_id, tool_use_id) + WHERE tool_use_id IS NOT NULL + `),this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(28,new Date().toISOString()),this.db.run("COMMIT")}catch(o){throw this.db.run("ROLLBACK"),o}}addObservationsUniqueContentHashIndex(){if(this.db.prepare("SELECT version FROM schema_versions WHERE version = ?").get(29))return;let t=this.db.query("PRAGMA table_info(observations)").all(),s=t.some(o=>o.name==="memory_session_id"),n=t.some(o=>o.name==="content_hash");if(!s||!n){this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(29,new Date().toISOString());return}this.db.run("BEGIN TRANSACTION");try{this.db.run(` DELETE FROM observations WHERE id NOT IN ( SELECT MIN(id) FROM observations diff --git a/plugin/scripts/worker-service.cjs b/plugin/scripts/worker-service.cjs index 700df4b8..95938ec6 100755 --- a/plugin/scripts/worker-service.cjs +++ b/plugin/scripts/worker-service.cjs @@ -17,7 +17,7 @@ ${s.stack}`:` ${s.message}`:this.getLevel()===0&&typeof s=="object"?l=` `)}else process.stderr.write(p+` `)}debug(e,r,i,n){this.log(0,e,r,i,n)}info(e,r,i,n){this.log(1,e,r,i,n)}warn(e,r,i,n){this.log(2,e,r,i,n)}error(e,r,i,n){this.log(3,e,r,i,n)}dataIn(e,r,i,n){this.info(e,`\u2192 ${r}`,i,n)}dataOut(e,r,i,n){this.info(e,`\u2190 ${r}`,i,n)}success(e,r,i,n){this.info(e,`\u2713 ${r}`,i,n)}failure(e,r,i,n){this.error(e,`\u2717 ${r}`,i,n)}timing(e,r,i,n){this.info(e,`\u23F1 ${r}`,n,{duration:`${i}ms`})}happyPathError(e,r,i,n,s=""){let u=((new Error().stack||"").split(` `)[2]||"").match(/at\s+(?:.*\s+)?\(?([^:]+):(\d+):(\d+)\)?/),l=u?`${u[1].split("/").pop()}:${u[2]}`:"unknown",d={...i,location:l};return this.warn(e,`[HAPPY-PATH] ${r}`,d,n),s}},g=new NR});function IF(t){return process.platform==="win32"?Math.round(t*fn.WINDOWS_MULTIPLIER):t}var fn,dt,Xn=ye(()=>{"use strict";fn={DEFAULT:3e5,HEALTH_CHECK:3e3,POST_SPAWN_WAIT:15e3,READINESS_WAIT:3e4,PORT_IN_USE_WAIT:3e3,WORKER_STARTUP_WAIT:1e3,PRE_RESTART_SETTLE_DELAY:2e3,POWERSHELL_COMMAND:1e4,WINDOWS_MULTIPLIER:1.5},dt={SUCCESS:0,FAILURE:1,BLOCKING_ERROR:2,USER_MESSAGE_ONLY:3}});var OF={};Sr(OF,{SettingsDefaultsManager:()=>ke});var Js,jf,MR,ke,sr=ye(()=>{"use strict";Js=require("fs"),jf=require("path"),MR=require("os"),ke=class{static DEFAULTS={CLAUDE_MEM_MODEL:"claude-sonnet-4-6",CLAUDE_MEM_CONTEXT_OBSERVATIONS:"50",CLAUDE_MEM_WORKER_PORT:String(37700+(process.getuid?.()??77)%100),CLAUDE_MEM_WORKER_HOST:"127.0.0.1",CLAUDE_MEM_SKIP_TOOLS:"ListMcpResourcesTool,SlashCommand,Skill,TodoWrite,AskUserQuestion",CLAUDE_MEM_PROVIDER:"claude",CLAUDE_MEM_CLAUDE_AUTH_METHOD:"cli",CLAUDE_MEM_GEMINI_API_KEY:"",CLAUDE_MEM_GEMINI_MODEL:"gemini-2.5-flash-lite",CLAUDE_MEM_GEMINI_RATE_LIMITING_ENABLED:"true",CLAUDE_MEM_GEMINI_MAX_CONTEXT_MESSAGES:"20",CLAUDE_MEM_GEMINI_MAX_TOKENS:"100000",CLAUDE_MEM_OPENROUTER_API_KEY:"",CLAUDE_MEM_OPENROUTER_MODEL:"xiaomi/mimo-v2-flash:free",CLAUDE_MEM_OPENROUTER_SITE_URL:"",CLAUDE_MEM_OPENROUTER_APP_NAME:"claude-mem",CLAUDE_MEM_OPENROUTER_MAX_CONTEXT_MESSAGES:"20",CLAUDE_MEM_OPENROUTER_MAX_TOKENS:"100000",CLAUDE_MEM_DATA_DIR:(0,jf.join)((0,MR.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,jf.join)((0,MR.homedir)(),".claude-mem","transcript-watch.json"),CLAUDE_MEM_MAX_CONCURRENT_AGENTS:"2",CLAUDE_MEM_HOOK_FAIL_LOUD_THRESHOLD:"3",CLAUDE_MEM_EXCLUDED_PROJECTS:"",CLAUDE_MEM_FOLDER_MD_EXCLUDE:"[]",CLAUDE_MEM_SEMANTIC_INJECT:"false",CLAUDE_MEM_SEMANTIC_INJECT_LIMIT:"5",CLAUDE_MEM_TIER_ROUTING_ENABLED:"true",CLAUDE_MEM_TIER_SIMPLE_MODEL:"haiku",CLAUDE_MEM_TIER_SUMMARY_MODEL:"",CLAUDE_MEM_CHROMA_ENABLED:"true",CLAUDE_MEM_CHROMA_MODE:"local",CLAUDE_MEM_CHROMA_HOST:"127.0.0.1",CLAUDE_MEM_CHROMA_PORT:"8000",CLAUDE_MEM_CHROMA_SSL:"false",CLAUDE_MEM_CHROMA_API_KEY:"",CLAUDE_MEM_CHROMA_TENANT:"default_tenant",CLAUDE_MEM_CHROMA_DATABASE:"default_database",CLAUDE_MEM_TELEGRAM_ENABLED:"true",CLAUDE_MEM_TELEGRAM_BOT_TOKEN:"",CLAUDE_MEM_TELEGRAM_CHAT_ID:"",CLAUDE_MEM_TELEGRAM_TRIGGER_TYPES:"security_alert",CLAUDE_MEM_TELEGRAM_TRIGGER_CONCEPTS:""};static getAllDefaults(){return{...this.DEFAULTS}}static get(e){return process.env[e]??this.DEFAULTS[e]}static getInt(e){let r=this.get(e);return parseInt(r,10)}static getBool(e){let r=this.get(e);return r==="true"||r===!0}static applyEnvOverrides(e){let r={...e};for(let i of Object.keys(this.DEFAULTS))process.env[i]!==void 0&&(r[i]=process.env[i]);return r}static loadFromFile(e){try{if(!(0,Js.existsSync)(e)){let o=this.getAllDefaults();try{let a=(0,jf.dirname)(e);(0,Js.existsSync)(a)||(0,Js.mkdirSync)(a,{recursive:!0}),(0,Js.writeFileSync)(e,JSON.stringify(o,null,2),"utf-8"),console.log("[SETTINGS] Created settings file with defaults:",e)}catch(a){console.warn("[SETTINGS] Failed to create settings file, using in-memory defaults:",e,a instanceof Error?a.message:String(a))}return this.applyEnvOverrides(o)}let r=(0,Js.readFileSync)(e,"utf-8"),i=JSON.parse(r),n=i;if(i.env&&typeof i.env=="object"){n=i.env;try{(0,Js.writeFileSync)(e,JSON.stringify(n,null,2),"utf-8"),console.log("[SETTINGS] Migrated settings file from nested to flat schema:",e)}catch(o){console.warn("[SETTINGS] Failed to auto-migrate settings file:",e,o instanceof Error?o.message:String(o))}}let s={...this.DEFAULTS};for(let o of Object.keys(this.DEFAULTS))n[o]!==void 0&&(s[o]=n[o]);return this.applyEnvOverrides(s)}catch(r){return console.warn("[SETTINGS] Failed to load settings, using defaults:",e,r instanceof Error?r.message:String(r)),this.applyEnvOverrides(this.getAllDefaults())}}}});var $F={};Sr($F,{ARCHIVES_DIR:()=>DR,BACKUPS_DIR:()=>NF,CLAUDE_COMMANDS_DIR:()=>MF,CLAUDE_CONFIG_DIR:()=>No,CLAUDE_MD_PATH:()=>Wpe,CLAUDE_SETTINGS_PATH:()=>qpe,DATA_DIR:()=>Kt,DB_PATH:()=>Wc,LOGS_DIR:()=>PF,MARKETPLACE_ROOT:()=>Mo,MODES_DIR:()=>jR,OBSERVER_SESSIONS_DIR:()=>zi,OBSERVER_SESSIONS_PROJECT:()=>Ui,TRASH_DIR:()=>AF,USER_SETTINGS_PATH:()=>kt,VECTOR_DB_DIR:()=>Fpe,createBackupFilename:()=>Jpe,ensureAllClaudeDirs:()=>Vpe,ensureAllDataDirs:()=>Zpe,ensureDir:()=>xr,ensureModesDir:()=>Gpe,getCurrentProjectName:()=>Kpe,getPackageCommandsDir:()=>Ype,getPackageRoot:()=>Qn,getProjectArchiveDir:()=>Hpe,getWorkerSocketPath:()=>Bpe});function zpe(){return typeof __dirname<"u"?__dirname:(0,wt.dirname)((0,CF.fileURLToPath)(Xpe.url))}function Lpe(){if(process.env.CLAUDE_MEM_DATA_DIR)return process.env.CLAUDE_MEM_DATA_DIR;let t=(0,wt.join)((0,$R.homedir)(),".claude-mem"),e=(0,wt.join)(t,"settings.json");try{if((0,pS.existsSync)(e)){let{readFileSync:r}=require("fs"),i=JSON.parse(r(e,"utf-8")),n=i.env??i;if(n.CLAUDE_MEM_DATA_DIR)return n.CLAUDE_MEM_DATA_DIR}}catch{}return t}function Hpe(t){return(0,wt.join)(DR,t)}function Bpe(t){return(0,wt.join)(Kt,`worker-${t}.sock`)}function xr(t){(0,pS.mkdirSync)(t,{recursive:!0})}function Zpe(){xr(Kt),xr(DR),xr(PF),xr(AF),xr(NF),xr(jR)}function Gpe(){xr(jR)}function Vpe(){xr(No),xr(MF)}function Kpe(){try{let t=(0,RF.execSync)("git rev-parse --show-toplevel",{cwd:process.cwd(),encoding:"utf8",stdio:["pipe","pipe","ignore"],windowsHide:!0}).trim();return(0,wt.basename)((0,wt.dirname)(t))+"/"+(0,wt.basename)(t)}catch(t){g.debug("SYSTEM","Git root detection failed, using cwd basename",{cwd:process.cwd()},t instanceof Error?t:new Error(String(t)));let e=process.cwd();return(0,wt.basename)((0,wt.dirname)(e))+"/"+(0,wt.basename)(e)}}function Qn(){return(0,wt.join)(Upe,"..")}function Ype(){let t=Qn();return(0,wt.join)(t,"commands")}function Jpe(t){let e=new Date().toISOString().replace(/[:.]/g,"-").replace("T","_").slice(0,19);return`${t}.backup.${e}`}var wt,$R,pS,RF,CF,Xpe,Upe,Kt,No,Mo,DR,PF,AF,NF,jR,kt,Wc,Fpe,zi,Ui,qpe,MF,Wpe,Tt=ye(()=>{"use strict";wt=require("path"),$R=require("os"),pS=require("fs"),RF=require("child_process"),CF=require("url");oe();Xpe={};Upe=zpe();Kt=Lpe(),No=process.env.CLAUDE_CONFIG_DIR||(0,wt.join)((0,$R.homedir)(),".claude"),Mo=(0,wt.join)(No,"plugins","marketplaces","thedotmack"),DR=(0,wt.join)(Kt,"archives"),PF=(0,wt.join)(Kt,"logs"),AF=(0,wt.join)(Kt,"trash"),NF=(0,wt.join)(Kt,"backups"),jR=(0,wt.join)(Kt,"modes"),kt=(0,wt.join)(Kt,"settings.json"),Wc=(0,wt.join)(Kt,"claude-mem.db"),Fpe=(0,wt.join)(Kt,"vector-db"),zi=(0,wt.join)(Kt,"observer-sessions"),Ui=(0,wt.basename)(zi),qpe=(0,wt.join)(No,"settings.json"),MF=(0,wt.join)(No,"commands"),Wpe=(0,wt.join)(No,"CLAUDE.md")});function Ma(){return mS!==null||(mS=ke.loadFromFile(kt)),mS}var mS,zf=ye(()=>{"use strict";sr();Tt();mS=null});function pi(t=process.env){let e={};for(let[r,i]of Object.entries(t))if(i!==void 0){if(Qpe.has(r)){e[r]=i;continue}UR.has(r)||zR.some(n=>r.startsWith(n))||(e[r]=i)}return e}var zR,UR,Qpe,$a=ye(()=>{"use strict";zR=["CLAUDECODE_","CLAUDE_CODE_"],UR=new Set(["CLAUDECODE","CLAUDE_CODE_SESSION","CLAUDE_CODE_ENTRYPOINT","MCP_SESSION_ID"]),Qpe=new Set(["CLAUDE_CODE_OAUTH_TOKEN","CLAUDE_CODE_GIT_BASH_PATH"])});function mi(t){if(!Number.isInteger(t)||t<0||t===0)return!1;try{return process.kill(t,0),!0}catch(e){if(e instanceof Error){let r=e.code;return r==="EPERM"?!0:(g.debug("SYSTEM","PID check failed",{pid:t,code:r}),!1)}return g.warn("SYSTEM","PID check threw non-Error",{pid:t,error:String(e)}),!1}}function qR(t){if(!Number.isInteger(t)||t<=0)return null;if(process.platform==="linux")try{let e=(0,Xs.readFileSync)(`/proc/${t}/stat`,"utf-8"),r=e.lastIndexOf(") ");if(r<0)return null;let n=e.slice(r+2).split(" ")[19];return n&&/^\d+$/.test(n)?n:null}catch(e){return g.debug("SYSTEM","captureProcessStartToken: /proc read failed",{pid:t,error:e instanceof Error?e.message:String(e)}),null}if(process.platform==="win32")return null;try{let e=(0,Lf.spawnSync)("ps",["-p",String(t),"-o","lstart="],{encoding:"utf-8",timeout:2e3,env:{...process.env,LC_ALL:"C",LANG:"C"}});if(e.status!==0)return null;let r=e.stdout.trim();return r.length>0?r:null}catch(e){return g.debug("SYSTEM","captureProcessStartToken: ps exec failed",{pid:t,error:e instanceof Error?e.message:String(e)}),null}}function qf(t){if(!t||!mi(t.pid))return!1;if(!t.startToken)return!0;let e=qR(t.pid);if(e===null)return!0;let r=e===t.startToken;return r||g.debug("SYSTEM","verifyPidFileOwnership: start-token mismatch (PID reused)",{pid:t.pid,stored:t.startToken,current:e}),r}function Da(){return LR||(LR=new FR),LR}function ja(t){let e=Da(),r=e.getBySession(t).filter(s=>s.type==="sdk");r.length>1&&g.warn("PROCESS",`Multiple SDK processes found for session ${t}`,{count:r.length,pids:r.map(s=>s.pid)});let i=r[0];if(!i)return;let n=e.getRuntimeProcess(i.id);if(n)return{pid:i.pid,pgid:i.pgid,sessionDbId:t,process:n}}async function za(t,e=5e3){let{pid:r,pgid:i,process:n}=t;if(n.exitCode!==null)return;let s=new Promise(u=>{n.once("exit",()=>u())}),o=new Promise(u=>{setTimeout(u,e)});if(await Promise.race([s,o]),n.exitCode!==null)return;g.warn("PROCESS",`PID ${r} did not exit after ${e}ms, sending SIGKILL to process group`,{pid:r,pgid:i,timeoutMs:e});try{typeof i=="number"&&process.platform!=="win32"?process.kill(-i,"SIGKILL"):n.kill("SIGKILL")}catch{}let a=new Promise(u=>{n.once("exit",()=>u())}),c=new Promise(u=>{setTimeout(u,1e3)});await Promise.race([a,c])}function jF(){return Da().getAll().filter(t=>t.type==="sdk").length}function ime(){let t=Uf.shift();t&&t()}async function UF(t,e=6e4){let r=jF();if(r>=DF)throw new Error(`Hard cap exceeded: ${r} processes in registry (cap=${DF}). Refusing to spawn more.`);if(!(r{let s=setTimeout(()=>{let a=Uf.indexOf(o);a>=0&&Uf.splice(a,1),n(new Error(`Timed out waiting for agent pool slot after ${e}ms`))},e),o=()=>{clearTimeout(s),jF()0&&s[s.length-1].startsWith("--")&&s.pop();continue}s.push(d)}let o=i?(0,Lf.spawn)("cmd.exe",["/d","/c",e.command,...s],{cwd:e.cwd,env:n,detached:!0,stdio:["pipe","pipe","pipe"],signal:e.signal,windowsHide:!0}):(0,Lf.spawn)(e.command,s,{cwd:e.cwd,env:n,detached:!0,stdio:["pipe","pipe","pipe"],signal:e.signal,windowsHide:!0});if(o.on("error",d=>{g.warn("SDK_SPAWN",`[session-${t}] child emitted error event`,{sessionDbId:t,pid:o.pid,errorName:d.name,errorCode:d.code},d)}),!o.pid)return g.error("PROCESS","Spawn succeeded but produced no PID",{sessionDbId:t}),null;let a=o.pid,c=a;o.stderr&&o.stderr.on("data",d=>{g.debug("SDK_SPAWN",`[session-${t}] stderr: ${d.toString().trim()}`)});let u=`sdk:${t}:${a}`;if(r.register(u,{pid:a,type:"sdk",sessionId:t,startedAt:new Date().toISOString(),pgid:c},o),o.on("exit",(d,p)=>{d!==0&&g.warn("SDK_SPAWN",`[session-${t}] Claude process exited`,{code:d,signal:p,pid:a}),r.unregister(u),ime()}),!o.stdin||!o.stdout||!o.stderr){g.error("PROCESS","Spawned SDK child missing required stdio streams",{sessionDbId:t,pid:a,hasStdin:!!o.stdin,hasStdout:!!o.stdout,hasStderr:!!o.stderr});try{o.kill("SIGKILL")}catch{}return null}return{process:{stdin:o.stdin,stdout:o.stdout,stderr:o.stderr,get killed(){return o.killed},get exitCode(){return o.exitCode},kill:o.kill.bind(o),on:o.on.bind(o),once:o.once.bind(o),off:o.off.bind(o)},pid:a,pgid:c}}function LF(t){return e=>{let i=Da().getBySession(t).filter(s=>s.type==="sdk");for(let s of i)if(mi(s.pid))try{typeof s.pgid=="number"&&process.platform!=="win32"?process.kill(-s.pgid,"SIGTERM"):process.kill(s.pid,"SIGTERM"),g.warn("PROCESS",`Killing duplicate SDK process PID ${s.pid} before spawning new one for session ${t}`,{existingPid:s.pid,sessionDbId:t})}catch(o){(o instanceof Error?o.code:void 0)!=="ESRCH"&&(o instanceof Error?g.warn("PROCESS",`Failed to SIGTERM duplicate SDK process PID ${s.pid}`,{sessionDbId:t},o):g.warn("PROCESS",`Failed to SIGTERM duplicate SDK process PID ${s.pid} (non-Error)`,{sessionDbId:t,error:String(o)}))}let n=sme(t,e);if(!n)throw new Error(`Failed to spawn SDK subprocess for session ${t}`);return n.process}}var Lf,Xs,zF,Ff,eme,tme,rme,nme,FR,LR,DF,Uf,Qs=ye(()=>{"use strict";Lf=require("child_process"),Xs=require("fs"),zF=require("os"),Ff=Oe(require("path"),1);oe();$a();eme=5e3,tme=1e3,rme=Ff.default.join((0,zF.homedir)(),".claude-mem"),nme=Ff.default.join(rme,"supervisor.json");FR=class{registryPath;entries=new Map;runtimeProcesses=new Map;initialized=!1;constructor(e=nme){this.registryPath=e}initialize(){if(this.initialized)return;if(this.initialized=!0,(0,Xs.mkdirSync)(Ff.default.dirname(this.registryPath),{recursive:!0}),!(0,Xs.existsSync)(this.registryPath)){this.persist();return}try{let i=JSON.parse((0,Xs.readFileSync)(this.registryPath,"utf-8")).processes??{};for(let[n,s]of Object.entries(i))this.entries.set(n,s)}catch(r){r instanceof Error?g.warn("SYSTEM","Failed to parse supervisor registry, rebuilding",{path:this.registryPath},r):g.warn("SYSTEM","Failed to parse supervisor registry, rebuilding",{path:this.registryPath,error:String(r)}),this.entries.clear()}let e=this.pruneDeadEntries();e>0&&g.info("SYSTEM","Removed dead processes from supervisor registry",{removed:e}),this.persist()}register(e,r,i){this.initialize(),this.entries.set(e,r),i&&this.runtimeProcesses.set(e,i),this.persist()}unregister(e){this.initialize(),this.entries.delete(e),this.runtimeProcesses.delete(e),this.persist()}clear(){this.entries.clear(),this.runtimeProcesses.clear(),this.persist()}getAll(){return this.initialize(),Array.from(this.entries.entries()).map(([e,r])=>({id:e,...r})).sort((e,r)=>{let i=Date.parse(e.startedAt),n=Date.parse(r.startedAt);return(Number.isNaN(i)?0:i)-(Number.isNaN(n)?0:n)})}getBySession(e){let r=String(e);return this.getAll().filter(i=>i.sessionId!==void 0&&String(i.sessionId)===r)}getRuntimeProcess(e){return this.runtimeProcesses.get(e)}getByPid(e){return this.getAll().filter(r=>r.pid===e)}pruneDeadEntries(){this.initialize();let e=0;for(let[r,i]of this.entries)mi(i.pid)||(this.entries.delete(r),this.runtimeProcesses.delete(r),e+=1);return e>0&&this.persist(),e}async reapSession(e){this.initialize();let r=this.getBySession(e);if(r.length===0)return 0;let i=typeof e=="number"?e:Number(e)||void 0;g.info("SYSTEM",`Reaping ${r.length} process(es) for session ${e}`,{sessionId:i,pids:r.map(a=>a.pid)});let n=r.filter(a=>mi(a.pid));for(let a of n)try{typeof a.pgid=="number"&&process.platform!=="win32"?process.kill(-a.pgid,"SIGTERM"):process.kill(a.pid,"SIGTERM")}catch(c){c instanceof Error?c.code!=="ESRCH"&&g.debug("SYSTEM",`Failed to SIGTERM session process PID ${a.pid}`,{pid:a.pid,pgid:a.pgid},c):g.warn("SYSTEM",`Failed to SIGTERM session process PID ${a.pid} (non-Error)`,{pid:a.pid,pgid:a.pgid,error:String(c)})}let s=Date.now()+eme;for(;Date.now()mi(c.pid)).length!==0;)await new Promise(c=>setTimeout(c,100));let o=n.filter(a=>mi(a.pid));for(let a of o){g.warn("SYSTEM",`Session process PID ${a.pid} did not exit after SIGTERM, sending SIGKILL`,{pid:a.pid,pgid:a.pgid,sessionId:i});try{typeof a.pgid=="number"&&process.platform!=="win32"?process.kill(-a.pgid,"SIGKILL"):process.kill(a.pid,"SIGKILL")}catch(c){c instanceof Error?c.code!=="ESRCH"&&g.debug("SYSTEM",`Failed to SIGKILL session process PID ${a.pid}`,{pid:a.pid,pgid:a.pgid},c):g.warn("SYSTEM",`Failed to SIGKILL session process PID ${a.pid} (non-Error)`,{pid:a.pid,pgid:a.pgid,error:String(c)})}}if(o.length>0){let a=Date.now()+tme;for(;Date.now()mi(u.pid)).length!==0;)await new Promise(u=>setTimeout(u,100))}for(let a of r)this.entries.delete(a.id),this.runtimeProcesses.delete(a.id);return this.persist(),g.info("SYSTEM",`Reaped ${r.length} process(es) for session ${e}`,{sessionId:i,reaped:r.length}),r.length}persist(){let e={processes:Object.fromEntries(this.entries.entries())};(0,Xs.mkdirSync)(Ff.default.dirname(this.registryPath),{recursive:!0}),(0,Xs.writeFileSync)(this.registryPath,JSON.stringify(e,null,2))}},LR=null;DF=10,Uf=[]});async function GF(t){let e=t.currentPid??process.pid,r=t.pidFilePath??cme,i=t.registry.getAll(),n=[...i].filter(o=>o.pid!==e).sort((o,a)=>Date.parse(a.startedAt)-Date.parse(o.startedAt));for(let o of n){if(!mi(o.pid)){t.registry.unregister(o.id);continue}try{await qF(o,"SIGTERM")}catch(a){a instanceof Error?g.debug("SYSTEM","Failed to send SIGTERM to child process",{pid:o.pid,pgid:o.pgid,type:o.type},a):g.warn("SYSTEM","Failed to send SIGTERM to child process (non-Error)",{pid:o.pid,pgid:o.pgid,type:o.type,error:String(a)})}}await FF(n,5e3);let s=n.filter(o=>mi(o.pid));for(let o of s)try{await qF(o,"SIGKILL")}catch(a){a instanceof Error?g.debug("SYSTEM","Failed to force kill child process",{pid:o.pid,pgid:o.pgid,type:o.type},a):g.warn("SYSTEM","Failed to force kill child process (non-Error)",{pid:o.pid,pgid:o.pgid,type:o.type,error:String(a)})}await FF(s,1e3);for(let o of n)t.registry.unregister(o.id);for(let o of i.filter(a=>a.pid===e))t.registry.unregister(o.id);try{(0,HF.rmSync)(r,{force:!0})}catch(o){o instanceof Error?g.debug("SYSTEM","Failed to remove PID file during shutdown",{pidFilePath:r},o):g.warn("SYSTEM","Failed to remove PID file during shutdown (non-Error)",{pidFilePath:r,error:String(o)})}t.registry.pruneDeadEntries()}async function FF(t,e){let r=Date.now()+e;for(;Date.now()mi(n.pid)).length===0)return;await new Promise(n=>setTimeout(n,100))}}async function qF(t,e){let{pid:r,pgid:i}=t;if(process.platform!=="win32"){try{typeof i=="number"?process.kill(-i,e):process.kill(r,e)}catch(o){if(o instanceof Error&&o.code==="ESRCH")return;throw o}return}if(e==="SIGTERM"){try{process.kill(r,e)}catch(o){if(o instanceof Error&&o.code==="ESRCH")return;throw o}return}let n=await ume();if(n){await new Promise((o,a)=>{n(r,e,c=>{if(!c){o();return}if(c.code==="ESRCH"){o();return}a(c)})});return}let s=["/PID",String(r),"/T"];e==="SIGKILL"&&s.push("/F"),await ome("taskkill",s,{timeout:fn.POWERSHELL_COMMAND,windowsHide:!0})}async function ume(){let t="tree-kill";try{let e=await import(t);return e.default??e}catch(e){return g.debug("SYSTEM","tree-kill module not available, using fallback",{},e instanceof Error?e:void 0),null}}var WF,HF,BF,WR,ZF,ome,ame,cme,VF=ye(()=>{"use strict";WF=require("child_process"),HF=require("fs"),BF=require("os"),WR=Oe(require("path"),1),ZF=require("util");oe();Xn();Qs();ome=(0,ZF.promisify)(WF.execFile),ame=WR.default.join((0,BF.homedir)(),".claude-mem"),cme=WR.default.join(ame,"worker.pid")});function lme(){let e=Da().pruneDeadEntries();e>0&&g.info("SYSTEM",`Health check: pruned ${e} dead process(es) from registry`)}function YF(){Ql===null&&(Ql=setInterval(lme,KF),Ql.unref(),g.debug("SYSTEM","Health checker started",{intervalMs:KF}))}function JF(){Ql!==null&&(clearInterval(Ql),Ql=null,g.debug("SYSTEM","Health checker stopped"))}var KF,Ql,XF=ye(()=>{"use strict";oe();Qs();KF=3e4,Ql=null});async function eq(){await ZR.start()}function Xr(){return ZR}function tq(t){ZR.configureSignalHandlers(t)}function Wf(t={}){let e=t.pidFilePath??pme;if(!(0,Hc.existsSync)(e))return"missing";let r=null;try{r=JSON.parse((0,Hc.readFileSync)(e,"utf-8"))}catch(n){return n instanceof Error?g.warn("SYSTEM","Failed to parse worker PID file, removing it",{path:e},n):g.warn("SYSTEM","Failed to parse worker PID file, removing it",{path:e,error:String(n)}),(0,Hc.rmSync)(e,{force:!0}),"invalid"}return qf(r)&&r?((t.logAlive??!0)&&g.info("SYSTEM","Worker already running (PID alive)",{existingPid:r.pid,existingPort:r.port,startedAt:r.startedAt}),"alive"):(g.info("SYSTEM","Removing stale PID file (worker process is dead or PID has been reused)",{pid:r?.pid,port:r?.port,startedAt:r?.startedAt}),(0,Hc.rmSync)(e,{force:!0}),"stale")}var Hc,QF,BR,dme,pme,HR,ZR,Ua=ye(()=>{"use strict";Hc=require("fs"),QF=require("os"),BR=Oe(require("path"),1);oe();Qs();VF();XF();dme=BR.default.join((0,QF.homedir)(),".claude-mem"),pme=BR.default.join(dme,"worker.pid"),HR=class{registry;started=!1;stopPromise=null;signalHandlersRegistered=!1;shutdownInitiated=!1;shutdownHandler=null;constructor(e){this.registry=e}async start(){if(this.started)return;if(this.registry.initialize(),Wf({logAlive:!1})==="alive")throw new Error("Worker already running");this.started=!0,YF()}configureSignalHandlers(e){if(this.shutdownHandler=e,this.signalHandlersRegistered)return;this.signalHandlersRegistered=!0;let r=async i=>{if(this.shutdownInitiated){g.warn("SYSTEM",`Received ${i} but shutdown already in progress`);return}this.shutdownInitiated=!0,g.info("SYSTEM",`Received ${i}, shutting down...`);try{this.shutdownHandler?await this.shutdownHandler():await this.stop()}catch(n){n instanceof Error?g.error("SYSTEM","Error during shutdown",{},n):g.error("SYSTEM","Error during shutdown (non-Error)",{error:String(n)});try{await this.stop()}catch(s){s instanceof Error?g.debug("SYSTEM","Supervisor shutdown fallback failed",{},s):g.debug("SYSTEM","Supervisor shutdown fallback failed",{error:String(s)})}}process.exit(0)};process.on("SIGTERM",()=>{r("SIGTERM")}),process.on("SIGINT",()=>{r("SIGINT")}),process.platform!=="win32"&&(process.argv.includes("--daemon")?process.on("SIGHUP",()=>{g.debug("SYSTEM","Ignoring SIGHUP in daemon mode")}):process.on("SIGHUP",()=>{r("SIGHUP")}))}async stop(){if(this.stopPromise){await this.stopPromise;return}JF(),this.stopPromise=GF({registry:this.registry,currentPid:process.pid}).finally(()=>{this.started=!1,this.stopPromise=null}),await this.stopPromise}assertCanSpawn(e){if(this.stopPromise!==null)throw new Error(`Supervisor is shutting down, refusing to spawn ${e}`)}registerProcess(e,r,i){this.registry.register(e,r,i)}unregisterProcess(e){this.registry.unregister(e)}getRegistry(){return this.registry}},ZR=new HR(Da())});function mme(t,e={},r){return new Promise((i,n)=>{let s=setTimeout(()=>n(new Error(`Request timed out after ${r}ms`)),r);fetch(t,e).then(o=>{clearTimeout(s),i(o)},o=>{clearTimeout(s),n(o)})})}function On(){if(Hf!==null)return Hf;let t=La.default.join(ke.get("CLAUDE_MEM_DATA_DIR"),"settings.json"),e=ke.loadFromFile(t);return Hf=parseInt(e.CLAUDE_MEM_WORKER_PORT,10),Hf}function VR(){if(Bf!==null)return Bf;let t=La.default.join(ke.get("CLAUDE_MEM_DATA_DIR"),"settings.json");return Bf=ke.loadFromFile(t).CLAUDE_MEM_WORKER_HOST,Bf}function nq(){Hf=null,Bf=null}function fme(t){return`http://${VR()}:${On()}${t}`}function Li(t,e={}){let r=e.method??"GET",i=e.timeoutMs??GR,n=fme(t),s={method:r};return e.headers&&(s.headers=e.headers),e.body&&(s.body=e.body),i>0?mme(n,s,i):fetch(n,s)}async function hme(){return(await Li("/api/health",{timeoutMs:GR})).ok}function gme(){try{let t=La.default.join(Mo,"package.json");return JSON.parse((0,fi.readFileSync)(t,"utf-8")).version}catch(t){let e=t instanceof Error?t.code:void 0;if(e==="ENOENT"||e==="EBUSY")return g.debug("SYSTEM","Could not read plugin version (shutdown race)",{code:e}),"unknown";throw t}}async function vme(){let t=await Li("/api/version",{timeoutMs:GR});if(!t.ok)throw new Error(`Failed to get worker version: ${t.status}`);return(await t.json()).version}async function yme(){let t;try{t=gme()}catch(r){g.debug("SYSTEM","Version check failed reading plugin version",{error:r instanceof Error?r.message:String(r)});return}if(t==="unknown")return;let e;try{e=await vme()}catch(r){g.debug("SYSTEM","Version check failed reading worker version",{error:r instanceof Error?r.message:String(r)});return}e!=="unknown"&&t!==e&&g.debug("SYSTEM","Version check",{pluginVersion:t,workerVersion:e,note:"Mismatch will be auto-restarted by worker-service start command"})}function _me(){let t=[La.default.join(Mo,"plugin","scripts","worker-service.cjs"),La.default.join(process.cwd(),"plugin","scripts","worker-service.cjs")];for(let e of t)if((0,fi.existsSync)(e))return e;return null}function bme(){if(process.env.BUN&&(0,fi.existsSync)(process.env.BUN))return process.env.BUN;try{let t=process.platform==="win32"?"where bun":"which bun";return(0,hS.execSync)(t,{stdio:["ignore","pipe","ignore"],encoding:"utf-8",windowsHide:!0}).split(/\r?\n/).map(i=>i.trim()).find(i=>i.length>0)||null}catch{return null}}async function Sme(t){let e=t.backoffMs;for(let r=1;r<=t.attempts;r++){if(await iq())return!0;rsetTimeout(i,e)),e*=2)}return!1}async function iq(){let t;try{t=await hme()}catch(r){return g.debug("SYSTEM","Worker health check threw",{error:r instanceof Error?r.message:String(r)}),!1}if(!t)return!1;let e=Wf({logAlive:!1});return e==="missing"||e==="alive"}async function gS(){if(await iq())return await yme(),!0;let t=bme(),e=_me();if(!t)return g.warn("SYSTEM","Cannot lazy-spawn worker: Bun runtime not found on PATH"),!1;if(!e)return g.warn("SYSTEM","Cannot lazy-spawn worker: worker-service.cjs not found in plugin/scripts"),!1;g.info("SYSTEM","Worker not running \u2014 lazy-spawning",{runtimePath:t,scriptPath:e});try{(0,hS.spawn)(t,[e,"--daemon"],{detached:!0,stdio:["ignore","ignore","ignore"]}).unref()}catch(i){return i instanceof Error?g.error("SYSTEM","Lazy-spawn of worker failed",{runtimePath:t,scriptPath:e},i):g.error("SYSTEM","Lazy-spawn of worker failed (non-Error)",{runtimePath:t,scriptPath:e,error:String(i)}),!1}return await Sme({attempts:3,backoffMs:250})?!0:(g.warn("SYSTEM","Worker port did not open after lazy-spawn within 3 attempts"),!1)}async function wme(){return fS!==null||(fS=await gS()),fS}function sq(){return La.default.join(Kt,"state")}function oq(){return La.default.join(sq(),"hook-failures.json")}function aq(){try{let t=(0,fi.readFileSync)(oq(),"utf-8"),e=JSON.parse(t);return{consecutiveFailures:typeof e.consecutiveFailures=="number"&&Number.isFinite(e.consecutiveFailures)?Math.max(0,Math.floor(e.consecutiveFailures)):0,lastFailureAt:typeof e.lastFailureAt=="number"&&Number.isFinite(e.lastFailureAt)?e.lastFailureAt:0}}catch{return{consecutiveFailures:0,lastFailureAt:0}}}function cq(t){let e=sq(),r=oq(),i=`${r}.tmp`;try{(0,fi.existsSync)(e)||(0,fi.mkdirSync)(e,{recursive:!0}),(0,fi.writeFileSync)(i,JSON.stringify(t),"utf-8"),(0,fi.renameSync)(i,r)}catch(n){g.debug("SYSTEM","Failed to persist hook-failure counter",{error:n instanceof Error?n.message:String(n)})}}function Eme(){try{let e=Ma().CLAUDE_MEM_HOOK_FAIL_LOUD_THRESHOLD,r=parseInt(e,10);if(Number.isFinite(r)&&r>=1)return r}catch{}return xme}function kme(){let e={consecutiveFailures:aq().consecutiveFailures+1,lastFailureAt:Date.now()};cq(e);let r=Eme();return e.consecutiveFailures>=r&&(process.stderr.write(`claude-mem worker unreachable for ${e.consecutiveFailures} consecutive hooks. -`),process.exit(dt.BLOCKING_ERROR)),e.consecutiveFailures}function rq(){aq().consecutiveFailures!==0&&cq({consecutiveFailures:0,lastFailureAt:0})}function Qr(t){return typeof t=="object"&&t!==null&&t[uq]===!0}async function en(t,e,r,i={}){if(!await wme())return kme(),{continue:!0,reason:"worker_unreachable",[uq]:!0};let s={method:e};r!==void 0&&(s.headers={"Content-Type":"application/json"},s.body=JSON.stringify(r)),i.timeoutMs!==void 0&&(s.timeoutMs=i.timeoutMs);let o=await Li(t,s);if(!o.ok){rq();let c=await o.text().catch(()=>""),u=c;try{u=JSON.parse(c)}catch{}return u}rq();let a=await o.text();if(a.length!==0)try{return JSON.parse(a)}catch{return a}}var La,fi,hS,GR,Hf,Bf,fS,xme,uq,hn=ye(()=>{"use strict";La=Oe(require("path"),1),fi=require("fs"),hS=require("child_process");oe();Xn();sr();Tt();zf();Ua();GR=(()=>{let t=process.env.CLAUDE_MEM_HEALTH_TIMEOUT_MS;if(t){let e=parseInt(t,10);if(Number.isFinite(e)&&e>=500&&e<=3e5)return e;g.warn("SYSTEM","Invalid CLAUDE_MEM_HEALTH_TIMEOUT_MS, using default",{value:t,min:500,max:3e5})}return IF(fn.HEALTH_CHECK)})();Hf=null,Bf=null;fS=null;xme=3;uq=Symbol.for("claude-mem/worker-fallback")});function hq(t){let e=bS.default.join(t,".git"),r;try{r=(0,SS.statSync)(e)}catch(l){return l instanceof Error&&l.code!=="ENOENT"&&console.warn("[worktree] Unexpected error checking .git:",l),Vf}if(!r.isFile())return Vf;let i;try{i=(0,SS.readFileSync)(e,"utf-8").trim()}catch(l){return console.warn("[worktree] Failed to read .git file:",l instanceof Error?l.message:String(l)),Vf}let n=i.match(/^gitdir:\s*(.+)$/);if(!n)return Vf;let o=n[1].match(/^(.+)[/\\]\.git[/\\]worktrees[/\\]([^/\\]+)$/);if(!o)return Vf;let a=o[1],c=bS.default.basename(t),u=bS.default.basename(a);return{isWorktree:!0,worktreeName:c,parentRepoPath:a,parentProjectName:u}}var SS,bS,Vf,gq=ye(()=>{"use strict";SS=require("fs"),bS=Oe(require("path"),1),Vf={isWorktree:!1,worktreeName:null,parentRepoPath:null,parentProjectName:null}});function _q(t){return t==="~"||t.startsWith("~/")?t.replace(/^~/,(0,vq.homedir)()):t}function Nme(t){if(!t||t.trim()==="")return g.warn("PROJECT_NAME","Empty cwd provided, using fallback",{cwd:t}),"unknown-project";let e=_q(t),r=yq.default.basename(e);if(r===""){if(process.platform==="win32"){let n=t.match(/^([A-Z]):\\/i);if(n){let o=`drive-${n[1].toUpperCase()}`;return g.info("PROJECT_NAME","Drive root detected",{cwd:t,projectName:o}),o}}return g.warn("PROJECT_NAME","Root directory detected, using fallback",{cwd:t}),"unknown-project"}return r}function vr(t){let e=Nme(t);if(!t)return{primary:e,parent:null,isWorktree:!1,allProjects:[e]};let r=_q(t),i=hq(r);if(i.isWorktree&&i.parentProjectName){let n=`${i.parentProjectName}/${e}`;return{primary:n,parent:i.parentProjectName,isWorktree:!0,allProjects:[i.parentProjectName,n]}}return{primary:e,parent:null,isWorktree:!1,allProjects:[e]}}var vq,yq,eo=ye(()=>{"use strict";vq=require("os"),yq=Oe(require("path"),1);oe();gq()});function wS(t,e,r){return(0,bq.createHash)("sha256").update([t||"",e||"",r||""].join("\0")).digest("hex").slice(0,16)}var bq,Sq=ye(()=>{"use strict";bq=require("crypto");oe();eo()});function td(t){if(!t)return[];try{let e=JSON.parse(t);return Array.isArray(e)?e:[String(e)]}catch{return[t]}}var nC=ye(()=>{"use strict"});function Mme(t){return t.trim().toLowerCase().replace(/\s+/g,"-")}function Zt(t){if(!t)return gn;let e=Mme(t);return e?e==="transcript"||e.includes("codex")?"codex":e.includes("cursor")?"cursor":e.includes("claude")?"claude":e:gn}function wq(t){let e=["claude","codex","cursor"];return[...t].sort((r,i)=>{let n=e.indexOf(r),s=e.indexOf(i);return n!==-1||s!==-1?n===-1?1:s===-1?-1:n-s:r.localeCompare(i)})}var gn,to=ye(()=>{"use strict";gn="claude"});function $me(t,e){return{customTitle:t,platformSource:e?Zt(e):void 0}}var iC,Do,xS=ye(()=>{"use strict";iC=require("bun:sqlite");Tt();oe();Sq();nC();to();Do=class{db;constructor(e=Wc){e instanceof iC.Database?this.db=e:(e!==":memory:"&&xr(Kt),this.db=new iC.Database(e),this.db.run("PRAGMA journal_mode = WAL"),this.db.run("PRAGMA synchronous = NORMAL"),this.db.run("PRAGMA foreign_keys = ON"),this.db.run("PRAGMA journal_size_limit = 4194304")),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(),this.ensureMergedIntoProjectColumns(),this.addObservationSubagentColumns(),this.addObservationsUniqueContentHashIndex()}initializeSchema(){this.db.run(` +`),process.exit(dt.BLOCKING_ERROR)),e.consecutiveFailures}function rq(){aq().consecutiveFailures!==0&&cq({consecutiveFailures:0,lastFailureAt:0})}function Qr(t){return typeof t=="object"&&t!==null&&t[uq]===!0}async function en(t,e,r,i={}){if(!await wme())return kme(),{continue:!0,reason:"worker_unreachable",[uq]:!0};let s={method:e};r!==void 0&&(s.headers={"Content-Type":"application/json"},s.body=JSON.stringify(r)),i.timeoutMs!==void 0&&(s.timeoutMs=i.timeoutMs);let o=await Li(t,s);if(!o.ok){rq();let c=await o.text().catch(()=>""),u=c;try{u=JSON.parse(c)}catch{}return u}rq();let a=await o.text();if(a.length!==0)try{return JSON.parse(a)}catch{return a}}var La,fi,hS,GR,Hf,Bf,fS,xme,uq,hn=ye(()=>{"use strict";La=Oe(require("path"),1),fi=require("fs"),hS=require("child_process");oe();Xn();sr();Tt();zf();Ua();GR=(()=>{let t=process.env.CLAUDE_MEM_HEALTH_TIMEOUT_MS;if(t){let e=parseInt(t,10);if(Number.isFinite(e)&&e>=500&&e<=3e5)return e;g.warn("SYSTEM","Invalid CLAUDE_MEM_HEALTH_TIMEOUT_MS, using default",{value:t,min:500,max:3e5})}return IF(fn.HEALTH_CHECK)})();Hf=null,Bf=null;fS=null;xme=3;uq=Symbol.for("claude-mem/worker-fallback")});function hq(t){let e=bS.default.join(t,".git"),r;try{r=(0,SS.statSync)(e)}catch(l){return l instanceof Error&&l.code!=="ENOENT"&&console.warn("[worktree] Unexpected error checking .git:",l),Vf}if(!r.isFile())return Vf;let i;try{i=(0,SS.readFileSync)(e,"utf-8").trim()}catch(l){return console.warn("[worktree] Failed to read .git file:",l instanceof Error?l.message:String(l)),Vf}let n=i.match(/^gitdir:\s*(.+)$/);if(!n)return Vf;let o=n[1].match(/^(.+)[/\\]\.git[/\\]worktrees[/\\]([^/\\]+)$/);if(!o)return Vf;let a=o[1],c=bS.default.basename(t),u=bS.default.basename(a);return{isWorktree:!0,worktreeName:c,parentRepoPath:a,parentProjectName:u}}var SS,bS,Vf,gq=ye(()=>{"use strict";SS=require("fs"),bS=Oe(require("path"),1),Vf={isWorktree:!1,worktreeName:null,parentRepoPath:null,parentProjectName:null}});function _q(t){return t==="~"||t.startsWith("~/")?t.replace(/^~/,(0,vq.homedir)()):t}function Nme(t){if(!t||t.trim()==="")return g.warn("PROJECT_NAME","Empty cwd provided, using fallback",{cwd:t}),"unknown-project";let e=_q(t),r=yq.default.basename(e);if(r===""){if(process.platform==="win32"){let n=t.match(/^([A-Z]):\\/i);if(n){let o=`drive-${n[1].toUpperCase()}`;return g.info("PROJECT_NAME","Drive root detected",{cwd:t,projectName:o}),o}}return g.warn("PROJECT_NAME","Root directory detected, using fallback",{cwd:t}),"unknown-project"}return r}function vr(t){let e=Nme(t);if(!t)return{primary:e,parent:null,isWorktree:!1,allProjects:[e]};let r=_q(t),i=hq(r);if(i.isWorktree&&i.parentProjectName){let n=`${i.parentProjectName}/${e}`;return{primary:n,parent:i.parentProjectName,isWorktree:!0,allProjects:[i.parentProjectName,n]}}return{primary:e,parent:null,isWorktree:!1,allProjects:[e]}}var vq,yq,eo=ye(()=>{"use strict";vq=require("os"),yq=Oe(require("path"),1);oe();gq()});function wS(t,e,r){return(0,bq.createHash)("sha256").update([t||"",e||"",r||""].join("\0")).digest("hex").slice(0,16)}var bq,Sq=ye(()=>{"use strict";bq=require("crypto");oe();eo()});function td(t){if(!t)return[];try{let e=JSON.parse(t);return Array.isArray(e)?e:[String(e)]}catch{return[t]}}var nC=ye(()=>{"use strict"});function Mme(t){return t.trim().toLowerCase().replace(/\s+/g,"-")}function Zt(t){if(!t)return gn;let e=Mme(t);return e?e==="transcript"||e.includes("codex")?"codex":e.includes("cursor")?"cursor":e.includes("claude")?"claude":e:gn}function wq(t){let e=["claude","codex","cursor"];return[...t].sort((r,i)=>{let n=e.indexOf(r),s=e.indexOf(i);return n!==-1||s!==-1?n===-1?1:s===-1?-1:n-s:r.localeCompare(i)})}var gn,to=ye(()=>{"use strict";gn="claude"});function $me(t,e){return{customTitle:t,platformSource:e?Zt(e):void 0}}var iC,Do,xS=ye(()=>{"use strict";iC=require("bun:sqlite");Tt();oe();Sq();nC();to();Do=class{db;constructor(e=Wc){e instanceof iC.Database?this.db=e:(e!==":memory:"&&xr(Kt),this.db=new iC.Database(e),this.db.run("PRAGMA journal_mode = WAL"),this.db.run("PRAGMA synchronous = NORMAL"),this.db.run("PRAGMA foreign_keys = ON"),this.db.run("PRAGMA journal_size_limit = 4194304")),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(),this.ensureMergedIntoProjectColumns(),this.addObservationSubagentColumns(),this.addPendingMessagesToolUseIdAndWorkerPidColumns(),this.addObservationsUniqueContentHashIndex()}initializeSchema(){this.db.run(` CREATE TABLE IF NOT EXISTS schema_versions ( id INTEGER PRIMARY KEY, version INTEGER UNIQUE NOT NULL, @@ -301,7 +301,19 @@ ${s.stack}`:` ${s.message}`:this.getLevel()===0&&typeof s=="object"?l=` UPDATE sdk_sessions SET platform_source = '${gn}' WHERE platform_source IS NULL OR platform_source = '' - `),n||this.db.run("CREATE INDEX IF NOT EXISTS idx_sdk_sessions_platform_source ON sdk_sessions(platform_source)"),this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(24,new Date().toISOString()))}addObservationModelColumns(){let e=this.db.query("PRAGMA table_info(observations)").all(),r=e.some(n=>n.name==="generated_by_model"),i=e.some(n=>n.name==="relevance_count");r&&i||(r||this.db.run("ALTER TABLE observations ADD COLUMN generated_by_model TEXT"),i||this.db.run("ALTER TABLE observations ADD COLUMN relevance_count INTEGER DEFAULT 0"),this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(26,new Date().toISOString()))}ensureMergedIntoProjectColumns(){this.db.query("PRAGMA table_info(observations)").all().some(i=>i.name==="merged_into_project")||this.db.run("ALTER TABLE observations ADD COLUMN merged_into_project TEXT"),this.db.run("CREATE INDEX IF NOT EXISTS idx_observations_merged_into ON observations(merged_into_project)"),this.db.query("PRAGMA table_info(session_summaries)").all().some(i=>i.name==="merged_into_project")||this.db.run("ALTER TABLE session_summaries ADD COLUMN merged_into_project TEXT"),this.db.run("CREATE INDEX IF NOT EXISTS idx_summaries_merged_into ON session_summaries(merged_into_project)")}addObservationSubagentColumns(){let e=this.db.prepare("SELECT version FROM schema_versions WHERE version = ?").get(27),r=this.db.query("PRAGMA table_info(observations)").all(),i=r.some(o=>o.name==="agent_type"),n=r.some(o=>o.name==="agent_id");i||this.db.run("ALTER TABLE observations ADD COLUMN agent_type TEXT"),n||this.db.run("ALTER TABLE observations ADD COLUMN agent_id TEXT"),this.db.run("CREATE INDEX IF NOT EXISTS idx_observations_agent_type ON observations(agent_type)"),this.db.run("CREATE INDEX IF NOT EXISTS idx_observations_agent_id ON observations(agent_id)");let s=this.db.query("PRAGMA table_info(pending_messages)").all();if(s.length>0){let o=s.some(c=>c.name==="agent_type"),a=s.some(c=>c.name==="agent_id");o||this.db.run("ALTER TABLE pending_messages ADD COLUMN agent_type TEXT"),a||this.db.run("ALTER TABLE pending_messages ADD COLUMN agent_id TEXT")}e||this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(27,new Date().toISOString())}addObservationsUniqueContentHashIndex(){if(this.db.prepare("SELECT version FROM schema_versions WHERE version = ?").get(29))return;let r=this.db.query("PRAGMA table_info(observations)").all(),i=r.some(s=>s.name==="memory_session_id"),n=r.some(s=>s.name==="content_hash");if(!i||!n){this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(29,new Date().toISOString());return}this.db.run("BEGIN TRANSACTION");try{this.db.run(` + `),n||this.db.run("CREATE INDEX IF NOT EXISTS idx_sdk_sessions_platform_source ON sdk_sessions(platform_source)"),this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(24,new Date().toISOString()))}addObservationModelColumns(){let e=this.db.query("PRAGMA table_info(observations)").all(),r=e.some(n=>n.name==="generated_by_model"),i=e.some(n=>n.name==="relevance_count");r&&i||(r||this.db.run("ALTER TABLE observations ADD COLUMN generated_by_model TEXT"),i||this.db.run("ALTER TABLE observations ADD COLUMN relevance_count INTEGER DEFAULT 0"),this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(26,new Date().toISOString()))}ensureMergedIntoProjectColumns(){this.db.query("PRAGMA table_info(observations)").all().some(i=>i.name==="merged_into_project")||this.db.run("ALTER TABLE observations ADD COLUMN merged_into_project TEXT"),this.db.run("CREATE INDEX IF NOT EXISTS idx_observations_merged_into ON observations(merged_into_project)"),this.db.query("PRAGMA table_info(session_summaries)").all().some(i=>i.name==="merged_into_project")||this.db.run("ALTER TABLE session_summaries ADD COLUMN merged_into_project TEXT"),this.db.run("CREATE INDEX IF NOT EXISTS idx_summaries_merged_into ON session_summaries(merged_into_project)")}addObservationSubagentColumns(){let e=this.db.prepare("SELECT version FROM schema_versions WHERE version = ?").get(27),r=this.db.query("PRAGMA table_info(observations)").all(),i=r.some(o=>o.name==="agent_type"),n=r.some(o=>o.name==="agent_id");i||this.db.run("ALTER TABLE observations ADD COLUMN agent_type TEXT"),n||this.db.run("ALTER TABLE observations ADD COLUMN agent_id TEXT"),this.db.run("CREATE INDEX IF NOT EXISTS idx_observations_agent_type ON observations(agent_type)"),this.db.run("CREATE INDEX IF NOT EXISTS idx_observations_agent_id ON observations(agent_id)");let s=this.db.query("PRAGMA table_info(pending_messages)").all();if(s.length>0){let o=s.some(c=>c.name==="agent_type"),a=s.some(c=>c.name==="agent_id");o||this.db.run("ALTER TABLE pending_messages ADD COLUMN agent_type TEXT"),a||this.db.run("ALTER TABLE pending_messages ADD COLUMN agent_id TEXT")}e||this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(27,new Date().toISOString())}addPendingMessagesToolUseIdAndWorkerPidColumns(){if(this.db.query("SELECT name FROM sqlite_master WHERE type='table' AND name='pending_messages'").all().length===0){this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(28,new Date().toISOString());return}let r=this.db.query("PRAGMA table_info(pending_messages)").all(),i=r.some(s=>s.name==="tool_use_id"),n=r.some(s=>s.name==="worker_pid");i||this.db.run("ALTER TABLE pending_messages ADD COLUMN tool_use_id TEXT"),n||this.db.run("ALTER TABLE pending_messages ADD COLUMN worker_pid INTEGER"),this.db.run("BEGIN TRANSACTION");try{this.db.run("CREATE INDEX IF NOT EXISTS idx_pending_messages_worker_pid ON pending_messages(worker_pid)"),this.db.run(` + DELETE FROM pending_messages + WHERE tool_use_id IS NOT NULL + AND id NOT IN ( + SELECT MIN(id) FROM pending_messages + WHERE tool_use_id IS NOT NULL + GROUP BY content_session_id, tool_use_id + ) + `),this.db.run(` + CREATE UNIQUE INDEX IF NOT EXISTS ux_pending_session_tool + ON pending_messages(content_session_id, tool_use_id) + WHERE tool_use_id IS NOT NULL + `),this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(28,new Date().toISOString()),this.db.run("COMMIT")}catch(s){throw this.db.run("ROLLBACK"),s}}addObservationsUniqueContentHashIndex(){if(this.db.prepare("SELECT version FROM schema_versions WHERE version = ?").get(29))return;let r=this.db.query("PRAGMA table_info(observations)").all(),i=r.some(s=>s.name==="memory_session_id"),n=r.some(s=>s.name==="content_hash");if(!i||!n){this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(29,new Date().toISOString());return}this.db.run("BEGIN TRANSACTION");try{this.db.run(` DELETE FROM observations WHERE id NOT IN ( SELECT MIN(id) FROM observations diff --git a/src/services/sqlite/SessionStore.ts b/src/services/sqlite/SessionStore.ts index a78a6c20..2c621480 100644 --- a/src/services/sqlite/SessionStore.ts +++ b/src/services/sqlite/SessionStore.ts @@ -73,6 +73,7 @@ export class SessionStore { this.addObservationModelColumns(); this.ensureMergedIntoProjectColumns(); this.addObservationSubagentColumns(); + this.addPendingMessagesToolUseIdAndWorkerPidColumns(); this.addObservationsUniqueContentHashIndex(); } @@ -1038,6 +1039,82 @@ export class SessionStore { } } + /** + * Add tool_use_id and worker_pid columns + indexes to pending_messages (migration 28). + * + * Mirrors MigrationRunner.rebuildPendingMessagesForSelfHealingClaim so bundled + * artifacts that embed SessionStore (e.g. worker-service.cjs, context-generator.cjs) + * stay schema-consistent. Without this, every queue-claim cycle fails with + * "no such column: worker_pid" and every observation insert fails with + * "table pending_messages has no column named tool_use_id" (issue #2139). + * + * Uses ALTER TABLE rather than the full table rebuild from MigrationRunner because: + * - It's safe on populated DBs that already reached v29 without ever applying v28. + * - The legacy stale-reset epoch column the rebuild dropped never existed in + * pending_messages tables created by the SessionStore migration path. + * + * Column existence is checked directly — schema_versions cannot be trusted because + * affected DBs may already have v29 recorded with neither column present (#2139). + */ + private addPendingMessagesToolUseIdAndWorkerPidColumns(): void { + // pending_messages may not exist yet on freshly-created DBs at this point in + // the migration order — createPendingMessagesTable (v16) has already run by + // the time we get here, so this guard is defensive only. + const tables = this.db.query( + "SELECT name FROM sqlite_master WHERE type='table' AND name='pending_messages'" + ).all() as TableNameRow[]; + if (tables.length === 0) { + this.db.prepare('INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)').run(28, new Date().toISOString()); + return; + } + + const cols = this.db.query('PRAGMA table_info(pending_messages)').all() as TableColumnInfo[]; + const hasToolUseId = cols.some(c => c.name === 'tool_use_id'); + const hasWorkerPid = cols.some(c => c.name === 'worker_pid'); + + if (!hasToolUseId) { + this.db.run('ALTER TABLE pending_messages ADD COLUMN tool_use_id TEXT'); + } + if (!hasWorkerPid) { + this.db.run('ALTER TABLE pending_messages ADD COLUMN worker_pid INTEGER'); + } + + // Wrap dedup DELETE + UNIQUE index creation + version-record in a transaction + // so a crash mid-flight cannot leave duplicates removed without v28 recorded. + // Matches addObservationsUniqueContentHashIndex (v29) at line 1127 and + // runner.ts rebuildPendingMessagesForSelfHealingClaim (v28). + this.db.run('BEGIN TRANSACTION'); + try { + // Indexes are idempotent — match runner.ts:1117-1120 + 1134-1138. + this.db.run('CREATE INDEX IF NOT EXISTS idx_pending_messages_worker_pid ON pending_messages(worker_pid)'); + + // The UNIQUE partial index requires no duplicate (content_session_id, tool_use_id) + // pairs. Dedup before creating it (matches runner.ts:1124-1132). Safe to run + // unconditionally — if tool_use_id was just added, every row has it as NULL + // and the WHERE filter excludes them. + this.db.run(` + DELETE FROM pending_messages + WHERE tool_use_id IS NOT NULL + AND id NOT IN ( + SELECT MIN(id) FROM pending_messages + WHERE tool_use_id IS NOT NULL + GROUP BY content_session_id, tool_use_id + ) + `); + this.db.run(` + CREATE UNIQUE INDEX IF NOT EXISTS ux_pending_session_tool + ON pending_messages(content_session_id, tool_use_id) + WHERE tool_use_id IS NOT NULL + `); + + this.db.prepare('INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)').run(28, new Date().toISOString()); + this.db.run('COMMIT'); + } catch (error) { + this.db.run('ROLLBACK'); + throw error; + } + } + /** * Add UNIQUE(memory_session_id, content_hash) on observations (migration 29). * Mirrors MigrationRunner.addObservationsUniqueContentHashIndex so bundled