keepmind 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/.agents/plugins/marketplace.json +20 -0
  2. package/.codex-plugin/plugin.json +46 -0
  3. package/LICENSE +202 -0
  4. package/README.md +139 -0
  5. package/dist/npx-cli/index.js +1398 -0
  6. package/dist/opencode-plugin/index.js +68 -0
  7. package/openclaw/Dockerfile.e2e +46 -0
  8. package/openclaw/SKILL.md +462 -0
  9. package/openclaw/TESTING.md +279 -0
  10. package/openclaw/dist/index.js +20 -0
  11. package/openclaw/e2e-verify.sh +222 -0
  12. package/openclaw/install.sh +1653 -0
  13. package/openclaw/openclaw.plugin.json +98 -0
  14. package/openclaw/package.json +21 -0
  15. package/openclaw/skills/do/SKILL.md +1 -0
  16. package/openclaw/skills/make-plan/SKILL.md +1 -0
  17. package/openclaw/src/index.test.ts +1178 -0
  18. package/openclaw/src/index.ts +1136 -0
  19. package/openclaw/test-e2e.sh +40 -0
  20. package/openclaw/test-install.sh +2086 -0
  21. package/openclaw/test-sse-consumer.js +98 -0
  22. package/openclaw/tsconfig.json +26 -0
  23. package/package.json +187 -0
  24. package/plugin/.claude-plugin/plugin.json +24 -0
  25. package/plugin/.codex-plugin/plugin.json +46 -0
  26. package/plugin/.mcp.json +12 -0
  27. package/plugin/bun.lock +325 -0
  28. package/plugin/hooks/bugfixes-2026-01-10.md +92 -0
  29. package/plugin/hooks/codex-hooks.json +63 -0
  30. package/plugin/hooks/hooks.json +117 -0
  31. package/plugin/modes/code--ar.json +24 -0
  32. package/plugin/modes/code--bn.json +24 -0
  33. package/plugin/modes/code--chill.json +8 -0
  34. package/plugin/modes/code--cs.json +24 -0
  35. package/plugin/modes/code--da.json +24 -0
  36. package/plugin/modes/code--de.json +24 -0
  37. package/plugin/modes/code--el.json +24 -0
  38. package/plugin/modes/code--es.json +24 -0
  39. package/plugin/modes/code--fi.json +24 -0
  40. package/plugin/modes/code--fr.json +24 -0
  41. package/plugin/modes/code--he.json +24 -0
  42. package/plugin/modes/code--hi.json +24 -0
  43. package/plugin/modes/code--hu.json +24 -0
  44. package/plugin/modes/code--id.json +24 -0
  45. package/plugin/modes/code--it.json +24 -0
  46. package/plugin/modes/code--ja.json +24 -0
  47. package/plugin/modes/code--ko.json +24 -0
  48. package/plugin/modes/code--nl.json +24 -0
  49. package/plugin/modes/code--no.json +24 -0
  50. package/plugin/modes/code--pl.json +24 -0
  51. package/plugin/modes/code--pt-br.json +24 -0
  52. package/plugin/modes/code--ro.json +24 -0
  53. package/plugin/modes/code--ru.json +24 -0
  54. package/plugin/modes/code--sv.json +24 -0
  55. package/plugin/modes/code--th.json +24 -0
  56. package/plugin/modes/code--tr.json +24 -0
  57. package/plugin/modes/code--uk.json +24 -0
  58. package/plugin/modes/code--ur.json +25 -0
  59. package/plugin/modes/code--vi.json +24 -0
  60. package/plugin/modes/code--zh.json +24 -0
  61. package/plugin/modes/code.json +139 -0
  62. package/plugin/modes/email-investigation.json +120 -0
  63. package/plugin/modes/law-study--chill.json +7 -0
  64. package/plugin/modes/law-study-CLAUDE.md +85 -0
  65. package/plugin/modes/law-study.json +120 -0
  66. package/plugin/modes/meme-tokens.json +125 -0
  67. package/plugin/package.json +47 -0
  68. package/plugin/scripts/bun-runner.js +229 -0
  69. package/plugin/scripts/context-generator.cjs +1005 -0
  70. package/plugin/scripts/mcp-server.cjs +247 -0
  71. package/plugin/scripts/statusline-counts.js +45 -0
  72. package/plugin/scripts/transcript-watcher.cjs +27 -0
  73. package/plugin/scripts/version-check.js +193 -0
  74. package/plugin/scripts/worker-cli.js +19 -0
  75. package/plugin/scripts/worker-service.cjs +2638 -0
  76. package/plugin/scripts/worker-wrapper.cjs +2 -0
  77. package/plugin/skills/babysit/SKILL.md +87 -0
  78. package/plugin/skills/design-is/SKILL.md +312 -0
  79. package/plugin/skills/do/SKILL.md +45 -0
  80. package/plugin/skills/how-it-works/SKILL.md +22 -0
  81. package/plugin/skills/how-it-works/onboarding-explainer.md +17 -0
  82. package/plugin/skills/knowledge-agent/SKILL.md +80 -0
  83. package/plugin/skills/learn-codebase/SKILL.md +21 -0
  84. package/plugin/skills/make-plan/SKILL.md +67 -0
  85. package/plugin/skills/mem-search/SKILL.md +131 -0
  86. package/plugin/skills/oh-my-issues/SKILL.md +226 -0
  87. package/plugin/skills/pathfinder/SKILL.md +111 -0
  88. package/plugin/skills/smart-explore/SKILL.md +193 -0
  89. package/plugin/skills/standup/SKILL.md +142 -0
  90. package/plugin/skills/standup/agent-brief.md +47 -0
  91. package/plugin/skills/standup/standup.mjs +662 -0
  92. package/plugin/skills/timeline-report/SKILL.md +211 -0
  93. package/plugin/skills/version-bump/SKILL.md +74 -0
  94. package/plugin/skills/version-bump/scripts/generate_changelog.js +34 -0
  95. package/plugin/skills/weekly-digests/SKILL.md +262 -0
  96. package/plugin/skills/what-the/SKILL.md +6 -0
  97. package/plugin/skills/wowerpoint/SKILL.md +205 -0
  98. package/plugin/ui/assets/fonts/monaspace-radon-var.woff +0 -0
  99. package/plugin/ui/assets/fonts/monaspace-radon-var.woff2 +0 -0
  100. package/plugin/ui/icon-thick-completed.svg +8 -0
  101. package/plugin/ui/icon-thick-investigated.svg +8 -0
  102. package/plugin/ui/icon-thick-learned.svg +12 -0
  103. package/plugin/ui/icon-thick-next-steps.svg +8 -0
  104. package/plugin/ui/viewer-bundle.js +65 -0
  105. package/plugin/ui/viewer.html +3302 -0
@@ -0,0 +1,1005 @@
1
+ "use strict";var ps=Object.create;var q=Object.defineProperty;var ms=Object.getOwnPropertyDescriptor;var Es=Object.getOwnPropertyNames;var gs=Object.getPrototypeOf,Ts=Object.prototype.hasOwnProperty;var fs=(r,e)=>{for(var t in e)q(r,t,{get:e[t],enumerable:!0})},Ge=(r,e,t,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of Es(e))!Ts.call(r,n)&&n!==t&&q(r,n,{get:()=>e[n],enumerable:!(s=ms(e,n))||s.enumerable});return r};var G=(r,e,t)=>(t=r!=null?ps(gs(r)):{},Ge(e||!r||!r.__esModule?q(t,"default",{value:r,enumerable:!0}):t,r)),bs=r=>Ge(q({},"__esModule",{value:!0}),r);var Sr={};fs(Sr,{generateContext:()=>_s,generateContextWithStats:()=>$e});module.exports=bs(Sr);var us=G(require("path"),1),cs=require("os"),ls=require("fs");var Xe=require("node:sqlite");function He(r){return typeof r=="bigint"?Number(r):r}function Ss(r){return r!==null&&typeof r=="object"&&!Array.isArray(r)&&!(r instanceof Uint8Array)&&!(typeof Buffer<"u"&&Buffer.isBuffer(r))}function Be(r){return r===void 0?null:typeof r=="boolean"?r?1:0:r}function J(r){let e=r;if(e.length===1&&Array.isArray(e[0])&&(e=e[0]),e.length===1&&Ss(e[0])){let t=e[0],s={};for(let n of Object.keys(t))s[n]=Be(t[n]);return[s]}return e.map(Be)}var ge=class{constructor(e){this.stmt=e}stmt;all(...e){return this.stmt.all(...J(e))}get(...e){return this.stmt.get(...J(e))??null}run(...e){let t=this.stmt.run(...J(e));return{changes:He(t.changes),lastInsertRowid:He(t.lastInsertRowid)}}values(...e){return this.stmt.all(...J(e)).map(s=>Object.values(s))}finalize(){}},H=class{db;queryCache=new Map;safeIntegers;txDepth=0;filename;constructor(e,t={}){let s=t.readonly===!0;this.safeIntegers=t.safeIntegers===!0;let n=e&&e.length>0?e:":memory:";if(this.filename=n,this.db=new Xe.DatabaseSync(n,{readOnly:s,allowExtension:!0}),!s&&n!==":memory:")try{this.db.exec("PRAGMA journal_mode=WAL")}catch{}}wrap(e){return this.safeIntegers&&e.setReadBigInts(!0),new ge(e)}prepare(e){return this.wrap(this.db.prepare(e))}query(e){let t=this.queryCache.get(e);if(t)return t;let s=this.prepare(e);return this.queryCache.set(e,s),s}run(e,...t){return t.length===0?(this.db.exec(e),{changes:0,lastInsertRowid:0}):this.prepare(e).run(...t)}exec(e){this.db.exec(e)}loadExtension(e,t){this.db.loadExtension(e)}transaction(e){return(...t)=>{let s=this.txDepth===0,n=`__cm_sp_${this.txDepth}`;s?this.db.exec("BEGIN"):this.db.exec(`SAVEPOINT ${n}`),this.txDepth++;try{let o=e(...t);return this.txDepth--,s?this.db.exec("COMMIT"):this.db.exec(`RELEASE ${n}`),o}catch(o){throw this.txDepth--,s?this.db.exec("ROLLBACK"):(this.db.exec(`ROLLBACK TO ${n}`),this.db.exec(`RELEASE ${n}`)),o}}}close(){this.db.close()}};var T=require("path"),he=require("os"),v=require("fs");var We=require("url");var w=require("fs"),je=require("path");var hs=null;function Rs(r){return(hs??process.stderr.write.bind(process.stderr))(r)}function Te(r){Rs(r)}var be=(o=>(o[o.DEBUG=0]="DEBUG",o[o.INFO=1]="INFO",o[o.WARN=2]="WARN",o[o.ERROR=3]="ERROR",o[o.SILENT=4]="SILENT",o))(be||{}),fe=null,Se=class{level=null;useColor;logFilePath=null;logFileInitialized=!1;constructor(){this.useColor=process.stdout.isTTY??!1}ensureLogFileInitialized(){if(!this.logFileInitialized){this.logFileInitialized=!0;try{let e=P.logsDir();(0,w.existsSync)(e)||(0,w.mkdirSync)(e,{recursive:!0});let t=new Date().toISOString().split("T")[0];this.logFilePath=(0,je.join)(e,`keepmind-${t}.log`)}catch(e){console.error("[LOGGER] Failed to initialize log file:",e instanceof Error?e.message:String(e)),this.logFilePath=null}}}getLevel(){if(this.level===null)try{let e=P.settings();if((0,w.existsSync)(e)){let t=(0,w.readFileSync)(e,"utf-8"),n=(JSON.parse(t).CLAUDE_MEM_LOG_LEVEL||"INFO").toUpperCase();this.level=be[n]??1}else this.level=1}catch(e){console.error("[LOGGER] Failed to load log level from settings:",e instanceof Error?e.message:String(e)),this.level=1}return this.level}formatData(e){if(e==null)return"";if(typeof e=="string")return e;if(typeof e=="number"||typeof e=="boolean")return e.toString();if(typeof e=="object"){if(e instanceof Error)return this.getLevel()===0?`${e.message}
2
+ ${e.stack}`:e.message;if(Array.isArray(e))return`[${e.length} items]`;let t=Object.keys(e);return t.length===0?"{}":t.length<=3?JSON.stringify(e):`{${t.length} keys: ${t.slice(0,3).join(", ")}...}`}return String(e)}formatTool(e,t){if(!t)return e;let s=t;if(typeof t=="string")try{s=JSON.parse(t)}catch{s=t}if(e==="Bash"&&s.command)return`${e}(${s.command})`;if(s.file_path)return`${e}(${s.file_path})`;if(s.notebook_path)return`${e}(${s.notebook_path})`;if(e==="Glob"&&s.pattern)return`${e}(${s.pattern})`;if(e==="Grep"&&s.pattern)return`${e}(${s.pattern})`;if(s.url)return`${e}(${s.url})`;if(s.query)return`${e}(${s.query})`;if(e==="Task"){if(s.subagent_type)return`${e}(${s.subagent_type})`;if(s.description)return`${e}(${s.description})`}return e==="Skill"&&s.skill?`${e}(${s.skill})`:e==="LSP"&&s.operation?`${e}(${s.operation})`:e}formatTimestamp(e){let t=e.getFullYear(),s=String(e.getMonth()+1).padStart(2,"0"),n=String(e.getDate()).padStart(2,"0"),o=String(e.getHours()).padStart(2,"0"),i=String(e.getMinutes()).padStart(2,"0"),a=String(e.getSeconds()).padStart(2,"0"),d=String(e.getMilliseconds()).padStart(3,"0");return`${t}-${s}-${n} ${o}:${i}:${a}.${d}`}log(e,t,s,n,o){if(e<this.getLevel())return;this.ensureLogFileInitialized();let i=this.formatTimestamp(new Date),a=be[e].padEnd(5),d=t.padEnd(6),u="";n?.correlationId?u=`[${n.correlationId}] `:n?.sessionId&&(u=`[session-${n.sessionId}] `);let c="";if(o!=null)if(o instanceof Error)c=this.getLevel()===0?`
3
+ ${o.message}
4
+ ${o.stack}`:` ${o.message}`;else if(this.getLevel()===0&&typeof o=="object")try{c=`
5
+ `+JSON.stringify(o,null,2)}catch{c=" "+this.formatData(o)}else c=" "+this.formatData(o);let m="";if(n){let{sessionId:g,memorySessionId:I,correlationId:A,...h}=n;Object.keys(h).length>0&&(m=` {${Object.entries(h).map(([y,D])=>`${y}=${D}`).join(", ")}}`)}let p=`[${i}] [${a}] [${d}] ${u}${s}${m}${c}`;if(this.logFilePath)try{(0,w.appendFileSync)(this.logFilePath,p+`
6
+ `,"utf8")}catch(g){Te(`[LOGGER] Failed to write to log file: ${g instanceof Error?g.message:String(g)}
7
+ `)}else Te(p+`
8
+ `)}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)}setErrorSink(e){fe=e}error(e,t,s,n){this.log(3,e,t,s,n),this.routeErrorToSink(t,s,n)}routeErrorToSink(e,t,s){try{if(!fe||!(s instanceof Error))return;fe(s)}catch{}}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)}happyPathError(e,t,s,n,o=""){let u=((new Error().stack||"").split(`
9
+ `)[2]||"").match(/at\s+(?:.*\s+)?\(?([^:]+):(\d+):(\d+)\)?/),c=u?`${u[1].split("/").pop()}:${u[2]}`:"unknown",m={...s,location:c};return this.warn(e,`[HAPPY-PATH] ${t}`,m,n),o}},l=new Se;var Us={};function Os(){return typeof __dirname<"u"?__dirname:(0,T.dirname)((0,We.fileURLToPath)(Us.url))}var As=Os();function Is(){let r=process.env.KEEPMIND_DATA_DIR??process.env.CLAUDE_MEM_DATA_DIR;if(r)return r;let e=(0,T.join)((0,he.homedir)(),".keepmind"),t=(0,T.join)(e,"settings.json");try{if((0,v.existsSync)(t)){let s=JSON.parse((0,v.readFileSync)(t,"utf-8")),n=s.env??s,o=n.KEEPMIND_DATA_DIR??n.CLAUDE_MEM_DATA_DIR;if(o)return o}}catch{}return e}var N=Is(),$=process.env.CLAUDE_CONFIG_DIR||(0,T.join)((0,he.homedir)(),".claude"),yr=(0,T.join)($,"plugins","marketplaces","keepmind"),Ns=(0,T.join)(N,"archives"),Cs=(0,T.join)(N,"logs"),Ls=(0,T.join)(N,"trash"),ys=(0,T.join)(N,"backups"),Ds=(0,T.join)(N,"modes"),Dr=(0,T.join)(N,"settings.json"),k=(0,T.join)(N,"keepmind.db"),B=(0,T.join)(N,"claude-mem.db"),vs=(0,T.join)(N,"vector-db"),Ve=(0,T.join)(N,"observer-sessions"),Re=(0,T.basename)(Ve),vr=(0,T.join)($,"settings.json"),Mr=(0,T.join)($,"commands"),Ur=(0,T.join)($,"CLAUDE.md");function Ke(r){(0,v.mkdirSync)(r,{recursive:!0})}function Ms(){try{if((0,v.existsSync)(k)||!(0,v.existsSync)(B))return(0,v.existsSync)(k);for(let r of["","-wal","-shm"]){let e=B+r,t=k+r;(0,v.existsSync)(e)&&!(0,v.existsSync)(t)&&(0,v.renameSync)(e,t)}return l.info("DB","Migrated legacy claude-mem.db to keepmind.db",{from:B,to:k}),!0}catch(r){return l.warn("DB","Could not rename legacy claude-mem.db to keepmind.db (file may be locked) \u2014 falling back to legacy path",{},r instanceof Error?r:new Error(String(r))),!1}}function Oe(){return Ms(),!(0,v.existsSync)(k)&&(0,v.existsSync)(B)?B:k}function Ye(){return(0,T.join)(As,"..")}var P={dataDir:()=>N,workerPid:()=>(0,T.join)(N,"worker.pid"),workerPort:()=>(0,T.join)(N,"worker.port"),serverPid:()=>(0,T.join)(N,".server-beta.pid"),serverPort:()=>(0,T.join)(N,".server-beta.port"),serverRuntime:()=>(0,T.join)(N,".server-beta.runtime.json"),settings:()=>(0,T.join)(N,"settings.json"),database:()=>Oe(),chroma:()=>(0,T.join)(N,"chroma"),combinedCerts:()=>(0,T.join)(N,"combined_certs.pem"),transcriptsConfig:()=>(0,T.join)(N,"transcript-watch.json"),transcriptsState:()=>(0,T.join)(N,"transcript-watch-state.json"),corpora:()=>(0,T.join)(N,"corpora"),supervisorRegistry:()=>(0,T.join)(N,"supervisor.json"),envFile:()=>(0,T.join)(N,".env"),logsDir:()=>Cs,archives:()=>Ns,trash:()=>Ls,backups:()=>ys,modes:()=>Ds,vectorDb:()=>vs,observerSessions:()=>Ve};var qe=require("crypto");function Ae(r,e,t){return(0,qe.createHash)("sha256").update([r||"",e||"",t||""].join("\0")).digest("hex").slice(0,16)}function Ie(r){if(!r)return[];try{let e=JSON.parse(r);return Array.isArray(e)?e:[String(e)]}catch{return[r]}}var Ne=r=>`\xABredacted:${r}\xBB`,xs=[{type:"PRIVATE_KEY",re:/-----BEGIN[ A-Z0-9_-]{0,100}PRIVATE KEY(?: BLOCK)?-----[\s\S]{0,4000}?-----END[ A-Z0-9_-]{0,100}PRIVATE KEY(?: BLOCK)?-----/g},{type:"CONNECTION_STRING",re:/\b(?:postgres(?:ql)?|mysql|mongodb(?:\+srv)?|redis|amqp|https?):\/\/[^\s/@]+:[^\s/@]+@[^\s]{1,200}/gi},{type:"AWS_KEY",re:/\b((?:A3T[A-Z0-9]|AKIA|ASIA|ABIA|ACCA)[A-Z2-7]{16})\b/g},{type:"GITHUB_FINE_PAT",re:/\bgithub_pat_\w{82}\b/g},{type:"GITHUB_PAT",re:/\bghp_[0-9A-Za-z]{36}\b/g},{type:"GITLAB_PAT",re:/\bglpat-[\w-]{20}\b/g},{type:"SLACK_TOKEN",re:/\bxox[baprs]-[0-9A-Za-z-]{10,200}\b/g},{type:"GOOGLE_API_KEY",re:/\bAIza[\w-]{35}\b/g},{type:"STRIPE_KEY",re:/\b(?:sk|rk|pk)_(?:test|live|prod)_[A-Za-z0-9]{10,99}\b/g},{type:"JWT",re:/\bey[A-Za-z0-9_-]{17,500}\.ey[A-Za-z0-9_/\\-]{17,500}\.[A-Za-z0-9_/\\-]{10,500}={0,2}/g},{type:"BEARER",re:/\b[Bb]earer\s+[A-Za-z0-9._~+/=-]{12,500}/g},{type:"BCRYPT",re:/\$2[aby]\$\d{2}\$[./A-Za-z0-9]{53}/g},{type:"GENERIC_SECRET",re:/(?:pass(?:word)?|secret|token|api[_-]?key|client[_-]?secret|auth)\b['"\s]{0,3}[:=>]{1,2}['"\s]{0,3}([\w./+=-]{10,150})/gi,group:1}];function ws(r,e){if(e.re.lastIndex=0,e.group===void 0)return r.replace(e.re,Ne(e.type));let t=e.group;return r.replace(e.re,(s,...n)=>{let o=n[t-1];return typeof o!="string"||o.length===0?s:s.replace(o,Ne(e.type))})}function ks(r){if(r.length===0)return 0;let e=new Map;for(let s of r)e.set(s,(e.get(s)??0)+1);let t=0;for(let s of e.values()){let n=s/r.length;t-=n*Math.log2(n)}return t}var Fs=/^[0-9a-f]+$/i;function Ps(r,e){return r.length<20||r.length>200||/[\s]/.test(r)||!/\d/.test(r)||!/[A-Za-z]/.test(r)||r.includes("/")||r.includes("\\")||r.length<=64&&Fs.test(r)||r.includes("redacted:")?!1:ks(r)>=e}var $s=/([\s"'`,;(){}\[\]<>]+)/;function Gs(r,e){let t=r.split($s);for(let s=0;s<t.length;s++){let n=t[s];n&&Ps(n,e)&&(t[s]=Ne("HIGH_ENTROPY"))}return t.join("")}function Ce(r,e={}){if(typeof r!="string"||r.length===0)return r;try{let t=r;for(let s of xs)t=ws(t,s);return e.entropySweep!==!1&&(t=Gs(t,e.entropyThreshold??4)),t}catch{return r}}function Q(r,e={}){if(typeof r=="string")return Ce(r,e);if(Array.isArray(r))return r.map(t=>Q(t,e));if(r&&typeof r=="object"){let t={};for(let[s,n]of Object.entries(r))t[s]=Q(n,e);return t}return r}var Z=require("fs");var ye={redactSecrets:{enabled:!0,entropyThreshold:4,entropySweep:!0},scoping:{enabled:!0,includeGlobal:!0,defaultSearchScope:"project"},importance:{enabled:!0,halfLifeDays:14,llmRefine:!1},injection:{tokenBudget:4e3,candidateMultiplier:3},reconcile:{enabled:!1,noopThreshold:.92,updateBand:.75,llmAdjudicate:!1,allowHardDelete:!1},supersession:{enabled:!1},expiry:{enabled:!1,ttlDays:28,importanceFloor:7,hardDelete:!1},optimizer:{enabled:!0,tickMinutes:5,vacuumHours:24}};function z(r){return!!r&&typeof r=="object"&&!Array.isArray(r)}function F(r,e){if(!z(e))return{...r};let t={...r};for(let s of Object.keys(r))e[s]!==void 0&&typeof e[s]==typeof r[s]&&(t[s]=e[s]);return t}var Le=null;function ee(r=!1){if(Le&&!r)return Le;let e=ye,t;try{let o=P.settings();if((0,Z.existsSync)(o)){let i=JSON.parse((0,Z.readFileSync)(o,"utf-8").replace(/^/,"")),a=z(i)?i.memoryQuality??(z(i.env)?i.env.memoryQuality:void 0):void 0;z(a)&&(t=a)}}catch(o){l.debug("CONFIG","memoryQuality config load failed; using defaults",{},o instanceof Error?o:new Error(String(o)))}let s={redactSecrets:F(e.redactSecrets,t?.redactSecrets),scoping:F(e.scoping,t?.scoping),importance:F(e.importance,t?.importance),injection:F(e.injection,t?.injection),reconcile:F(e.reconcile,t?.reconcile),supersession:F(e.supersession,t?.supersession),expiry:F(e.expiry,t?.expiry),optimizer:F(e.optimizer,t?.optimizer)},n=process.env.CLAUDE_MEM_REDACT_SECRETS;return(n==="0"||n==="false")&&(s.redactSecrets.enabled=!1),Le=s,s}var Hs={decision:9,bugfix:8,refactor:6,discovery:5,global:7,other:3,trivial:1};function Bs(r){if(Array.isArray(r))return r.length;if(typeof r=="string")try{let e=JSON.parse(r);return Array.isArray(e)?e.length:0}catch{return 0}return 0}function De(r){let e=Hs[r.type??"other"]??4;return Bs(r.files_modified)>0&&(e+=1),(r.narrative?.length??0)<40&&(e-=1),/\b(TODO|FIXME|WIP)\b/i.test(r.narrative??"")&&(e-=1),Math.max(1,Math.min(10,e))}var Xs=14,js=864e5;function Je(r,e={}){let t=e.now??Date.now(),s=(e.halfLifeDays??Xs)*js,n=(r.importance??5)/10,o=Math.max(0,t-(r.created_at_epoch??t)),i=Math.pow(.5,o/s);return n*i}var Ws=new Set(["the","a","an","and","or","but","to","of","in","on","for","with","is","are","was","were","be","been","it","this","that","we","i","as","at","by","from","into","over","so","then","than","will"]);function te(r){return r?r.toLowerCase().replace(/[^a-z0-9\s]+/g," ").split(/\s+/).filter(e=>e.length>0&&!Ws.has(e)).join(" ").trim():""}function Qe(r){let e=new Set,t=r.replace(/\s+/g," ");for(let s=0;s+3<=t.length;s++)e.add(t.slice(s,s+3));return e}function Vs(r,e){let t=Qe(r),s=Qe(e);if(t.size===0&&s.size===0)return 1;if(t.size===0||s.size===0)return 0;let n=0;for(let o of t)s.has(o)&&n++;return n/(t.size+s.size-n)}function Ks(r,e){let t=new Map,s=new Map;for(let a of r.split(" "))a&&t.set(a,(t.get(a)??0)+1);for(let a of e.split(" "))a&&s.set(a,(s.get(a)??0)+1);if(t.size===0||s.size===0)return 0;let n=0;for(let[a,d]of t)n+=d*(s.get(a)??0);let o=0;for(let a of t.values())o+=a*a;let i=0;for(let a of s.values())i+=a*a;return n/(Math.sqrt(o)*Math.sqrt(i)||1)}function Ys(r,e){let t=te(`${r??""}`),s=te(`${e??""}`);return Math.max(Vs(t,s),Ks(t,s))}function ze(r,e,t){let s=`${r.title??""} ${r.narrative??""}`,n={action:"ADD"},o=-1;for(let i of e){let a=Ys(s,`${i.title??""} ${i.narrative??""}`);a<=o||(o=a,a>=t.noopThreshold?n={action:"NOOP",candidateId:i.id,score:a}:a>=t.updateBand&&t.supersessionEnabled?n={action:"UPDATE",candidateId:i.id,score:a}:n={action:"ADD",score:a})}return n}var Ze=require("crypto");function ve(r){let e=r.title??"";if(!e){if(Array.isArray(r.facts)&&r.facts.length>0)e=r.facts[0];else if(typeof r.facts=="string")try{let s=JSON.parse(r.facts);Array.isArray(s)&&s.length>0&&(e=String(s[0]))}catch{}}e||(e=(r.narrative??"").slice(0,80));let t=te(e);return(0,Ze.createHash)("sha1").update(t).digest("hex").slice(0,16)}var E="claude";function qs(r){return r.trim().toLowerCase().replace(/\s+/g,"-")}function L(r){if(!r)return E;let e=qs(r);return e?e==="transcript"||e.includes("codex")?"codex":e.includes("cursor")?"cursor":e.includes("claude")?"claude":e:E}function et(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 tt(r,e,t,s,n){let o=Date.now()-s,i=n!==void 0?"up.session_db_id = ?":"up.content_session_id = ?",a=n??e;return r.prepare(`
10
+ SELECT
11
+ up.*,
12
+ s.memory_session_id,
13
+ s.project,
14
+ COALESCE(s.platform_source, '${E}') as platform_source
15
+ FROM user_prompts up
16
+ JOIN sdk_sessions s ON up.session_db_id = s.id
17
+ WHERE ${i}
18
+ AND up.prompt_text = ?
19
+ AND up.created_at_epoch >= ?
20
+ ORDER BY up.created_at_epoch DESC
21
+ LIMIT 1
22
+ `).get(a,t,o)??void 0}var nt=["private","claude-mem-context","system_instruction","system-instruction","persisted-output","system-reminder"],st=new RegExp(`<(${nt.join("|")})\\b[^>]*>[\\s\\S]*?</\\1>`,"g"),ot=/<system-reminder>[\s\S]*?<\/system-reminder>/g,rt=100;function Js(r){let e=Object.fromEntries(nt.map(n=>[n,0]));st.lastIndex=0;let t=0,s=r.replace(st,(n,o)=>(e[o]=(e[o]??0)+1,t+=1,""));return t>rt&&l.warn("SYSTEM","tag count exceeds limit",void 0,{tagCount:t,maxAllowed:rt,contentLength:r.length}),{stripped:s.trim(),counts:e}}function it(r){return Js(r).stripped}var Qs=["task-notification"],qr=new RegExp(`^\\s*<(${Qs.join("|")})\\b[^>]*>(?:(?!<\\1\\b|</\\1\\b)[\\s\\S])*</\\1>\\s*$`),Jr=256*1024;var Me=4e3;function se(r){let e=r.trim(),s=it(r).trim()||e;return s.length<=Me?s:(l.debug("DB","Truncated stored prompt text to the configured cap",{originalLength:s.length,storedLength:Me}),`${s.slice(0,Me-1)}\u2026`)}function zs(r,e){return{customTitle:r,platformSource:e?L(e):void 0}}var re=class{db;redactEnabled;redactOpts;mq;rt(e){return this.redactEnabled?Ce(e,this.redactOpts):e}rl(e){return this.redactEnabled?Q(e,this.redactOpts):e}constructor(e=k){try{this.mq=ee();let t=this.mq.redactSecrets;this.redactEnabled=t.enabled,this.redactOpts={entropySweep:t.entropySweep,entropyThreshold:t.entropyThreshold}}catch{this.mq=ye,this.redactEnabled=process.env.CLAUDE_MEM_REDACT_SECRETS!=="0"&&process.env.CLAUDE_MEM_REDACT_SECRETS!=="false",this.redactOpts={entropySweep:!0,entropyThreshold:4}}if(e instanceof H)this.db=e;else{e!==":memory:"&&Ke(N);let t=e===k?Oe():e;this.db=new H(t),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(),this.addObservationsMetadataColumn(),this.dropDeadPendingMessagesColumns(),this.ensurePendingMessagesToolUseIdColumn(),this.dropWorkerPidColumn(),this.ensureSDKSessionsPlatformContentIdentity(),this.ensureUserPromptsSessionDbId(),this.ensurePendingMessagesSessionToolUniqueIndex(),this.addObservationImportanceColumn(),this.addObservationBitemporalColumns(),this.addObservationLastUsedColumn()}addObservationBitemporalColumns(){let e=this.db.prepare("SELECT version FROM schema_versions WHERE version = ?").get(37),t=this.db.query("PRAGMA table_info(observations)").all(),s=n=>t.some(o=>o.name===n);e&&s("valid_from")&&s("valid_to")&&s("subject_key")||(s("valid_from")||this.db.run("ALTER TABLE observations ADD COLUMN valid_from INTEGER"),s("valid_to")||this.db.run("ALTER TABLE observations ADD COLUMN valid_to INTEGER"),s("subject_key")||this.db.run("ALTER TABLE observations ADD COLUMN subject_key TEXT"),this.db.run("UPDATE observations SET valid_from = created_at_epoch WHERE valid_from IS NULL"),this.db.run("CREATE INDEX IF NOT EXISTS idx_obs_subject_valid ON observations(project, subject_key, valid_to)"),e||this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(37,new Date().toISOString()))}addObservationLastUsedColumn(){let e=this.db.prepare("SELECT version FROM schema_versions WHERE version = ?").get(38),s=this.db.query("PRAGMA table_info(observations)").all().some(n=>n.name==="last_used_at");e&&s||(s||this.db.run("ALTER TABLE observations ADD COLUMN last_used_at INTEGER"),this.db.run("CREATE INDEX IF NOT EXISTS idx_obs_last_used ON observations(last_used_at)"),e||this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(38,new Date().toISOString()))}addObservationImportanceColumn(){let e=this.db.prepare("SELECT version FROM schema_versions WHERE version = ?").get(36),s=this.db.query("PRAGMA table_info(observations)").all().some(n=>n.name==="importance");e&&s||(s||this.db.run("ALTER TABLE observations ADD COLUMN importance INTEGER"),this.db.run("CREATE INDEX IF NOT EXISTS idx_observations_importance ON observations(importance)"),e||this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(36,new Date().toISOString()))}getIndexColumns(e){return this.db.query(`PRAGMA index_info(${JSON.stringify(e)})`).all().map(t=>t.name)}hasUniqueIndexOnColumns(e,t){return this.db.query(`PRAGMA index_list(${e})`).all().some(n=>{if(n.unique!==1)return!1;let o=this.getIndexColumns(n.name);return o.length===t.length&&o.every((i,a)=>i===t[a])})}resolvePromptSessionDbId(e,t,s){if(t!==void 0)return t;let n=s?L(s):void 0;return n?this.db.prepare(`
23
+ SELECT id
24
+ FROM sdk_sessions
25
+ WHERE COALESCE(NULLIF(platform_source, ''), ?) = ?
26
+ AND content_session_id = ?
27
+ LIMIT 1
28
+ `).get(E,n,e)?.id??null:this.db.prepare(`
29
+ SELECT id
30
+ FROM sdk_sessions
31
+ WHERE content_session_id = ?
32
+ ORDER BY CASE COALESCE(NULLIF(platform_source, ''), '${E}')
33
+ WHEN '${E}' THEN 0
34
+ ELSE 1
35
+ END, id
36
+ LIMIT 1
37
+ `).get(e)?.id??null}dropWorkerPidColumn(){let e=this.db.prepare("SELECT version FROM schema_versions WHERE version = ?").get(32),s=this.db.query("PRAGMA table_info(pending_messages)").all().some(n=>n.name==="worker_pid");if(!(e&&!s)){if(s)try{this.db.run("DROP INDEX IF EXISTS idx_pending_messages_worker_pid"),this.db.run("ALTER TABLE pending_messages DROP COLUMN worker_pid"),l.debug("DB","Dropped worker_pid column and its index from pending_messages")}catch(n){l.warn("DB","Failed to drop worker_pid column from pending_messages",{},n instanceof Error?n:new Error(String(n)));return}e||this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(32,new Date().toISOString())}}ensureSDKSessionsPlatformContentIdentity(){let e=this.db.prepare("SELECT version FROM schema_versions WHERE version = ?").get(33),t=this.hasUniqueIndexOnColumns("sdk_sessions",["content_session_id"]),s=this.hasUniqueIndexOnColumns("sdk_sessions",["platform_source","content_session_id"]),o=this.db.query("PRAGMA table_info(sdk_sessions)").all().some(i=>i.name==="platform_source");if(!(e&&!t&&s&&o)){if(o||this.db.run(`ALTER TABLE sdk_sessions ADD COLUMN platform_source TEXT NOT NULL DEFAULT '${E}'`),this.db.run(`
38
+ UPDATE sdk_sessions
39
+ SET platform_source = '${E}'
40
+ WHERE platform_source IS NULL OR platform_source = ''
41
+ `),t){this.db.run("PRAGMA foreign_keys = OFF"),this.db.run("BEGIN TRANSACTION");try{this.db.run("DROP TABLE IF EXISTS sdk_sessions_new"),this.db.run(`
42
+ CREATE TABLE sdk_sessions_new (
43
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
44
+ content_session_id TEXT NOT NULL,
45
+ memory_session_id TEXT UNIQUE,
46
+ project TEXT NOT NULL,
47
+ platform_source TEXT NOT NULL DEFAULT '${E}',
48
+ user_prompt TEXT,
49
+ started_at TEXT NOT NULL,
50
+ started_at_epoch INTEGER NOT NULL,
51
+ completed_at TEXT,
52
+ completed_at_epoch INTEGER,
53
+ status TEXT NOT NULL DEFAULT 'active' CHECK(status IN ('active', 'completed', 'failed')),
54
+ worker_port INTEGER,
55
+ prompt_counter INTEGER DEFAULT 0,
56
+ custom_title TEXT
57
+ )
58
+ `),this.db.run(`
59
+ INSERT INTO sdk_sessions_new (
60
+ id, content_session_id, memory_session_id, project, platform_source,
61
+ user_prompt, started_at, started_at_epoch, completed_at, completed_at_epoch,
62
+ status, worker_port, prompt_counter, custom_title
63
+ )
64
+ SELECT
65
+ id, content_session_id, memory_session_id, project,
66
+ COALESCE(NULLIF(platform_source, ''), '${E}'),
67
+ user_prompt, started_at, started_at_epoch, completed_at, completed_at_epoch,
68
+ status, worker_port, prompt_counter, custom_title
69
+ FROM sdk_sessions
70
+ `),this.db.run("DROP TABLE sdk_sessions"),this.db.run("ALTER TABLE sdk_sessions_new RENAME TO sdk_sessions"),this.db.run("CREATE INDEX IF NOT EXISTS idx_sdk_sessions_claude_id ON sdk_sessions(content_session_id)"),this.db.run("CREATE INDEX IF NOT EXISTS idx_sdk_sessions_sdk_id ON sdk_sessions(memory_session_id)"),this.db.run("CREATE INDEX IF NOT EXISTS idx_sdk_sessions_project ON sdk_sessions(project)"),this.db.run("CREATE INDEX IF NOT EXISTS idx_sdk_sessions_status ON sdk_sessions(status)"),this.db.run("CREATE INDEX IF NOT EXISTS idx_sdk_sessions_started ON sdk_sessions(started_at_epoch DESC)"),this.db.run("CREATE INDEX IF NOT EXISTS idx_sdk_sessions_platform_source ON sdk_sessions(platform_source)"),this.db.run("CREATE UNIQUE INDEX IF NOT EXISTS ux_sdk_sessions_platform_content ON sdk_sessions(platform_source, content_session_id)"),e||this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(33,new Date().toISOString()),this.db.run("COMMIT")}catch(i){throw this.db.run("ROLLBACK"),i}finally{this.db.run("PRAGMA foreign_keys = ON")}return}this.db.run("CREATE UNIQUE INDEX IF NOT EXISTS ux_sdk_sessions_platform_content ON sdk_sessions(platform_source, content_session_id)"),this.db.run("CREATE INDEX IF NOT EXISTS idx_sdk_sessions_platform_source ON sdk_sessions(platform_source)"),e||this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(33,new Date().toISOString())}}ensureUserPromptsSessionDbId(){let e=this.db.prepare("SELECT version FROM schema_versions WHERE version = ?").get(34);if(this.db.query("SELECT name FROM sqlite_master WHERE type='table' AND name='user_prompts'").all().length===0){this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(34,new Date().toISOString());return}let n=this.db.query("PRAGMA table_info(user_prompts)").all().some(u=>u.name==="session_db_id"),i=this.db.query("PRAGMA foreign_key_list(user_prompts)").all().some(u=>u.table==="sdk_sessions"&&u.from==="content_session_id");if(e&&n&&!i)return;let a=this.db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='user_prompts_fts'").all().length>0,d=n?`COALESCE(up.session_db_id, (
71
+ SELECT s.id FROM sdk_sessions s
72
+ WHERE s.content_session_id = up.content_session_id
73
+ ORDER BY CASE COALESCE(NULLIF(s.platform_source, ''), '${E}')
74
+ WHEN '${E}' THEN 0
75
+ ELSE 1
76
+ END, s.id
77
+ LIMIT 1
78
+ ))`:`(
79
+ SELECT s.id FROM sdk_sessions s
80
+ WHERE s.content_session_id = up.content_session_id
81
+ ORDER BY CASE COALESCE(NULLIF(s.platform_source, ''), '${E}')
82
+ WHEN '${E}' THEN 0
83
+ ELSE 1
84
+ END, s.id
85
+ LIMIT 1
86
+ )`;this.db.run("PRAGMA foreign_keys = OFF"),this.db.run("BEGIN TRANSACTION");try{this.db.run("DROP TRIGGER IF EXISTS user_prompts_ai"),this.db.run("DROP TRIGGER IF EXISTS user_prompts_ad"),this.db.run("DROP TRIGGER IF EXISTS user_prompts_au"),this.db.run("DROP TABLE IF EXISTS user_prompts_new"),this.db.run(`
87
+ CREATE TABLE user_prompts_new (
88
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
89
+ session_db_id INTEGER,
90
+ content_session_id TEXT NOT NULL,
91
+ prompt_number INTEGER NOT NULL,
92
+ prompt_text TEXT NOT NULL,
93
+ created_at TEXT NOT NULL,
94
+ created_at_epoch INTEGER NOT NULL,
95
+ FOREIGN KEY(session_db_id) REFERENCES sdk_sessions(id) ON DELETE CASCADE
96
+ )
97
+ `),this.db.run(`
98
+ INSERT INTO user_prompts_new (
99
+ id, session_db_id, content_session_id, prompt_number,
100
+ prompt_text, created_at, created_at_epoch
101
+ )
102
+ SELECT
103
+ up.id,
104
+ ${d},
105
+ up.content_session_id,
106
+ up.prompt_number,
107
+ up.prompt_text,
108
+ up.created_at,
109
+ up.created_at_epoch
110
+ FROM user_prompts up
111
+ `),this.db.run("DROP TABLE user_prompts"),this.db.run("ALTER TABLE user_prompts_new RENAME TO user_prompts"),this.db.run("CREATE INDEX IF NOT EXISTS idx_user_prompts_session ON user_prompts(session_db_id)"),this.db.run("CREATE INDEX IF NOT EXISTS idx_user_prompts_claude_session ON user_prompts(content_session_id)"),this.db.run("CREATE INDEX IF NOT EXISTS idx_user_prompts_created ON user_prompts(created_at_epoch DESC)"),this.db.run("CREATE INDEX IF NOT EXISTS idx_user_prompts_prompt_number ON user_prompts(prompt_number)"),this.db.run("CREATE INDEX IF NOT EXISTS idx_user_prompts_lookup ON user_prompts(session_db_id, prompt_number)"),this.db.run("CREATE INDEX IF NOT EXISTS idx_user_prompts_content_lookup ON user_prompts(content_session_id, prompt_number)"),a&&(this.db.run(`
112
+ CREATE TRIGGER user_prompts_ai AFTER INSERT ON user_prompts BEGIN
113
+ INSERT INTO user_prompts_fts(rowid, prompt_text)
114
+ VALUES (new.id, new.prompt_text);
115
+ END;
116
+
117
+ CREATE TRIGGER user_prompts_ad AFTER DELETE ON user_prompts BEGIN
118
+ INSERT INTO user_prompts_fts(user_prompts_fts, rowid, prompt_text)
119
+ VALUES('delete', old.id, old.prompt_text);
120
+ END;
121
+
122
+ CREATE TRIGGER user_prompts_au AFTER UPDATE ON user_prompts BEGIN
123
+ INSERT INTO user_prompts_fts(user_prompts_fts, rowid, prompt_text)
124
+ VALUES('delete', old.id, old.prompt_text);
125
+ INSERT INTO user_prompts_fts(rowid, prompt_text)
126
+ VALUES (new.id, new.prompt_text);
127
+ END;
128
+ `),this.db.run("INSERT INTO user_prompts_fts(user_prompts_fts) VALUES('rebuild')")),e||this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(34,new Date().toISOString()),this.db.run("COMMIT")}catch(u){throw this.db.run("ROLLBACK"),u}finally{this.db.run("PRAGMA foreign_keys = ON")}}ensurePendingMessagesSessionToolUniqueIndex(){let e=this.db.prepare("SELECT version FROM schema_versions WHERE version = ?").get(35);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(35,new Date().toISOString());return}let s=this.hasUniqueIndexOnColumns("pending_messages",["session_db_id","tool_use_id"]);if(!(e&&s)){this.db.run("BEGIN TRANSACTION");try{this.db.run("DROP INDEX IF EXISTS ux_pending_session_tool"),this.db.run(`
129
+ DELETE FROM pending_messages
130
+ WHERE id IN (
131
+ SELECT id
132
+ FROM (
133
+ SELECT id,
134
+ ROW_NUMBER() OVER (
135
+ PARTITION BY session_db_id, tool_use_id
136
+ ORDER BY CASE status
137
+ WHEN 'processing' THEN 0
138
+ WHEN 'pending' THEN 1
139
+ ELSE 2
140
+ END, id
141
+ ) AS duplicate_rank
142
+ FROM pending_messages
143
+ WHERE tool_use_id IS NOT NULL
144
+ )
145
+ WHERE duplicate_rank > 1
146
+ )
147
+ `),this.db.run(`
148
+ CREATE UNIQUE INDEX IF NOT EXISTS ux_pending_session_tool
149
+ ON pending_messages(session_db_id, tool_use_id)
150
+ WHERE tool_use_id IS NOT NULL
151
+ `),e||this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(35,new Date().toISOString()),this.db.run("COMMIT")}catch(n){throw this.db.run("ROLLBACK"),n}}}dropDeadPendingMessagesColumns(){let e=this.db.prepare("SELECT version FROM schema_versions WHERE version = ?").get(31),t=this.db.query("PRAGMA table_info(pending_messages)").all(),s=new Set(t.map(i=>i.name)),o=["retry_count","failed_at_epoch","completed_at_epoch"].filter(i=>s.has(i));if(!(e&&o.length===0)){if(o.length>0){this.db.run("BEGIN TRANSACTION");try{this.db.run("DELETE FROM pending_messages WHERE status NOT IN ('pending', 'processing')");for(let i of o)this.db.run(`ALTER TABLE pending_messages DROP COLUMN ${i}`),l.debug("DB",`Dropped dead column ${i} from pending_messages`);e||this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(31,new Date().toISOString()),this.db.run("COMMIT")}catch(i){this.db.run("ROLLBACK"),l.warn("DB","Failed to drop dead columns from pending_messages",{},i instanceof Error?i:new Error(String(i)));return}return}e||this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(31,new Date().toISOString())}}initializeSchema(){this.db.run(`
152
+ CREATE TABLE IF NOT EXISTS schema_versions (
153
+ id INTEGER PRIMARY KEY,
154
+ version INTEGER UNIQUE NOT NULL,
155
+ applied_at TEXT NOT NULL
156
+ )
157
+ `),this.db.run(`
158
+ CREATE TABLE IF NOT EXISTS sdk_sessions (
159
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
160
+ content_session_id TEXT NOT NULL,
161
+ memory_session_id TEXT UNIQUE,
162
+ project TEXT NOT NULL,
163
+ platform_source TEXT NOT NULL DEFAULT 'claude',
164
+ user_prompt TEXT,
165
+ started_at TEXT NOT NULL,
166
+ started_at_epoch INTEGER NOT NULL,
167
+ completed_at TEXT,
168
+ completed_at_epoch INTEGER,
169
+ status TEXT CHECK(status IN ('active', 'completed', 'failed')) NOT NULL DEFAULT 'active'
170
+ );
171
+
172
+ CREATE INDEX IF NOT EXISTS idx_sdk_sessions_claude_id ON sdk_sessions(content_session_id);
173
+ CREATE INDEX IF NOT EXISTS idx_sdk_sessions_sdk_id ON sdk_sessions(memory_session_id);
174
+ CREATE INDEX IF NOT EXISTS idx_sdk_sessions_project ON sdk_sessions(project);
175
+ CREATE INDEX IF NOT EXISTS idx_sdk_sessions_status ON sdk_sessions(status);
176
+ CREATE INDEX IF NOT EXISTS idx_sdk_sessions_started ON sdk_sessions(started_at_epoch DESC);
177
+ CREATE INDEX IF NOT EXISTS idx_sdk_sessions_platform_source ON sdk_sessions(platform_source);
178
+ CREATE UNIQUE INDEX IF NOT EXISTS ux_sdk_sessions_platform_content ON sdk_sessions(platform_source, content_session_id);
179
+
180
+ CREATE TABLE IF NOT EXISTS observations (
181
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
182
+ memory_session_id TEXT NOT NULL,
183
+ project TEXT NOT NULL,
184
+ text TEXT NOT NULL,
185
+ type TEXT NOT NULL,
186
+ created_at TEXT NOT NULL,
187
+ created_at_epoch INTEGER NOT NULL,
188
+ FOREIGN KEY(memory_session_id) REFERENCES sdk_sessions(memory_session_id) ON DELETE CASCADE ON UPDATE CASCADE
189
+ );
190
+
191
+ CREATE INDEX IF NOT EXISTS idx_observations_sdk_session ON observations(memory_session_id);
192
+ CREATE INDEX IF NOT EXISTS idx_observations_project ON observations(project);
193
+ CREATE INDEX IF NOT EXISTS idx_observations_type ON observations(type);
194
+ CREATE INDEX IF NOT EXISTS idx_observations_created ON observations(created_at_epoch DESC);
195
+
196
+ CREATE TABLE IF NOT EXISTS session_summaries (
197
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
198
+ memory_session_id TEXT UNIQUE NOT NULL,
199
+ project TEXT NOT NULL,
200
+ request TEXT,
201
+ investigated TEXT,
202
+ learned TEXT,
203
+ completed TEXT,
204
+ next_steps TEXT,
205
+ files_read TEXT,
206
+ files_edited TEXT,
207
+ notes TEXT,
208
+ created_at TEXT NOT NULL,
209
+ created_at_epoch INTEGER NOT NULL,
210
+ FOREIGN KEY(memory_session_id) REFERENCES sdk_sessions(memory_session_id) ON DELETE CASCADE ON UPDATE CASCADE
211
+ );
212
+
213
+ CREATE INDEX IF NOT EXISTS idx_session_summaries_sdk_session ON session_summaries(memory_session_id);
214
+ CREATE INDEX IF NOT EXISTS idx_session_summaries_project ON session_summaries(project);
215
+ CREATE INDEX IF NOT EXISTS idx_session_summaries_created ON session_summaries(created_at_epoch DESC);
216
+ `),this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(4,new Date().toISOString())}ensureWorkerPortColumn(){this.db.query("PRAGMA table_info(sdk_sessions)").all().some(s=>s.name==="worker_port")||(this.db.run("ALTER TABLE sdk_sessions ADD COLUMN worker_port INTEGER"),l.debug("DB","Added worker_port column to sdk_sessions table")),this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(5,new Date().toISOString())}ensurePromptTrackingColumns(){this.db.query("PRAGMA table_info(sdk_sessions)").all().some(a=>a.name==="prompt_counter")||(this.db.run("ALTER TABLE sdk_sessions ADD COLUMN prompt_counter INTEGER DEFAULT 0"),l.debug("DB","Added prompt_counter column to sdk_sessions table")),this.db.query("PRAGMA table_info(observations)").all().some(a=>a.name==="prompt_number")||(this.db.run("ALTER TABLE observations ADD COLUMN prompt_number INTEGER"),l.debug("DB","Added prompt_number column to observations table")),this.db.query("PRAGMA table_info(session_summaries)").all().some(a=>a.name==="prompt_number")||(this.db.run("ALTER TABLE session_summaries ADD COLUMN prompt_number INTEGER"),l.debug("DB","Added prompt_number column to session_summaries table")),this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(6,new Date().toISOString())}removeSessionSummariesUniqueConstraint(){if(!this.db.query("PRAGMA index_list(session_summaries)").all().some(s=>s.unique===1&&s.origin!=="pk")){this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(7,new Date().toISOString());return}l.debug("DB","Removing UNIQUE constraint from session_summaries.memory_session_id"),this.db.run("BEGIN TRANSACTION"),this.db.run("DROP TABLE IF EXISTS session_summaries_new"),this.db.run(`
217
+ CREATE TABLE session_summaries_new (
218
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
219
+ memory_session_id TEXT NOT NULL,
220
+ project TEXT NOT NULL,
221
+ request TEXT,
222
+ investigated TEXT,
223
+ learned TEXT,
224
+ completed TEXT,
225
+ next_steps TEXT,
226
+ files_read TEXT,
227
+ files_edited TEXT,
228
+ notes TEXT,
229
+ prompt_number INTEGER,
230
+ created_at TEXT NOT NULL,
231
+ created_at_epoch INTEGER NOT NULL,
232
+ FOREIGN KEY(memory_session_id) REFERENCES sdk_sessions(memory_session_id) ON DELETE CASCADE
233
+ )
234
+ `),this.db.run(`
235
+ INSERT INTO session_summaries_new
236
+ SELECT id, memory_session_id, project, request, investigated, learned,
237
+ completed, next_steps, files_read, files_edited, notes,
238
+ prompt_number, created_at, created_at_epoch
239
+ FROM session_summaries
240
+ `),this.db.run("DROP TABLE session_summaries"),this.db.run("ALTER TABLE session_summaries_new RENAME TO session_summaries"),this.db.run(`
241
+ CREATE INDEX idx_session_summaries_sdk_session ON session_summaries(memory_session_id);
242
+ CREATE INDEX idx_session_summaries_project ON session_summaries(project);
243
+ CREATE INDEX idx_session_summaries_created ON session_summaries(created_at_epoch DESC);
244
+ `),this.db.run("COMMIT"),this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(7,new Date().toISOString()),l.debug("DB","Successfully removed UNIQUE constraint from session_summaries.memory_session_id")}addObservationHierarchicalFields(){if(this.db.prepare("SELECT version FROM schema_versions WHERE version = ?").get(8))return;if(this.db.query("PRAGMA table_info(observations)").all().some(n=>n.name==="title")){this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(8,new Date().toISOString());return}l.debug("DB","Adding hierarchical fields to observations table"),this.db.run(`
245
+ ALTER TABLE observations ADD COLUMN title TEXT;
246
+ ALTER TABLE observations ADD COLUMN subtitle TEXT;
247
+ ALTER TABLE observations ADD COLUMN facts TEXT;
248
+ ALTER TABLE observations ADD COLUMN narrative TEXT;
249
+ ALTER TABLE observations ADD COLUMN concepts TEXT;
250
+ ALTER TABLE observations ADD COLUMN files_read TEXT;
251
+ ALTER TABLE observations ADD COLUMN files_modified TEXT;
252
+ `),this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(8,new Date().toISOString()),l.debug("DB","Successfully added hierarchical fields to observations table")}makeObservationsTextNullable(){if(this.db.prepare("SELECT version FROM schema_versions WHERE version = ?").get(9))return;let s=this.db.query("PRAGMA table_info(observations)").all().find(n=>n.name==="text");if(!s||s.notnull===0){this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(9,new Date().toISOString());return}l.debug("DB","Making observations.text nullable"),this.db.run("BEGIN TRANSACTION"),this.db.run("DROP TABLE IF EXISTS observations_new"),this.db.run(`
253
+ CREATE TABLE observations_new (
254
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
255
+ memory_session_id TEXT NOT NULL,
256
+ project TEXT NOT NULL,
257
+ text TEXT,
258
+ type TEXT NOT NULL,
259
+ title TEXT,
260
+ subtitle TEXT,
261
+ facts TEXT,
262
+ narrative TEXT,
263
+ concepts TEXT,
264
+ files_read TEXT,
265
+ files_modified TEXT,
266
+ prompt_number INTEGER,
267
+ created_at TEXT NOT NULL,
268
+ created_at_epoch INTEGER NOT NULL,
269
+ FOREIGN KEY(memory_session_id) REFERENCES sdk_sessions(memory_session_id) ON DELETE CASCADE
270
+ )
271
+ `),this.db.run(`
272
+ INSERT INTO observations_new
273
+ SELECT id, memory_session_id, project, text, type, title, subtitle, facts,
274
+ narrative, concepts, files_read, files_modified, prompt_number,
275
+ created_at, created_at_epoch
276
+ FROM observations
277
+ `),this.db.run("DROP TABLE observations"),this.db.run("ALTER TABLE observations_new RENAME TO observations"),this.db.run(`
278
+ CREATE INDEX idx_observations_sdk_session ON observations(memory_session_id);
279
+ CREATE INDEX idx_observations_project ON observations(project);
280
+ CREATE INDEX idx_observations_type ON observations(type);
281
+ CREATE INDEX idx_observations_created ON observations(created_at_epoch DESC);
282
+ `),this.db.run("COMMIT"),this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(9,new Date().toISOString()),l.debug("DB","Successfully made observations.text nullable")}createUserPromptsTable(){if(this.db.prepare("SELECT version FROM schema_versions WHERE version = ?").get(10))return;if(this.db.query("PRAGMA table_info(user_prompts)").all().length>0){this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(10,new Date().toISOString());return}l.debug("DB","Creating user_prompts table with FTS5 support"),this.db.run("BEGIN TRANSACTION"),this.db.run(`
283
+ CREATE TABLE user_prompts (
284
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
285
+ session_db_id INTEGER,
286
+ content_session_id TEXT NOT NULL,
287
+ prompt_number INTEGER NOT NULL,
288
+ prompt_text TEXT NOT NULL,
289
+ created_at TEXT NOT NULL,
290
+ created_at_epoch INTEGER NOT NULL,
291
+ FOREIGN KEY(session_db_id) REFERENCES sdk_sessions(id) ON DELETE CASCADE
292
+ );
293
+
294
+ CREATE INDEX idx_user_prompts_session ON user_prompts(session_db_id);
295
+ CREATE INDEX idx_user_prompts_claude_session ON user_prompts(content_session_id);
296
+ CREATE INDEX idx_user_prompts_created ON user_prompts(created_at_epoch DESC);
297
+ CREATE INDEX idx_user_prompts_prompt_number ON user_prompts(prompt_number);
298
+ CREATE INDEX idx_user_prompts_lookup ON user_prompts(session_db_id, prompt_number);
299
+ CREATE INDEX idx_user_prompts_content_lookup ON user_prompts(content_session_id, prompt_number);
300
+ `);let s=`
301
+ CREATE VIRTUAL TABLE user_prompts_fts USING fts5(
302
+ prompt_text,
303
+ content='user_prompts',
304
+ content_rowid='id'
305
+ );
306
+ `,n=`
307
+ CREATE TRIGGER user_prompts_ai AFTER INSERT ON user_prompts BEGIN
308
+ INSERT INTO user_prompts_fts(rowid, prompt_text)
309
+ VALUES (new.id, new.prompt_text);
310
+ END;
311
+
312
+ CREATE TRIGGER user_prompts_ad AFTER DELETE ON user_prompts BEGIN
313
+ INSERT INTO user_prompts_fts(user_prompts_fts, rowid, prompt_text)
314
+ VALUES('delete', old.id, old.prompt_text);
315
+ END;
316
+
317
+ CREATE TRIGGER user_prompts_au AFTER UPDATE ON user_prompts BEGIN
318
+ INSERT INTO user_prompts_fts(user_prompts_fts, rowid, prompt_text)
319
+ VALUES('delete', old.id, old.prompt_text);
320
+ INSERT INTO user_prompts_fts(rowid, prompt_text)
321
+ VALUES (new.id, new.prompt_text);
322
+ END;
323
+ `;try{this.db.run(s),this.db.run(n)}catch(o){o instanceof Error?l.warn("DB","FTS5 not available \u2014 user_prompts_fts skipped (search uses ChromaDB)",{},o):l.warn("DB","FTS5 not available \u2014 user_prompts_fts skipped (search uses ChromaDB)",{},new Error(String(o))),this.db.run("COMMIT"),this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(10,new Date().toISOString()),l.debug("DB","Created user_prompts table (without FTS5)");return}this.db.run("COMMIT"),this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(10,new Date().toISOString()),l.debug("DB","Successfully created user_prompts table")}ensureDiscoveryTokensColumn(){if(this.db.prepare("SELECT version FROM schema_versions WHERE version = ?").get(11))return;this.db.query("PRAGMA table_info(observations)").all().some(i=>i.name==="discovery_tokens")||(this.db.run("ALTER TABLE observations ADD COLUMN discovery_tokens INTEGER DEFAULT 0"),l.debug("DB","Added discovery_tokens column to observations table")),this.db.query("PRAGMA table_info(session_summaries)").all().some(i=>i.name==="discovery_tokens")||(this.db.run("ALTER TABLE session_summaries ADD COLUMN discovery_tokens INTEGER DEFAULT 0"),l.debug("DB","Added discovery_tokens column to session_summaries table")),this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(11,new Date().toISOString())}createPendingMessagesTable(){if(this.db.prepare("SELECT version FROM schema_versions WHERE version = ?").get(16))return;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(16,new Date().toISOString());return}l.debug("DB","Creating pending_messages table"),this.db.run(`
324
+ CREATE TABLE pending_messages (
325
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
326
+ session_db_id INTEGER NOT NULL,
327
+ content_session_id TEXT NOT NULL,
328
+ message_type TEXT NOT NULL CHECK(message_type IN ('observation', 'summarize')),
329
+ tool_name TEXT,
330
+ tool_input TEXT,
331
+ tool_response TEXT,
332
+ cwd TEXT,
333
+ last_user_message TEXT,
334
+ last_assistant_message TEXT,
335
+ prompt_number INTEGER,
336
+ status TEXT NOT NULL DEFAULT 'pending' CHECK(status IN ('pending', 'processing')),
337
+ created_at_epoch INTEGER NOT NULL,
338
+ FOREIGN KEY (session_db_id) REFERENCES sdk_sessions(id) ON DELETE CASCADE
339
+ )
340
+ `),this.db.run("CREATE INDEX IF NOT EXISTS idx_pending_messages_session ON pending_messages(session_db_id)"),this.db.run("CREATE INDEX IF NOT EXISTS idx_pending_messages_status ON pending_messages(status)"),this.db.run("CREATE INDEX IF NOT EXISTS idx_pending_messages_claude_session ON pending_messages(content_session_id)"),this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(16,new Date().toISOString()),l.debug("DB","pending_messages table created successfully")}renameSessionIdColumns(){if(this.db.prepare("SELECT version FROM schema_versions WHERE version = ?").get(17))return;l.debug("DB","Checking session ID columns for semantic clarity rename");let t=0,s=(n,o,i)=>{let a=this.db.query(`PRAGMA table_info(${n})`).all(),d=a.some(c=>c.name===o);return a.some(c=>c.name===i)?!1:d?(this.db.run(`ALTER TABLE ${n} RENAME COLUMN ${o} TO ${i}`),l.debug("DB",`Renamed ${n}.${o} to ${i}`),!0):(l.warn("DB",`Column ${o} not found in ${n}, skipping rename`),!1)};s("sdk_sessions","claude_session_id","content_session_id")&&t++,s("sdk_sessions","sdk_session_id","memory_session_id")&&t++,s("pending_messages","claude_session_id","content_session_id")&&t++,s("observations","sdk_session_id","memory_session_id")&&t++,s("session_summaries","sdk_session_id","memory_session_id")&&t++,s("user_prompts","claude_session_id","content_session_id")&&t++,this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(17,new Date().toISOString()),t>0?l.debug("DB",`Successfully renamed ${t} session ID columns`):l.debug("DB","No session ID column renames needed (already up to date)")}repairSessionIdColumnRename(){this.db.prepare("SELECT version FROM schema_versions WHERE version = ?").get(19)||this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(19,new Date().toISOString())}addFailedAtEpochColumn(){if(this.db.prepare("SELECT version FROM schema_versions WHERE version = ?").get(20))return;this.db.query("PRAGMA table_info(pending_messages)").all().some(n=>n.name==="failed_at_epoch")||(this.db.run("ALTER TABLE pending_messages ADD COLUMN failed_at_epoch INTEGER"),l.debug("DB","Added failed_at_epoch column to pending_messages table")),this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(20,new Date().toISOString())}addOnUpdateCascadeToForeignKeys(){if(this.db.prepare("SELECT version FROM schema_versions WHERE version = ?").get(21))return;l.debug("DB","Adding ON UPDATE CASCADE to FK constraints on observations and session_summaries"),this.db.run("PRAGMA foreign_keys = OFF"),this.db.run("BEGIN TRANSACTION"),this.db.run("DROP TRIGGER IF EXISTS observations_ai"),this.db.run("DROP TRIGGER IF EXISTS observations_ad"),this.db.run("DROP TRIGGER IF EXISTS observations_au"),this.db.run("DROP TABLE IF EXISTS observations_new");let t=this.db.query("PRAGMA table_info(observations)").all(),s=t.some(S=>S.name==="metadata"),n=t.some(S=>S.name==="content_hash"),o=s?`,
341
+ metadata TEXT`:"",i=s?", metadata":"",a=n?`,
342
+ content_hash TEXT`:"",d=n?", content_hash":"",u=`
343
+ CREATE TABLE observations_new (
344
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
345
+ memory_session_id TEXT NOT NULL,
346
+ project TEXT NOT NULL,
347
+ text TEXT,
348
+ type TEXT NOT NULL,
349
+ title TEXT,
350
+ subtitle TEXT,
351
+ facts TEXT,
352
+ narrative TEXT,
353
+ concepts TEXT,
354
+ files_read TEXT,
355
+ files_modified TEXT,
356
+ prompt_number INTEGER,
357
+ discovery_tokens INTEGER DEFAULT 0,
358
+ created_at TEXT NOT NULL,
359
+ created_at_epoch INTEGER NOT NULL${o}${a},
360
+ FOREIGN KEY(memory_session_id) REFERENCES sdk_sessions(memory_session_id) ON DELETE CASCADE ON UPDATE CASCADE
361
+ )
362
+ `,c=`
363
+ INSERT INTO observations_new
364
+ SELECT id, memory_session_id, project, text, type, title, subtitle, facts,
365
+ narrative, concepts, files_read, files_modified, prompt_number,
366
+ discovery_tokens, created_at, created_at_epoch${i}${d}
367
+ FROM observations
368
+ `,m=`
369
+ CREATE INDEX idx_observations_sdk_session ON observations(memory_session_id);
370
+ CREATE INDEX idx_observations_project ON observations(project);
371
+ CREATE INDEX idx_observations_type ON observations(type);
372
+ CREATE INDEX idx_observations_created ON observations(created_at_epoch DESC);
373
+ `,p=`
374
+ CREATE TRIGGER IF NOT EXISTS observations_ai AFTER INSERT ON observations BEGIN
375
+ INSERT INTO observations_fts(rowid, title, subtitle, narrative, text, facts, concepts)
376
+ VALUES (new.id, new.title, new.subtitle, new.narrative, new.text, new.facts, new.concepts);
377
+ END;
378
+
379
+ CREATE TRIGGER IF NOT EXISTS observations_ad AFTER DELETE ON observations BEGIN
380
+ INSERT INTO observations_fts(observations_fts, rowid, title, subtitle, narrative, text, facts, concepts)
381
+ VALUES('delete', old.id, old.title, old.subtitle, old.narrative, old.text, old.facts, old.concepts);
382
+ END;
383
+
384
+ CREATE TRIGGER IF NOT EXISTS observations_au AFTER UPDATE ON observations BEGIN
385
+ INSERT INTO observations_fts(observations_fts, rowid, title, subtitle, narrative, text, facts, concepts)
386
+ VALUES('delete', old.id, old.title, old.subtitle, old.narrative, old.text, old.facts, old.concepts);
387
+ INSERT INTO observations_fts(rowid, title, subtitle, narrative, text, facts, concepts)
388
+ VALUES (new.id, new.title, new.subtitle, new.narrative, new.text, new.facts, new.concepts);
389
+ END;
390
+ `;this.db.run("DROP TRIGGER IF EXISTS session_summaries_ai"),this.db.run("DROP TRIGGER IF EXISTS session_summaries_ad"),this.db.run("DROP TRIGGER IF EXISTS session_summaries_au"),this.db.run("DROP TABLE IF EXISTS session_summaries_new");let g=`
391
+ CREATE TABLE session_summaries_new (
392
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
393
+ memory_session_id TEXT NOT NULL,
394
+ project TEXT NOT NULL,
395
+ request TEXT,
396
+ investigated TEXT,
397
+ learned TEXT,
398
+ completed TEXT,
399
+ next_steps TEXT,
400
+ files_read TEXT,
401
+ files_edited TEXT,
402
+ notes TEXT,
403
+ prompt_number INTEGER,
404
+ discovery_tokens INTEGER DEFAULT 0,
405
+ created_at TEXT NOT NULL,
406
+ created_at_epoch INTEGER NOT NULL,
407
+ FOREIGN KEY(memory_session_id) REFERENCES sdk_sessions(memory_session_id) ON DELETE CASCADE ON UPDATE CASCADE
408
+ )
409
+ `,I=`
410
+ INSERT INTO session_summaries_new
411
+ SELECT id, memory_session_id, project, request, investigated, learned,
412
+ completed, next_steps, files_read, files_edited, notes,
413
+ prompt_number, discovery_tokens, created_at, created_at_epoch
414
+ FROM session_summaries
415
+ `,A=`
416
+ CREATE INDEX idx_session_summaries_sdk_session ON session_summaries(memory_session_id);
417
+ CREATE INDEX idx_session_summaries_project ON session_summaries(project);
418
+ CREATE INDEX idx_session_summaries_created ON session_summaries(created_at_epoch DESC);
419
+ `,h=`
420
+ CREATE TRIGGER IF NOT EXISTS session_summaries_ai AFTER INSERT ON session_summaries BEGIN
421
+ INSERT INTO session_summaries_fts(rowid, request, investigated, learned, completed, next_steps, notes)
422
+ VALUES (new.id, new.request, new.investigated, new.learned, new.completed, new.next_steps, new.notes);
423
+ END;
424
+
425
+ CREATE TRIGGER IF NOT EXISTS session_summaries_ad AFTER DELETE ON session_summaries BEGIN
426
+ INSERT INTO session_summaries_fts(session_summaries_fts, rowid, request, investigated, learned, completed, next_steps, notes)
427
+ VALUES('delete', old.id, old.request, old.investigated, old.learned, old.completed, old.next_steps, old.notes);
428
+ END;
429
+
430
+ CREATE TRIGGER IF NOT EXISTS session_summaries_au AFTER UPDATE ON session_summaries BEGIN
431
+ INSERT INTO session_summaries_fts(session_summaries_fts, rowid, request, investigated, learned, completed, next_steps, notes)
432
+ VALUES('delete', old.id, old.request, old.investigated, old.learned, old.completed, old.next_steps, old.notes);
433
+ INSERT INTO session_summaries_fts(rowid, request, investigated, learned, completed, next_steps, notes)
434
+ VALUES (new.id, new.request, new.investigated, new.learned, new.completed, new.next_steps, new.notes);
435
+ END;
436
+ `;try{this.recreateObservationsWithCascade(u,c,m,p),this.recreateSessionSummariesWithCascade(g,I,A,h),this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(21,new Date().toISOString()),this.db.run("COMMIT"),this.db.run("PRAGMA foreign_keys = ON"),l.debug("DB","Successfully added ON UPDATE CASCADE to FK constraints")}catch(S){throw this.db.run("ROLLBACK"),this.db.run("PRAGMA foreign_keys = ON"),S instanceof Error?S:new Error(String(S))}}recreateObservationsWithCascade(e,t,s,n){this.db.run(e),this.db.run(t),this.db.run("DROP TABLE observations"),this.db.run("ALTER TABLE observations_new RENAME TO observations"),this.db.run(s),this.db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='observations_fts'").all().length>0&&this.db.run(n)}recreateSessionSummariesWithCascade(e,t,s,n){this.db.run(e),this.db.run(t),this.db.run("DROP TABLE session_summaries"),this.db.run("ALTER TABLE session_summaries_new RENAME TO session_summaries"),this.db.run(s),this.db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='session_summaries_fts'").all().length>0&&this.db.run(n)}addObservationContentHashColumn(){if(this.db.query("PRAGMA table_info(observations)").all().some(s=>s.name==="content_hash")){this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(22,new Date().toISOString());return}this.db.run("ALTER TABLE observations ADD COLUMN content_hash TEXT"),this.db.run("UPDATE observations SET content_hash = substr(hex(randomblob(8)), 1, 16) WHERE content_hash IS NULL"),this.db.run("CREATE INDEX IF NOT EXISTS idx_observations_content_hash ON observations(content_hash, created_at_epoch)"),l.debug("DB","Added content_hash column to observations table with backfill and index"),this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(22,new Date().toISOString())}addSessionCustomTitleColumn(){if(this.db.prepare("SELECT version FROM schema_versions WHERE version = ?").get(23))return;this.db.query("PRAGMA table_info(sdk_sessions)").all().some(n=>n.name==="custom_title")||(this.db.run("ALTER TABLE sdk_sessions ADD COLUMN custom_title TEXT"),l.debug("DB","Added custom_title column to sdk_sessions table")),this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(23,new Date().toISOString())}addSessionPlatformSourceColumn(){let t=this.db.query("PRAGMA table_info(sdk_sessions)").all().some(i=>i.name==="platform_source"),n=this.db.query("PRAGMA index_list(sdk_sessions)").all().some(i=>i.name==="idx_sdk_sessions_platform_source");this.db.prepare("SELECT version FROM schema_versions WHERE version = ?").get(24)&&t&&n||(t||(this.db.run(`ALTER TABLE sdk_sessions ADD COLUMN platform_source TEXT NOT NULL DEFAULT '${E}'`),l.debug("DB","Added platform_source column to sdk_sessions table")),this.db.run(`
437
+ UPDATE sdk_sessions
438
+ SET platform_source = '${E}'
439
+ WHERE platform_source IS NULL OR platform_source = ''
440
+ `),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())}ensurePendingMessagesToolUseIdColumn(){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}this.db.query("PRAGMA table_info(pending_messages)").all().some(n=>n.name==="tool_use_id")||this.db.run("ALTER TABLE pending_messages ADD COLUMN tool_use_id TEXT"),this.db.run("BEGIN TRANSACTION");try{this.db.run(`
441
+ DELETE FROM pending_messages
442
+ WHERE id IN (
443
+ SELECT id
444
+ FROM (
445
+ SELECT id,
446
+ ROW_NUMBER() OVER (
447
+ PARTITION BY session_db_id, tool_use_id
448
+ ORDER BY CASE status
449
+ WHEN 'processing' THEN 0
450
+ WHEN 'pending' THEN 1
451
+ ELSE 2
452
+ END, id
453
+ ) AS duplicate_rank
454
+ FROM pending_messages
455
+ WHERE tool_use_id IS NOT NULL
456
+ )
457
+ WHERE duplicate_rank > 1
458
+ )
459
+ `),this.db.run(`
460
+ -- tool_use_id is optional for summaries and legacy rows; enforce de-dupe
461
+ -- only for rows that came from a concrete tool-use event.
462
+ CREATE UNIQUE INDEX IF NOT EXISTS ux_pending_session_tool
463
+ ON pending_messages(session_db_id, tool_use_id)
464
+ WHERE tool_use_id IS NOT NULL
465
+ `),this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(28,new Date().toISOString()),this.db.run("COMMIT")}catch(n){throw this.db.run("ROLLBACK"),n}}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(`
466
+ UPDATE observations
467
+ SET content_hash = '__null_migration_' || id || '__'
468
+ WHERE content_hash IS NULL
469
+ `),this.db.run(`
470
+ DELETE FROM observations
471
+ WHERE id IN (
472
+ SELECT id
473
+ FROM (
474
+ SELECT id,
475
+ ROW_NUMBER() OVER (
476
+ PARTITION BY memory_session_id, content_hash
477
+ ORDER BY id
478
+ ) AS duplicate_rank
479
+ FROM observations
480
+ )
481
+ WHERE duplicate_rank > 1
482
+ )
483
+ `),this.db.run(`
484
+ CREATE UNIQUE INDEX IF NOT EXISTS ux_observations_session_hash
485
+ ON observations(memory_session_id, content_hash)
486
+ `),this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(29,new Date().toISOString()),this.db.run("COMMIT")}catch(o){throw this.db.run("ROLLBACK"),o}}addObservationsMetadataColumn(){this.db.query("PRAGMA table_info(observations)").all().some(s=>s.name==="metadata")||(this.db.run("ALTER TABLE observations ADD COLUMN metadata TEXT"),l.debug("DB","Added metadata column to observations table (#2116)")),this.db.prepare("INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)").run(30,new Date().toISOString())}updateMemorySessionId(e,t){this.db.prepare(`
487
+ UPDATE sdk_sessions
488
+ SET memory_session_id = ?
489
+ WHERE id = ?
490
+ `).run(t,e)}markSessionCompleted(e){let t=Date.now(),s=new Date(t).toISOString();this.db.prepare(`
491
+ UPDATE sdk_sessions
492
+ SET status = 'completed', completed_at = ?, completed_at_epoch = ?
493
+ WHERE id = ?
494
+ `).run(s,t,e)}ensureMemorySessionIdRegistered(e,t,s){let n=this.db.prepare(`
495
+ SELECT id, memory_session_id, worker_port FROM sdk_sessions WHERE id = ?
496
+ `).get(e);if(!n)throw new Error(`Session ${e} not found in sdk_sessions`);n.memory_session_id!==t&&(this.db.prepare(`
497
+ UPDATE sdk_sessions SET memory_session_id = ? WHERE id = ?
498
+ `).run(t,e),l.info("DB","Registered memory_session_id before storage (FK fix)",{sessionDbId:e,oldId:n.memory_session_id,newId:t})),typeof s=="number"&&n.worker_port!==s&&this.db.prepare(`
499
+ UPDATE sdk_sessions SET worker_port = ? WHERE id = ?
500
+ `).run(s,e)}getRecentSummaries(e,t=10){return this.db.prepare(`
501
+ SELECT
502
+ request, investigated, learned, completed, next_steps,
503
+ files_read, files_edited, notes, prompt_number, created_at
504
+ FROM session_summaries
505
+ WHERE project = ?
506
+ ORDER BY created_at_epoch DESC
507
+ LIMIT ?
508
+ `).all(e,t)}getRecentSummariesWithSessionInfo(e,t=3){return this.db.prepare(`
509
+ SELECT
510
+ memory_session_id, request, learned, completed, next_steps,
511
+ prompt_number, created_at
512
+ FROM session_summaries
513
+ WHERE project = ?
514
+ ORDER BY created_at_epoch DESC
515
+ LIMIT ?
516
+ `).all(e,t)}getRecentObservations(e,t=20){return this.db.prepare(`
517
+ SELECT type, text, prompt_number, created_at
518
+ FROM observations
519
+ WHERE project = ?
520
+ ORDER BY created_at_epoch DESC
521
+ LIMIT ?
522
+ `).all(e,t)}getAllRecentObservations(e=100){return this.db.prepare(`
523
+ SELECT
524
+ o.id,
525
+ o.type,
526
+ o.title,
527
+ o.subtitle,
528
+ o.text,
529
+ o.project,
530
+ COALESCE(s.platform_source, '${E}') as platform_source,
531
+ o.prompt_number,
532
+ o.created_at,
533
+ o.created_at_epoch
534
+ FROM observations o
535
+ LEFT JOIN sdk_sessions s ON o.memory_session_id = s.memory_session_id
536
+ ORDER BY o.created_at_epoch DESC
537
+ LIMIT ?
538
+ `).all(e)}getAllRecentSummaries(e=50){return this.db.prepare(`
539
+ SELECT
540
+ ss.id,
541
+ ss.request,
542
+ ss.investigated,
543
+ ss.learned,
544
+ ss.completed,
545
+ ss.next_steps,
546
+ ss.files_read,
547
+ ss.files_edited,
548
+ ss.notes,
549
+ ss.project,
550
+ COALESCE(s.platform_source, '${E}') as platform_source,
551
+ ss.prompt_number,
552
+ ss.created_at,
553
+ ss.created_at_epoch
554
+ FROM session_summaries ss
555
+ LEFT JOIN sdk_sessions s ON ss.memory_session_id = s.memory_session_id
556
+ ORDER BY ss.created_at_epoch DESC
557
+ LIMIT ?
558
+ `).all(e)}getAllRecentUserPrompts(e=100){return this.db.prepare(`
559
+ SELECT
560
+ up.id,
561
+ up.content_session_id,
562
+ s.project,
563
+ COALESCE(s.platform_source, '${E}') as platform_source,
564
+ up.prompt_number,
565
+ up.prompt_text,
566
+ up.created_at,
567
+ up.created_at_epoch
568
+ FROM user_prompts up
569
+ LEFT JOIN sdk_sessions s ON up.session_db_id = s.id
570
+ ORDER BY up.created_at_epoch DESC
571
+ LIMIT ?
572
+ `).all(e)}getAllProjects(e){let t=e?L(e):void 0,s=`
573
+ SELECT DISTINCT project
574
+ FROM sdk_sessions
575
+ WHERE project IS NOT NULL AND project != ''
576
+ AND project != ?
577
+ `,n=[Re];return t&&(s+=" AND COALESCE(platform_source, ?) = ?",n.push(E,t)),s+=" ORDER BY project ASC",this.db.prepare(s).all(...n).map(i=>i.project)}getProjectCatalog(){let e=this.db.prepare(`
578
+ SELECT
579
+ COALESCE(platform_source, '${E}') as platform_source,
580
+ project,
581
+ MAX(started_at_epoch) as latest_epoch
582
+ FROM sdk_sessions
583
+ WHERE project IS NOT NULL AND project != ''
584
+ AND project != ?
585
+ GROUP BY COALESCE(platform_source, '${E}'), project
586
+ ORDER BY latest_epoch DESC
587
+ `).all(Re),t=[],s=new Set,n={};for(let i of e){let a=L(i.platform_source);n[a]||(n[a]=[]),n[a].includes(i.project)||n[a].push(i.project),s.has(i.project)||(s.add(i.project),t.push(i.project))}let o=et(Object.keys(n));return{projects:t,sources:o,projectsBySource:Object.fromEntries(o.map(i=>[i,n[i]||[]]))}}getLatestUserPrompt(e,t){let s=this.resolvePromptSessionDbId(e,t),n=s!==null?"up.session_db_id = ?":"up.content_session_id = ?",o=s!==null?s:e;return this.db.prepare(`
588
+ SELECT
589
+ up.*,
590
+ s.memory_session_id,
591
+ s.project,
592
+ COALESCE(s.platform_source, '${E}') as platform_source
593
+ FROM user_prompts up
594
+ JOIN sdk_sessions s ON up.session_db_id = s.id
595
+ WHERE ${n}
596
+ ORDER BY up.created_at_epoch DESC
597
+ LIMIT 1
598
+ `).get(o)}findRecentDuplicateUserPrompt(e,t,s,n){return tt(this.db,e,se(t),s,this.resolvePromptSessionDbId(e,n)??void 0)}getRecentSessionsWithStatus(e,t=3,s){let n=[e],o="";return s&&(o=`AND COALESCE(NULLIF(s.platform_source, ''), '${E}') = ?`,n.push(L(s))),n.push(t),this.db.prepare(`
599
+ SELECT * FROM (
600
+ SELECT
601
+ s.memory_session_id,
602
+ s.status,
603
+ s.started_at,
604
+ s.started_at_epoch,
605
+ s.user_prompt,
606
+ CASE WHEN sum.memory_session_id IS NOT NULL THEN 1 ELSE 0 END as has_summary
607
+ FROM sdk_sessions s
608
+ LEFT JOIN session_summaries sum ON s.memory_session_id = sum.memory_session_id
609
+ WHERE s.project = ? AND s.memory_session_id IS NOT NULL
610
+ ${o}
611
+ GROUP BY s.memory_session_id
612
+ ORDER BY s.started_at_epoch DESC
613
+ LIMIT ?
614
+ )
615
+ ORDER BY started_at_epoch ASC
616
+ `).all(...n)}getObservationsForSession(e,t){let s=[e],n="";return t&&(n=`
617
+ AND EXISTS (
618
+ SELECT 1
619
+ FROM sdk_sessions s
620
+ WHERE s.memory_session_id = observations.memory_session_id
621
+ AND COALESCE(NULLIF(s.platform_source, ''), '${E}') = ?
622
+ )
623
+ `,s.push(L(t))),this.db.prepare(`
624
+ SELECT title, subtitle, type, prompt_number
625
+ FROM observations
626
+ WHERE memory_session_id = ?
627
+ ${n}
628
+ ORDER BY created_at_epoch ASC
629
+ `).all(...s)}getObservationById(e,t){return t?this.db.prepare(`
630
+ SELECT o.*
631
+ FROM observations o
632
+ LEFT JOIN sdk_sessions s ON s.memory_session_id = o.memory_session_id
633
+ WHERE o.id = ?
634
+ AND COALESCE(NULLIF(s.platform_source, ''), '${E}') = ?
635
+ `).get(e,L(t))||null:this.db.prepare(`
636
+ SELECT *
637
+ FROM observations
638
+ WHERE id = ?
639
+ `).get(e)||null}getObservationsByIds(e,t={}){if(e.length===0)return[];let{orderBy:s="date_desc",limit:n,project:o,platformSource:i,type:a,concepts:d,files:u}=t,c=s==="relevance",m=c?"":`ORDER BY o.created_at_epoch ${s==="date_asc"?"ASC":"DESC"}`,p=n&&!c?`LIMIT ${n}`:"",g=e.map(()=>"?").join(","),I=[...e],A=[];if(o&&(A.push("o.project = ?"),I.push(o)),i&&(A.push(`COALESCE(NULLIF(s.platform_source, ''), '${E}') = ?`),I.push(L(i))),a)if(Array.isArray(a)){let R=a.map(()=>"?").join(",");A.push(`o.type IN (${R})`),I.push(...a)}else A.push("o.type = ?"),I.push(a);if(d){let R=Array.isArray(d)?d:[d],b=R.map(()=>"EXISTS (SELECT 1 FROM json_each(o.concepts) WHERE value = ?)");I.push(...R),A.push(`(${b.join(" OR ")})`)}if(u){let R=Array.isArray(u)?u:[u],b=R.map(()=>"(EXISTS (SELECT 1 FROM json_each(o.files_read) WHERE value LIKE ?) OR EXISTS (SELECT 1 FROM json_each(o.files_modified) WHERE value LIKE ?))");R.forEach(C=>{I.push(`%${C}%`,`%${C}%`)}),A.push(`(${b.join(" OR ")})`)}let h=A.length>0?`WHERE o.id IN (${g}) AND ${A.join(" AND ")}`:`WHERE o.id IN (${g})`,y=this.db.prepare(`
640
+ SELECT o.*
641
+ FROM observations o
642
+ LEFT JOIN sdk_sessions s ON s.memory_session_id = o.memory_session_id
643
+ ${h}
644
+ ${m}
645
+ ${p}
646
+ `).all(...I);if(!c)return y;let D=new Map(y.map(R=>[R.id,R])),f=e.map(R=>D.get(R)).filter(R=>!!R);return n?f.slice(0,n):f}getSummaryForSession(e,t){let s=[e],n="";return t&&(n=`
647
+ AND EXISTS (
648
+ SELECT 1
649
+ FROM sdk_sessions sdk
650
+ WHERE sdk.memory_session_id = session_summaries.memory_session_id
651
+ AND COALESCE(NULLIF(sdk.platform_source, ''), '${E}') = ?
652
+ )
653
+ `,s.push(L(t))),this.db.prepare(`
654
+ SELECT
655
+ request, investigated, learned, completed, next_steps,
656
+ files_read, files_edited, notes, prompt_number, created_at,
657
+ created_at_epoch
658
+ FROM session_summaries
659
+ WHERE memory_session_id = ?
660
+ ${n}
661
+ ORDER BY created_at_epoch DESC
662
+ LIMIT 1
663
+ `).get(...s)||null}getFilesForSession(e){let s=this.db.prepare(`
664
+ SELECT files_read, files_modified
665
+ FROM observations
666
+ WHERE memory_session_id = ?
667
+ `).all(e),n=new Set,o=new Set;for(let i of s)Ie(i.files_read).forEach(a=>n.add(a)),Ie(i.files_modified).forEach(a=>o.add(a));return{filesRead:Array.from(n),filesModified:Array.from(o)}}getSessionById(e){return this.db.prepare(`
668
+ SELECT id, content_session_id, memory_session_id, project,
669
+ COALESCE(platform_source, '${E}') as platform_source,
670
+ user_prompt, custom_title, status
671
+ FROM sdk_sessions
672
+ WHERE id = ?
673
+ LIMIT 1
674
+ `).get(e)||null}getSdkSessionsBySessionIds(e){if(e.length===0)return[];let t=e.map(()=>"?").join(",");return this.db.prepare(`
675
+ SELECT id, content_session_id, memory_session_id, project,
676
+ COALESCE(platform_source, '${E}') as platform_source,
677
+ user_prompt, custom_title,
678
+ started_at, started_at_epoch, completed_at, completed_at_epoch, status
679
+ FROM sdk_sessions
680
+ WHERE memory_session_id IN (${t})
681
+ ORDER BY started_at_epoch DESC
682
+ `).all(...e)}getPromptNumberFromUserPrompts(e,t){let s=this.resolvePromptSessionDbId(e,t);return s!==null?this.db.prepare(`
683
+ SELECT COUNT(*) as count FROM user_prompts WHERE session_db_id = ?
684
+ `).get(s).count:this.db.prepare(`
685
+ SELECT COUNT(*) as count FROM user_prompts WHERE content_session_id = ?
686
+ `).get(e).count}createSDKSession(e,t,s,n,o){let i=new Date,a=i.getTime(),d=zs(n,o),u=d.platformSource??E,c=this.rt(se(s)),m=this.db.prepare(`
687
+ SELECT id, platform_source
688
+ FROM sdk_sessions
689
+ WHERE COALESCE(NULLIF(platform_source, ''), ?) = ?
690
+ AND content_session_id = ?
691
+ `).get(E,u,e);if(m)return t&&this.db.prepare(`
692
+ UPDATE sdk_sessions SET project = ?
693
+ WHERE id = ? AND (project IS NULL OR project = '')
694
+ `).run(t,m.id),d.customTitle&&this.db.prepare(`
695
+ UPDATE sdk_sessions SET custom_title = ?
696
+ WHERE id = ? AND custom_title IS NULL
697
+ `).run(d.customTitle,m.id),m.id;let p=this.db.prepare(`
698
+ INSERT INTO sdk_sessions
699
+ (content_session_id, memory_session_id, project, platform_source, user_prompt, custom_title, started_at, started_at_epoch, status)
700
+ VALUES (?, NULL, ?, ?, ?, ?, ?, ?, 'active')
701
+ `).run(e,t,u,c,d.customTitle||null,i.toISOString(),a);return Number(p.lastInsertRowid)}saveUserPrompt(e,t,s,n){let o=new Date,i=o.getTime(),a=this.rt(se(s)),d=this.resolvePromptSessionDbId(e,n);return this.db.prepare(`
702
+ INSERT INTO user_prompts
703
+ (session_db_id, content_session_id, prompt_number, prompt_text, created_at, created_at_epoch)
704
+ VALUES (?, ?, ?, ?, ?, ?)
705
+ `).run(d,e,t,a,o.toISOString(),i).lastInsertRowid}getUserPrompt(e,t,s){let n=this.resolvePromptSessionDbId(e,s);return n!==null?this.db.prepare(`
706
+ SELECT prompt_text
707
+ FROM user_prompts
708
+ WHERE session_db_id = ? AND prompt_number = ?
709
+ LIMIT 1
710
+ `).get(n,t)?.prompt_text??null:this.db.prepare(`
711
+ SELECT prompt_text
712
+ FROM user_prompts
713
+ WHERE content_session_id = ? AND prompt_number = ?
714
+ LIMIT 1
715
+ `).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(),c=this.rt(s.title),m=this.rt(s.subtitle),p=this.rt(s.narrative),g=this.rl(s.facts),I=this.rt(s.metadata??null),A=Ae(e,c??null,p??null),h=De({type:s.type,narrative:p,files_modified:s.files_modified}),S;if(this.mq.reconcile.enabled){let R=this.reconcileBeforeInsert(t,s.type,c??null,p??null);if(R.action==="NOOP"&&R.candidateId){let b=this.db.prepare("SELECT id, created_at_epoch FROM observations WHERE id = ?").get(R.candidateId);if(b)return{id:b.id,createdAtEpoch:b.created_at_epoch}}else R.action==="UPDATE"&&(S=R.candidateId)}let D=this.db.prepare(`
716
+ INSERT INTO observations
717
+ (memory_session_id, project, type, title, subtitle, facts, narrative, concepts,
718
+ files_read, files_modified, prompt_number, discovery_tokens, agent_type, agent_id, content_hash, created_at, created_at_epoch,
719
+ generated_by_model, metadata, importance, valid_from, subject_key)
720
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
721
+ ON CONFLICT(memory_session_id, content_hash) DO NOTHING
722
+ RETURNING id, created_at_epoch
723
+ `).get(e,t,s.type,c,m,JSON.stringify(g),p,JSON.stringify(s.concepts),JSON.stringify(s.files_read),JSON.stringify(s.files_modified),n||null,o,s.agent_type??null,s.agent_id??null,A,u,d,a||null,I,h,d,ve({title:c??null,facts:g,narrative:p??null}));if(D)return S!==void 0&&this.mq.supersession.enabled&&this.supersedeObservation(S,D.id,d),{id:D.id,createdAtEpoch:D.created_at_epoch};let f=this.db.prepare("SELECT id, created_at_epoch FROM observations WHERE memory_session_id = ? AND content_hash = ?").get(e,A);if(!f)throw new Error(`storeObservation: ON CONFLICT without existing row for content_hash=${A}`);return{id:f.id,createdAtEpoch:f.created_at_epoch}}storeSummary(e,t,s,n,o=0,i){let a=i??Date.now(),d=new Date(a).toISOString(),c=this.db.prepare(`
724
+ INSERT INTO session_summaries
725
+ (memory_session_id, project, request, investigated, learned, completed,
726
+ next_steps, notes, prompt_number, discovery_tokens, created_at, created_at_epoch)
727
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
728
+ `).run(e,t,this.rt(s.request),this.rt(s.investigated),this.rt(s.learned),this.rt(s.completed),this.rt(s.next_steps),this.rt(s.notes),n||null,o,d,a);return{id:Number(c.lastInsertRowid),createdAtEpoch:a}}storeObservations(e,t,s,n,o,i=0,a,d){let u=a??Date.now(),c=new Date(u).toISOString();return this.db.transaction(()=>{let p=[],g=this.db.prepare(`
729
+ INSERT INTO observations
730
+ (memory_session_id, project, type, title, subtitle, facts, narrative, concepts,
731
+ files_read, files_modified, prompt_number, discovery_tokens, agent_type, agent_id, content_hash, created_at, created_at_epoch,
732
+ generated_by_model, importance, valid_from, subject_key)
733
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
734
+ ON CONFLICT(memory_session_id, content_hash) DO NOTHING
735
+ RETURNING id
736
+ `),I=this.db.prepare("SELECT id FROM observations WHERE memory_session_id = ? AND content_hash = ?");for(let h of s){let S=this.rt(h.title),y=this.rt(h.subtitle),D=this.rt(h.narrative),f=this.rl(h.facts),R=Ae(e,S??null,D??null),b=g.get(e,t,h.type,S,y,JSON.stringify(f),D,JSON.stringify(h.concepts),JSON.stringify(h.files_read),JSON.stringify(h.files_modified),o||null,i,h.agent_type??null,h.agent_id??null,R,c,u,d||null,De({type:h.type,narrative:D,files_modified:h.files_modified}),u,ve({title:S??null,facts:f,narrative:D??null}));if(b){p.push(b.id);continue}let C=I.get(e,R);if(!C)throw new Error(`storeObservations: ON CONFLICT without existing row for content_hash=${R}`);p.push(C.id)}let A=null;if(n){let S=this.db.prepare(`
737
+ INSERT INTO session_summaries
738
+ (memory_session_id, project, request, investigated, learned, completed,
739
+ next_steps, notes, prompt_number, discovery_tokens, created_at, created_at_epoch)
740
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
741
+ `).run(e,t,this.rt(n.request),this.rt(n.investigated),this.rt(n.learned),this.rt(n.completed),this.rt(n.next_steps),this.rt(n.notes),o||null,i,c,u);A=Number(S.lastInsertRowid)}return{observationIds:p,summaryId:A,createdAtEpoch:u}})()}markObservationsUsed(e,t=Date.now()){if(e.length!==0)try{if(!this.db.query("PRAGMA table_info(observations)").all().some(o=>o.name==="last_used_at"))return;let n=e.map(()=>"?").join(",");this.db.prepare(`UPDATE observations SET last_used_at = ? WHERE id IN (${n})`).run(t,...e)}catch(s){l.debug("DB","markObservationsUsed failed",{count:e.length},s instanceof Error?s:new Error(String(s)))}}evaporateScratch(e){try{let t=this.db.prepare("DELETE FROM observations WHERE memory_session_id = ? AND type = 'scratch'").run(e),s=Number(t.changes??0);return s>0&&l.info("DB","Evaporated scratch observations at SessionEnd",{memorySessionId:e,count:s}),s}catch(t){return l.warn("DB","evaporateScratch failed",{memorySessionId:e},t instanceof Error?t:new Error(String(t))),0}}reconcileBeforeInsert(e,t,s,n){try{let o=Date.now()-7776e6,i=this.db.query("PRAGMA table_info(observations)").all().some(m=>m.name==="valid_to"),a=i?"AND valid_to IS NULL":"",d=this.db.prepare(`
742
+ SELECT id, title, narrative, importance
743
+ FROM observations
744
+ WHERE project = ? AND type = ? AND created_at_epoch >= ? ${a}
745
+ ORDER BY created_at_epoch DESC
746
+ LIMIT 20
747
+ `).all(e,t,o);if(d.length===0)return{action:"ADD"};let u=this.mq.supersession.enabled&&i;return ze({title:s,narrative:n},d,{noopThreshold:this.mq.reconcile.noopThreshold,updateBand:this.mq.reconcile.updateBand,supersessionEnabled:u})}catch(o){return l.warn("DB","reconcileBeforeInsert failed; defaulting to ADD",{project:e,type:t},o instanceof Error?o:new Error(String(o))),{action:"ADD"}}}supersedeObservation(e,t,s){try{this.db.prepare(`
748
+ UPDATE observations
749
+ SET valid_to = ?,
750
+ metadata = json_set(COALESCE(metadata, '{}'), '$.superseded_by', ?)
751
+ WHERE id = ? AND valid_to IS NULL
752
+ `).run(s,t,e)}catch(n){l.warn("DB","supersedeObservation failed",{oldId:e,newId:t},n instanceof Error?n:new Error(String(n)))}}getObservationsAsOf(e,t){return this.db.query("PRAGMA table_info(observations)").all().some(n=>n.name==="valid_from")?this.db.prepare(`
753
+ SELECT * FROM observations
754
+ WHERE project = ?
755
+ AND COALESCE(valid_from, created_at_epoch) <= ?
756
+ AND (valid_to IS NULL OR valid_to > ?)
757
+ `).all(e,t,t):this.db.prepare("SELECT * FROM observations WHERE project = ?").all(e)}deleteObservationsByProject(e,t={}){let s=(e??"").trim();if(s===""||s==="*")throw new Error(`deleteObservationsByProject: refusing unsafe project '${e}'`);let n=this.db.prepare("SELECT count(*) AS c FROM observations WHERE project = ?").get(s).c,o=this.db.prepare("SELECT count(*) AS c FROM session_summaries WHERE project = ?").get(s).c;if(t.dryRun)return{project:s,dryRun:!0,observationsDeleted:n,summariesDeleted:o};this.db.transaction(()=>{this.db.prepare("DELETE FROM observations WHERE project = ?").run(s),this.db.prepare("DELETE FROM session_summaries WHERE project = ?").run(s)})();try{this.db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='observations_fts'").all().length>0&&this.db.run("INSERT INTO observations_fts(observations_fts) VALUES('rebuild')")}catch(a){l.warn("DB","observations_fts rebuild after project delete failed",{project:s},a instanceof Error?a:new Error(String(a)))}return l.info("DB","Deleted observations by project",{project:s,observationsDeleted:n,summariesDeleted:o}),{project:s,dryRun:!1,observationsDeleted:n,summariesDeleted:o}}getSessionSummariesByIds(e,t={}){if(e.length===0)return[];let{orderBy:s="date_desc",limit:n,project:o,platformSource:i}=t,a=s==="relevance",d=a?"":`ORDER BY ss.created_at_epoch ${s==="date_asc"?"ASC":"DESC"}`,u=n&&!a?`LIMIT ${n}`:"",c=e.map(()=>"?").join(","),m=[...e],p=[];o&&(p.push("ss.project = ?"),m.push(o)),i&&(p.push(`COALESCE(NULLIF(s.platform_source, ''), '${E}') = ?`),m.push(L(i)));let g=p.length>0?`AND ${p.join(" AND ")}`:"",A=this.db.prepare(`
758
+ SELECT ss.*
759
+ FROM session_summaries ss
760
+ LEFT JOIN sdk_sessions s ON s.memory_session_id = ss.memory_session_id
761
+ WHERE ss.id IN (${c}) ${g}
762
+ ${d}
763
+ ${u}
764
+ `).all(...m);if(!a)return A;let h=new Map(A.map(y=>[y.id,y])),S=e.map(y=>h.get(y)).filter(y=>!!y);return n?S.slice(0,n):S}getUserPromptsByIds(e,t={}){if(e.length===0)return[];let{orderBy:s="date_desc",limit:n,project:o,platformSource:i}=t,a=s==="relevance",d=a?"":`ORDER BY up.created_at_epoch ${s==="date_asc"?"ASC":"DESC"}`,u=n?`LIMIT ${n}`:"",c=e.map(()=>"?").join(","),m=[...e],p=[];o&&(p.push("s.project = ?"),m.push(o)),i&&(p.push(`COALESCE(NULLIF(s.platform_source, ''), '${E}') = ?`),m.push(L(i)));let g=p.length>0?`AND ${p.join(" AND ")}`:"",A=this.db.prepare(`
765
+ SELECT
766
+ up.*,
767
+ s.project,
768
+ s.memory_session_id,
769
+ COALESCE(NULLIF(s.platform_source, ''), '${E}') as platform_source
770
+ FROM user_prompts up
771
+ JOIN sdk_sessions s ON up.session_db_id = s.id
772
+ WHERE up.id IN (${c}) ${g}
773
+ ${d}
774
+ ${u}
775
+ `).all(...m);if(!a)return A;let h=new Map(A.map(S=>[S.id,S]));return e.map(S=>h.get(S)).filter(S=>!!S)}getTimelineAroundTimestamp(e,t=10,s=10,n,o){return this.getTimelineAroundObservation(null,e,t,s,n,o)}getTimelineAroundObservation(e,t,s=10,n=10,o,i){let a=i?L(i):void 0,d=(f,R)=>{let b=[],C=[];return o&&(b.push(`${f}.project = ?`),C.push(o)),a&&(b.push(`COALESCE(NULLIF(${R}.platform_source, ''), '${E}') = ?`),C.push(a)),{clause:b.length>0?`AND ${b.join(" AND ")}`:"",params:C}},u=d("o","src"),c=d("ss","src"),m=d("s","s"),p,g;if(e!==null){let f=`
776
+ SELECT o.id, o.created_at_epoch
777
+ FROM observations o
778
+ LEFT JOIN sdk_sessions src ON src.memory_session_id = o.memory_session_id
779
+ WHERE o.id <= ? ${u.clause}
780
+ ORDER BY o.id DESC
781
+ LIMIT ?
782
+ `,R=`
783
+ SELECT o.id, o.created_at_epoch
784
+ FROM observations o
785
+ LEFT JOIN sdk_sessions src ON src.memory_session_id = o.memory_session_id
786
+ WHERE o.id >= ? ${u.clause}
787
+ ORDER BY o.id ASC
788
+ LIMIT ?
789
+ `;try{let b=this.db.prepare(f).all(e,...u.params,s+1),C=this.db.prepare(R).all(e,...u.params,n+1);if(b.length===0&&C.length===0)return{observations:[],sessions:[],prompts:[]};p=b.length>0?b[b.length-1].created_at_epoch:t,g=C.length>0?C[C.length-1].created_at_epoch:t}catch(b){return b instanceof Error?l.error("DB","Error getting boundary observations",{project:o},b):l.error("DB","Error getting boundary observations with non-Error",{},new Error(String(b))),{observations:[],sessions:[],prompts:[]}}}else{let f=`
790
+ SELECT o.created_at_epoch
791
+ FROM observations o
792
+ LEFT JOIN sdk_sessions src ON src.memory_session_id = o.memory_session_id
793
+ WHERE o.created_at_epoch <= ? ${u.clause}
794
+ ORDER BY o.created_at_epoch DESC
795
+ LIMIT ?
796
+ `,R=`
797
+ SELECT o.created_at_epoch
798
+ FROM observations o
799
+ LEFT JOIN sdk_sessions src ON src.memory_session_id = o.memory_session_id
800
+ WHERE o.created_at_epoch >= ? ${u.clause}
801
+ ORDER BY o.created_at_epoch ASC
802
+ LIMIT ?
803
+ `;try{let b=this.db.prepare(f).all(t,...u.params,s),C=this.db.prepare(R).all(t,...u.params,n+1);if(b.length===0&&C.length===0)return{observations:[],sessions:[],prompts:[]};p=b.length>0?b[b.length-1].created_at_epoch:t,g=C.length>0?C[C.length-1].created_at_epoch:t}catch(b){return b instanceof Error?l.error("DB","Error getting boundary timestamps",{project:o},b):l.error("DB","Error getting boundary timestamps with non-Error",{},new Error(String(b))),{observations:[],sessions:[],prompts:[]}}}let I=`
804
+ SELECT o.*
805
+ FROM observations o
806
+ LEFT JOIN sdk_sessions src ON src.memory_session_id = o.memory_session_id
807
+ WHERE o.created_at_epoch >= ? AND o.created_at_epoch <= ? ${u.clause}
808
+ ORDER BY o.created_at_epoch ASC
809
+ `,A=`
810
+ SELECT ss.*
811
+ FROM session_summaries ss
812
+ LEFT JOIN sdk_sessions src ON src.memory_session_id = ss.memory_session_id
813
+ WHERE ss.created_at_epoch >= ? AND ss.created_at_epoch <= ? ${c.clause}
814
+ ORDER BY ss.created_at_epoch ASC
815
+ `,h=`
816
+ SELECT up.*, s.project, s.memory_session_id, COALESCE(NULLIF(s.platform_source, ''), '${E}') as platform_source
817
+ FROM user_prompts up
818
+ JOIN sdk_sessions s ON up.session_db_id = s.id
819
+ WHERE up.created_at_epoch >= ? AND up.created_at_epoch <= ? ${m.clause}
820
+ ORDER BY up.created_at_epoch ASC
821
+ `,S=this.db.prepare(I).all(p,g,...u.params),y=this.db.prepare(A).all(p,g,...c.params),D=this.db.prepare(h).all(p,g,...m.params);return{observations:S,sessions:y.map(f=>({id:f.id,memory_session_id:f.memory_session_id,project:f.project,request:f.request,completed:f.completed,next_steps:f.next_steps,created_at:f.created_at,created_at_epoch:f.created_at_epoch})),prompts:D.map(f=>({id:f.id,content_session_id:f.content_session_id,prompt_number:f.prompt_number,prompt_text:f.prompt_text,project:f.project,platform_source:f.platform_source,created_at:f.created_at,created_at_epoch:f.created_at_epoch}))}}getPromptById(e){return this.db.prepare(`
822
+ SELECT
823
+ p.id,
824
+ p.content_session_id,
825
+ p.prompt_number,
826
+ p.prompt_text,
827
+ s.project,
828
+ p.created_at,
829
+ p.created_at_epoch
830
+ FROM user_prompts p
831
+ LEFT JOIN sdk_sessions s ON p.session_db_id = s.id
832
+ WHERE p.id = ?
833
+ LIMIT 1
834
+ `).get(e)||null}getPromptsByIds(e){if(e.length===0)return[];let t=e.map(()=>"?").join(",");return this.db.prepare(`
835
+ SELECT
836
+ p.id,
837
+ p.content_session_id,
838
+ p.prompt_number,
839
+ p.prompt_text,
840
+ s.project,
841
+ p.created_at,
842
+ p.created_at_epoch
843
+ FROM user_prompts p
844
+ LEFT JOIN sdk_sessions s ON p.session_db_id = s.id
845
+ WHERE p.id IN (${t})
846
+ ORDER BY p.created_at_epoch DESC
847
+ `).all(...e)}getOrCreateManualSession(e){let t=`manual-${e}`,s=`manual-content-${e}`;if(this.db.prepare("SELECT memory_session_id FROM sdk_sessions WHERE memory_session_id = ?").get(t))return t;let o=new Date;return this.db.prepare(`
848
+ INSERT INTO sdk_sessions (memory_session_id, content_session_id, project, platform_source, started_at, started_at_epoch, status)
849
+ VALUES (?, ?, ?, ?, ?, ?, 'active')
850
+ `).run(t,s,e,E,o.toISOString(),o.getTime()),l.info("SESSION","Created manual session",{memorySessionId:t,project:e}),t}close(){this.db.close()}importSdkSession(e){let t=L(e.platform_source),s=this.db.prepare(`SELECT id FROM sdk_sessions
851
+ WHERE platform_source = ? AND content_session_id = ?`).get(t,e.content_session_id);return s?{imported:!1,id:s.id}:{imported:!0,id:this.db.prepare(`
852
+ INSERT INTO sdk_sessions (
853
+ content_session_id, memory_session_id, project, platform_source, user_prompt,
854
+ started_at, started_at_epoch, completed_at, completed_at_epoch, status
855
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
856
+ `).run(e.content_session_id,e.memory_session_id,e.project,t,e.user_prompt,e.started_at,e.started_at_epoch,e.completed_at,e.completed_at_epoch,e.status).lastInsertRowid}}importSessionSummary(e){let t=this.db.prepare("SELECT id FROM session_summaries WHERE memory_session_id = ?").get(e.memory_session_id);return t?{imported:!1,id:t.id}:{imported:!0,id:this.db.prepare(`
857
+ INSERT INTO session_summaries (
858
+ memory_session_id, project, request, investigated, learned,
859
+ completed, next_steps, files_read, files_edited, notes,
860
+ prompt_number, discovery_tokens, created_at, created_at_epoch
861
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
862
+ `).run(e.memory_session_id,e.project,e.request,e.investigated,e.learned,e.completed,e.next_steps,e.files_read,e.files_edited,e.notes,e.prompt_number,e.discovery_tokens||0,e.created_at,e.created_at_epoch).lastInsertRowid}}importObservation(e){let t=this.db.prepare(`
863
+ SELECT id FROM observations
864
+ WHERE memory_session_id = ? AND title = ? AND created_at_epoch = ?
865
+ `).get(e.memory_session_id,e.title,e.created_at_epoch);return t?{imported:!1,id:t.id}:{imported:!0,id:this.db.prepare(`
866
+ INSERT INTO observations (
867
+ memory_session_id, project, text, type, title, subtitle,
868
+ facts, narrative, concepts, files_read, files_modified,
869
+ prompt_number, discovery_tokens, agent_type, agent_id,
870
+ created_at, created_at_epoch
871
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
872
+ `).run(e.memory_session_id,e.project,e.text,e.type,e.title,e.subtitle,e.facts,e.narrative,e.concepts,e.files_read,e.files_modified,e.prompt_number,e.discovery_tokens||0,e.agent_type??null,e.agent_id??null,e.created_at,e.created_at_epoch).lastInsertRowid}}rebuildObservationsFTSIndex(){this.db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='observations_fts'").all().length>0&&this.db.run("INSERT INTO observations_fts(observations_fts) VALUES('rebuild')")}importUserPrompt(e){let t=null,s=e.platform_source?L(e.platform_source):void 0;if(typeof e.session_db_id=="number"){let a=this.db.prepare(`
873
+ SELECT id, content_session_id, COALESCE(NULLIF(platform_source, ''), '${E}') as platform_source
874
+ FROM sdk_sessions
875
+ WHERE id = ?
876
+ LIMIT 1
877
+ `).get(e.session_db_id);a&&a.content_session_id===e.content_session_id&&(!s||L(a.platform_source)===s)&&(t=a.id)}t===null&&(t=this.resolvePromptSessionDbId(e.content_session_id,void 0,s));let n=this.db.prepare(`
878
+ SELECT id FROM user_prompts
879
+ WHERE ${t!==null?"session_db_id = ?":"content_session_id = ?"} AND prompt_number = ?
880
+ `).get(t??e.content_session_id,e.prompt_number);return n?{imported:!1,id:n.id}:{imported:!0,id:this.db.prepare(`
881
+ INSERT INTO user_prompts (
882
+ session_db_id, content_session_id, prompt_number, prompt_text,
883
+ created_at, created_at_epoch
884
+ ) VALUES (?, ?, ?, ?, ?, ?)
885
+ `).run(t,e.content_session_id,e.prompt_number,e.prompt_text,e.created_at,e.created_at_epoch).lastInsertRowid}}};var dt=require("os"),ut=G(require("path"),1),ct=require("child_process");var oe=require("fs"),ne=G(require("path"),1);var X={isWorktree:!1,worktreeName:null,parentRepoPath:null,parentProjectName:null};function at(r){let e=ne.default.join(r,".git"),t;try{t=(0,oe.statSync)(e)}catch(c){return c instanceof Error&&c.code!=="ENOENT"&&l.warn("GIT","Unexpected error checking .git",{error:c instanceof Error?c.message:String(c)}),X}if(!t.isFile())return X;let s;try{s=(0,oe.readFileSync)(e,"utf-8").trim()}catch(c){return l.warn("GIT","Failed to read .git file",{error:c instanceof Error?c.message:String(c)}),X}let n=s.match(/^gitdir:\s*(.+)$/);if(!n)return X;let i=n[1].match(/^(.+)[/\\]\.git[/\\]worktrees[/\\]([^/\\]+)$/);if(!i)return X;let a=i[1],d=ne.default.basename(r),u=ne.default.basename(a);return{isWorktree:!0,worktreeName:d,parentRepoPath:a,parentProjectName:u}}function lt(r){return r==="~"||r.startsWith("~/")?r.replace(/^~/,(0,dt.homedir)()):r}function Zs(r){try{return(0,ct.execFileSync)("git",["rev-parse","--show-toplevel"],{cwd:r,encoding:"utf-8",stdio:["ignore","pipe","ignore"]}).trim()||null}catch{return null}}function er(r){if(!r||r.trim()==="")return l.warn("PROJECT_NAME","Empty cwd provided, using fallback",{cwd:r}),"unknown-project";let e=lt(r),s=Zs(e)??e,n=ut.default.basename(s);if(n===""){if(process.platform==="win32"){let i=r.match(/^([A-Z]):\\/i);if(i){let d=`drive-${i[1].toUpperCase()}`;return l.info("PROJECT_NAME","Drive root detected",{cwd:r,projectName:d}),d}}return l.warn("PROJECT_NAME","Root directory detected, using fallback",{cwd:r}),"unknown-project"}return n}function _t(r){let e=er(r);if(!r)return{primary:e,parent:null,isWorktree:!1,allProjects:[e]};let t=lt(r),s=at(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]}}var x=require("fs"),j=require("path"),xe=require("os");var Ue={DEFAULT:3e5,HEALTH_CHECK:3e3,API_REQUEST:3e4,HOOK_READINESS_WAIT:1e4,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};function pt(r){return process.platform==="win32"?Math.round(r*Ue.WINDOWS_MULTIPLIER):r}var O=require("fs");var U=require("path");var mt=require("crypto");var tr=process.platform==="win32";function sr(r){(0,O.existsSync)(r)||(0,O.mkdirSync)(r,{recursive:!0})}function ie(r,e){let t=r;try{if((0,O.lstatSync)(r).isSymbolicLink())try{t=(0,O.realpathSync)(r)}catch{let u=(0,O.readlinkSync)(r);t=(0,U.resolve)((0,U.dirname)(r),u)}}catch(u){let c=u.code;if(c!=="ENOENT"&&c!=="ENOTDIR")throw u}sr((0,U.dirname)(t));let s=(0,U.dirname)(t),n=(0,U.basename)(t),o=(0,U.join)(s,`.${n}.${process.pid}.${(0,mt.randomBytes)(6).toString("hex")}.tmp`),i=Buffer.from(JSON.stringify(e,null,2)+`
886
+ `,"utf-8"),a;try{a=(0,O.statSync)(t).mode&511}catch{}let d;try{d=a!==void 0?(0,O.openSync)(o,"w",a):(0,O.openSync)(o,"w");let u=0;for(;u<i.length;){let c=(0,O.writeSync)(d,i,u,i.length-u);if(c===0)throw new Error(`writeSync stalled at ${u}/${i.length} bytes`);u+=c}if((0,O.fsyncSync)(d),(0,O.closeSync)(d),d=void 0,(0,O.renameSync)(o,t),!tr){let c;try{c=(0,O.openSync)(s,"r"),(0,O.fsyncSync)(c)}catch{}finally{if(c!==void 0)try{(0,O.closeSync)(c)}catch{}}}}catch(u){if(d!==void 0)try{(0,O.closeSync)(d)}catch{}try{(0,O.unlinkSync)(o)}catch{}throw u}}var ae=class{static DEFAULTS={CLAUDE_MEM_MODEL:"claude-haiku-4-5-20251001",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_API_TIMEOUT_MS:String(pt(Ue.API_REQUEST)),CLAUDE_MEM_SKIP_TOOLS:"ListMcpResourcesTool,SlashCommand,Skill,TodoWrite,AskUserQuestion",CLAUDE_MEM_PROVIDER:"claude",CLAUDE_MEM_CLAUDE_AUTH_METHOD:"subscription",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_BASE_URL:"",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,j.join)((0,xe.homedir)(),".keepmind"),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_WELCOME_HINT_ENABLED:"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,j.join)((0,xe.homedir)(),".keepmind","transcript-watch.json"),CLAUDE_MEM_CODEX_TRANSCRIPT_INGESTION:"false",CLAUDE_MEM_MAX_CONCURRENT_AGENTS:"2",CLAUDE_MEM_HOOK_FAIL_LOUD_THRESHOLD:"3",CLAUDE_MEM_EXCLUDED_PROJECTS:"",CLAUDE_MEM_FOLDER_MD_EXCLUDE:"[]",CLAUDE_MEM_FOLDER_MD_SKELETON_DENYLIST:"[]",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_TIER_FAST_MODEL:"haiku",CLAUDE_MEM_TIER_SMART_MODEL:"sonnet",CLAUDE_MEM_CHROMA_ENABLED:"true",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:"",CLAUDE_MEM_QUEUE_ENGINE:"sqlite",CLAUDE_MEM_REDIS_URL:"",CLAUDE_MEM_REDIS_HOST:"127.0.0.1",CLAUDE_MEM_REDIS_PORT:"6379",CLAUDE_MEM_REDIS_MODE:"external",CLAUDE_MEM_QUEUE_REDIS_PREFIX:`claude_mem_${process.env.CLAUDE_MEM_WORKER_PORT??String(37700+(process.getuid?.()??77)%100)}`,CLAUDE_MEM_AUTH_MODE:"api-key",CLAUDE_MEM_RUNTIME:"worker",CLAUDE_MEM_SERVER_URL:`http://127.0.0.1:${process.env.CLAUDE_MEM_SERVER_PORT??String(37877+(process.getuid?.()??77)%100)}`,CLAUDE_MEM_SERVER_API_KEY:"",CLAUDE_MEM_SERVER_PROJECT_ID:"",CLAUDE_MEM_SERVER_BETA_URL:`http://127.0.0.1:${process.env.CLAUDE_MEM_SERVER_PORT??String(37877+(process.getuid?.()??77)%100)}`,CLAUDE_MEM_SERVER_BETA_API_KEY:"",CLAUDE_MEM_SERVER_BETA_PROJECT_ID:""};static getAllDefaults(){return{...this.DEFAULTS}}static envOverride(e){let t=e.replace(/^CLAUDE_MEM_/,"KEEPMIND_");return process.env[t]??process.env[e]}static get(e){return this.envOverride(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)){let n=this.envOverride(s);n!==void 0&&(t[s]=n)}return t}static loadFromFile(e,t=!0){try{if(!(0,x.existsSync)(e)){let a=this.getAllDefaults();try{let d=(0,j.dirname)(e);(0,x.existsSync)(d)||(0,x.mkdirSync)(d,{recursive:!0}),ie(e,a),console.warn("[SETTINGS] Created settings file with defaults:",e)}catch(d){console.warn("[SETTINGS] Failed to create settings file, using in-memory defaults:",e,d instanceof Error?d.message:String(d))}return t?this.applyEnvOverrides(a):a}let s=(0,x.readFileSync)(e,"utf-8"),n=JSON.parse(s.replace(/^\uFEFF/,"")),o=n;if(n.env&&typeof n.env=="object"){o=n.env;try{ie(e,o),console.warn("[SETTINGS] Migrated settings file from nested to flat schema:",e)}catch(a){console.warn("[SETTINGS] Failed to auto-migrate settings file:",e,a instanceof Error?a.message:String(a))}}let i={...this.DEFAULTS};for(let a of Object.keys(this.DEFAULTS))o[a]!==void 0&&(i[a]=o[a]);return t?this.applyEnvOverrides(i):i}catch(s){console.warn("[SETTINGS] Failed to load settings, using defaults:",e,s instanceof Error?s.message:String(s));let n=this.getAllDefaults();try{if((0,x.existsSync)(e)){let o=`${e}.corrupt-${Date.now()}`;(0,x.renameSync)(e,o),console.warn("[SETTINGS] Backed up corrupt settings file to:",o)}ie(e,n),console.warn("[SETTINGS] Recovered settings file with defaults:",e)}catch(o){console.warn("[SETTINGS] Failed to recover corrupt settings file:",e,o instanceof Error?o.message:String(o))}return t?this.applyEnvOverrides(n):n}}};var W=require("fs"),de=require("path");var M=class r{static instance=null;activeMode=null;modesDir;constructor(){let e=Ye(),t=[...process.env.CLAUDE_MEM_MODES_DIR?[process.env.CLAUDE_MEM_MODES_DIR]:[],(0,de.join)(e,"modes"),(0,de.join)(e,"..","plugin","modes")],s=t.find(n=>(0,W.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,de.join)(this.modesDir,`${e}.json`);if(!(0,W.existsSync)(t))throw new Error(`Mode file not found: ${t}`);let s=(0,W.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,l.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(d){if(d instanceof Error?l.warn("WORKER",`Mode file not found: ${e}, falling back to 'code'`,{message:d.message}):l.warn("WORKER",`Mode file not found: ${e}, falling back to 'code'`,{error:String(d)}),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(d){d instanceof Error?l.warn("WORKER",`Parent mode '${s}' not found for ${e}, falling back to 'code'`,{message:d.message}):l.warn("WORKER",`Parent mode '${s}' not found for ${e}, falling back to 'code'`,{error:String(d)}),o=this.loadMode("code")}let i;try{i=this.loadModeFile(n),l.debug("SYSTEM",`Loaded override file: ${n} for parent ${s}`)}catch(d){return d instanceof Error?l.warn("WORKER",`Override file '${n}' not found, using parent mode '${s}' only`,{message:d.message}):l.warn("WORKER",`Override file '${n}' not found, using parent mode '${s}' only`,{error:String(d)}),this.activeMode=o,o}if(!i)return l.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,l.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}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}"}};function Et(){let r=P.settings(),e=ae.loadFromFile(r),t=M.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 _={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"},gt=4,we=1;function ue(r){let e=(r.title?.length||0)+(r.subtitle?.length||0)+(r.narrative?.length||0)+JSON.stringify(r.facts||[]).length;return Math.ceil(e/gt)}function ke(r){let e=r.length,t=r.reduce((i,a)=>i+ue(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 rr(r){return M.getInstance().getWorkEmoji(r)}function V(r,e){let t=ue(r),s=r.discovery_tokens||0,n=rr(r.type),o=s>0?`${n} ${s.toLocaleString("en-US")}`:"-";return{readTokens:t,discoveryTokens:s,discoveryDisplay:o,workEmoji:n}}function ce(r){return r.showReadTokens||r.showWorkTokens||r.showSavingsAmount||r.showSavingsPercent}function nr(r){return ue(r)}function or(r,e){if(!Number.isFinite(e)||e<=0)return r;let t=[],s=0;for(let n of r){let o=nr(n);s+o>e||(t.push(n),s+=o)}return t}function Tt(r,e){let t=e.now??Date.now(),s=r.map(i=>({o:i,score:Je(i,{now:t,halfLifeDays:e.halfLifeDays})})).sort((i,a)=>a.score-i.score).map(i=>i.o),n=e.maxRows>0?s.slice(0,e.maxRows):s;return or(n,e.tokenBudget).sort((i,a)=>(a.created_at_epoch??0)-(i.created_at_epoch??0))}var ft=G(require("path"),1),le=require("fs");function bt(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(`
887
+ SELECT
888
+ o.id,
889
+ o.memory_session_id,
890
+ COALESCE(s.platform_source, 'claude') as platform_source,
891
+ o.type,
892
+ o.title,
893
+ o.subtitle,
894
+ o.narrative,
895
+ o.facts,
896
+ o.concepts,
897
+ o.files_read,
898
+ o.files_modified,
899
+ o.discovery_tokens,
900
+ o.created_at,
901
+ o.created_at_epoch,
902
+ o.importance
903
+ FROM observations o
904
+ LEFT JOIN sdk_sessions s ON o.memory_session_id = s.memory_session_id
905
+ WHERE (o.project = ? OR o.merged_into_project = ? OR o.type = 'global')
906
+ AND (o.valid_to IS NULL)
907
+ AND (? IS NULL OR s.platform_source = ?)
908
+ AND (
909
+ o.type = 'global'
910
+ OR (
911
+ type IN (${o})
912
+ AND EXISTS (
913
+ SELECT 1 FROM json_each(o.concepts)
914
+ WHERE value IN (${a})
915
+ )
916
+ )
917
+ )
918
+ ORDER BY o.created_at_epoch DESC
919
+ LIMIT ?
920
+ `).all(e,e,s??null,s??null,...n,...i,t.totalObservationCount)}function St(r,e,t,s){return r.db.prepare(`
921
+ SELECT
922
+ ss.id,
923
+ ss.memory_session_id,
924
+ COALESCE(s.platform_source, 'claude') as platform_source,
925
+ ss.request,
926
+ ss.investigated,
927
+ ss.learned,
928
+ ss.completed,
929
+ ss.next_steps,
930
+ ss.created_at,
931
+ ss.created_at_epoch
932
+ FROM session_summaries ss
933
+ LEFT JOIN sdk_sessions s ON ss.memory_session_id = s.memory_session_id
934
+ WHERE (ss.project = ? OR ss.merged_into_project = ?)
935
+ AND (? IS NULL OR s.platform_source = ?)
936
+ ORDER BY ss.created_at_epoch DESC
937
+ LIMIT ?
938
+ `).all(e,e,s??null,s??null,t.sessionCount+we)}function ht(r,e,t,s){let n=Array.from(t.observationTypes),o=n.map(()=>"?").join(","),i=Array.from(t.observationConcepts),a=i.map(()=>"?").join(","),d=e.map(()=>"?").join(",");return r.db.prepare(`
939
+ SELECT
940
+ o.id,
941
+ o.memory_session_id,
942
+ COALESCE(s.platform_source, 'claude') as platform_source,
943
+ o.type,
944
+ o.title,
945
+ o.subtitle,
946
+ o.narrative,
947
+ o.facts,
948
+ o.concepts,
949
+ o.files_read,
950
+ o.files_modified,
951
+ o.discovery_tokens,
952
+ o.created_at,
953
+ o.created_at_epoch,
954
+ o.project,
955
+ o.importance
956
+ FROM observations o
957
+ LEFT JOIN sdk_sessions s ON o.memory_session_id = s.memory_session_id
958
+ WHERE (o.project IN (${d})
959
+ OR o.merged_into_project IN (${d})
960
+ OR o.type = 'global')
961
+ AND (o.valid_to IS NULL)
962
+ AND (? IS NULL OR s.platform_source = ?)
963
+ AND (
964
+ o.type = 'global'
965
+ OR (
966
+ type IN (${o})
967
+ AND EXISTS (
968
+ SELECT 1 FROM json_each(o.concepts)
969
+ WHERE value IN (${a})
970
+ )
971
+ )
972
+ )
973
+ ORDER BY o.created_at_epoch DESC
974
+ LIMIT ?
975
+ `).all(...e,...e,s??null,s??null,...n,...i,t.totalObservationCount)}function Rt(r,e,t,s){let n=e.map(()=>"?").join(",");return r.db.prepare(`
976
+ SELECT
977
+ ss.id,
978
+ ss.memory_session_id,
979
+ COALESCE(s.platform_source, 'claude') as platform_source,
980
+ ss.request,
981
+ ss.investigated,
982
+ ss.learned,
983
+ ss.completed,
984
+ ss.next_steps,
985
+ ss.created_at,
986
+ ss.created_at_epoch,
987
+ ss.project
988
+ FROM session_summaries ss
989
+ LEFT JOIN sdk_sessions s ON ss.memory_session_id = s.memory_session_id
990
+ WHERE (ss.project IN (${n})
991
+ OR ss.merged_into_project IN (${n}))
992
+ AND (? IS NULL OR s.platform_source = ?)
993
+ ORDER BY ss.created_at_epoch DESC
994
+ LIMIT ?
995
+ `).all(...e,...e,s??null,s??null,t.sessionCount+we)}function ir(r){return r.replace(/[/.]/g,"-")}function ar(r){if(!r.includes('"type":"assistant"'))return null;let e=JSON.parse(r);if(e.type==="assistant"&&e.message?.content&&Array.isArray(e.message.content)){let t="";for(let s of e.message.content)s.type==="text"&&(t+=s.text);if(t=t.replace(ot,"").trim(),t)return t}return null}function dr(r){for(let e=r.length-1;e>=0;e--)try{let t=ar(r[e]);if(t)return t}catch(t){t instanceof Error?l.debug("WORKER","Skipping malformed transcript line",{lineIndex:e},t):l.debug("WORKER","Skipping malformed transcript line",{lineIndex:e,error:String(t)});continue}return""}function ur(r){try{if(!(0,le.existsSync)(r))return{assistantMessage:""};let e=(0,le.readFileSync)(r,"utf-8").trim();if(!e)return{assistantMessage:""};let t=e.split(`
996
+ `).filter(n=>n.trim());return{assistantMessage:dr(t)}}catch(e){return e instanceof Error?l.failure("WORKER","Failed to extract prior messages from transcript",{transcriptPath:r},e):l.warn("WORKER","Failed to extract prior messages from transcript",{transcriptPath:r,error:String(e)}),{assistantMessage:""}}}function Ot(r,e,t,s){if(!e.showLastMessage||r.length===0)return{assistantMessage:""};let n=r.find(d=>d.memory_session_id!==t);if(!n)return{assistantMessage:""};let o=n.memory_session_id,i=ir(s),a=ft.default.join($,"projects",i,`${o}.jsonl`);return ur(a)}function At(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 It(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 Nt(r,e){return new Set(r.slice(0,e).map(t=>t.id))}function Ct(){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 Lt(r){return[`# [${r}] recent context, ${Ct()}`,""]}function yt(){return[`Legend: \u{1F3AF}session ${M.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 Dt(r,e){let t=[],s=[`${r.totalObservations} obs (${r.totalReadTokens.toLocaleString("en-US")}t read)`,`${r.totalDiscoveryTokens.toLocaleString("en-US")}t work`];return r.totalDiscoveryTokens>0&&(e.showSavingsAmount||e.showSavingsPercent)&&(e.showSavingsPercent?s.push(`${r.savingsPercent}% savings`):e.showSavingsAmount&&s.push(`${r.savings.toLocaleString("en-US")}t saved`)),t.push(`Stats: ${s.join(" | ")}`),t.push(""),t}function vt(r){return[`### ${r}`]}function Mt(r){return r.toLowerCase().replace(" am","a").replace(" pm","p")}function Ut(r,e,t){let s=r.title||"Untitled",n=M.getInstance().getTypeIcon(r.type),o=e?Mt(e):'"';return`${r.id} ${o} ${n} ${s}`}function xt(r,e,t,s){let n=[],o=r.title||"Untitled",i=M.getInstance().getTypeIcon(r.type),a=e?Mt(e):'"',{readTokens:d,discoveryDisplay:u}=V(r,s);n.push(`**${r.id}** ${a} ${i} **${o}**`),t&&n.push(t);let c=[];return s.showReadTokens&&c.push(`~${d}t`),s.showWorkTokens&&c.push(u),c.length>0&&n.push(c.join(" ")),n.push(""),n}function wt(r,e){return[`S${r.id} ${r.request||"Session started"} (${e})`]}function K(r,e){return e?[`**${r}**: ${e}`,""]:[]}function kt(r){return r.assistantMessage?["","---","","**Previously**","",`A: ${r.assistantMessage}`,""]:[]}function Ft(r,e){return["",`Access ${Math.round(r/1e3)}k tokens of past work via get_observations([IDs]) or mem-search skill.`]}function Pt(r){return`# [${r}] recent context, ${Ct()}
997
+
998
+ No previous sessions found.`}function $t(){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 Gt(r){return["",`${_.bright}${_.cyan}[${r}] recent context, ${$t()}${_.reset}`,`${_.gray}${"\u2500".repeat(60)}${_.reset}`,""]}function Ht(){let e=M.getInstance().getActiveMode().observation_types.map(t=>`${t.emoji} ${t.id}`).join(" | ");return[`${_.dim}Legend: session-request | ${e}${_.reset}`,""]}function Bt(){return[`${_.bright}Column Key${_.reset}`,`${_.dim} Read: Tokens to read this observation (cost to learn it now)${_.reset}`,`${_.dim} Work: Tokens spent on work that produced this record ( research, building, deciding)${_.reset}`,""]}function Xt(){return[`${_.dim}Context Index: This semantic index (titles, types, files, tokens) is usually sufficient to understand past work.${_.reset}`,"",`${_.dim}When you need implementation details, rationale, or debugging context:${_.reset}`,`${_.dim} - Fetch by ID: get_observations([IDs]) for observations visible in this index${_.reset}`,`${_.dim} - Search history: Use the mem-search skill for past decisions, bugs, and deeper research${_.reset}`,`${_.dim} - Trust this index over re-reading code for past decisions and learnings${_.reset}`,""]}function jt(r,e){let t=[];if(t.push(`${_.bright}${_.cyan}Context Economics${_.reset}`),t.push(`${_.dim} Loading: ${r.totalObservations} observations (${r.totalReadTokens.toLocaleString()} tokens to read)${_.reset}`),t.push(`${_.dim} Work investment: ${r.totalDiscoveryTokens.toLocaleString()} tokens spent on research, building, and decisions${_.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(`${_.green}${s}${_.reset}`)}return t.push(""),t}function Wt(r){return[`${_.bright}${_.cyan}${r}${_.reset}`,""]}function Vt(r){return[`${_.dim}${r}${_.reset}`]}function Kt(r,e,t,s){let n=r.title||"Untitled",o=M.getInstance().getTypeIcon(r.type),{readTokens:i,discoveryTokens:a,workEmoji:d}=V(r,s),u=t?`${_.dim}${e}${_.reset}`:" ".repeat(e.length),c=s.showReadTokens&&i>0?`${_.dim}(~${i}t)${_.reset}`:"",m=s.showWorkTokens&&a>0?`${_.dim}(${d} ${a.toLocaleString()}t)${_.reset}`:"";return` ${_.dim}#${r.id}${_.reset} ${u} ${o} ${n} ${c} ${m}`}function Yt(r,e,t,s,n){let o=[],i=r.title||"Untitled",a=M.getInstance().getTypeIcon(r.type),{readTokens:d,discoveryTokens:u,workEmoji:c}=V(r,n),m=t?`${_.dim}${e}${_.reset}`:" ".repeat(e.length),p=n.showReadTokens&&d>0?`${_.dim}(~${d}t)${_.reset}`:"",g=n.showWorkTokens&&u>0?`${_.dim}(${c} ${u.toLocaleString()}t)${_.reset}`:"";return o.push(` ${_.dim}#${r.id}${_.reset} ${m} ${a} ${_.bright}${i}${_.reset}`),s&&o.push(` ${_.dim}${s}${_.reset}`),(p||g)&&o.push(` ${p} ${g}`),o.push(""),o}function qt(r,e){let t=`${r.request||"Session started"} (${e})`;return[`${_.yellow}#S${r.id}${_.reset} ${t}`,""]}function Y(r,e,t){return e?[`${t}${r}:${_.reset} ${e}`,""]:[]}function Jt(r){return r.assistantMessage?["","---","",`${_.bright}${_.magenta}Previously${_.reset}`,"",`${_.dim}A: ${r.assistantMessage}${_.reset}`,""]:[]}function Qt(r,e){let t=Math.round(r/1e3);return["",`${_.dim}Access ${t}k tokens of past research & decisions for just ${e.toLocaleString()}t. Use the claude-mem skill to access memories by ID.${_.reset}`]}function zt(r){return`
999
+ ${_.bright}${_.cyan}[${r}] recent context, ${$t()}${_.reset}
1000
+ ${_.gray}${"\u2500".repeat(60)}${_.reset}
1001
+
1002
+ ${_.dim}No previous sessions found for this project yet.${_.reset}
1003
+ `}function Zt(r,e,t,s){let n=[];return s?n.push(...Gt(r)):n.push(...Lt(r)),s?n.push(...Ht()):n.push(...yt()),s&&(n.push(...Bt()),n.push(...Xt())),ce(t)&&(s?n.push(...jt(e,t)):n.push(...Dt(e,t))),n}var me=G(require("path"),1);function Ee(r){if(!r)return[];try{let e=JSON.parse(r);return Array.isArray(e)?e:[]}catch(e){return l.debug("PARSER","Failed to parse JSON array, using empty fallback",{preview:r?.substring(0,50)},e instanceof Error?e:new Error(String(e))),[]}}function Fe(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 ts(r){return new Date(r).toLocaleString("en-US",{month:"short",day:"numeric",year:"numeric"})}function es(r,e){return me.default.isAbsolute(r)?me.default.relative(e,r).split(me.default.sep).join("/"):r}function ss(r,e,t){let s=Ee(r);if(s.length>0)return es(s[0],e);if(t){let n=Ee(t);if(n.length>0)return es(n[0],e)}return"General"}function cr(r){let e=new Map;for(let s of r){let n=s.type==="observation"?s.data.created_at:s.data.displayTime,o=ts(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 rs(r,e){return e.fullObservationField==="narrative"?r.narrative:r.facts?Ee(r.facts).join(`
1004
+ `):null}function lr(r,e,t,s){let n=[];n.push(...vt(r));let o="";for(let i of e)if(i.type==="summary"){let a=i.data,d=Fe(a.displayTime);n.push(...wt(a,d))}else{let a=i.data,d=Pe(a.created_at),c=d!==o?d:"";if(o=d,t.has(a.id)){let p=rs(a,s);n.push(...xt(a,c,p,s))}else n.push(Ut(a,c,s))}return n}function _r(r,e,t,s,n){let o=[];o.push(...Wt(r));let i=null,a="";for(let d of e)if(d.type==="summary"){i=null,a="";let u=d.data,c=Fe(u.displayTime);o.push(...qt(u,c))}else{let u=d.data,c=ss(u.files_modified,n,u.files_read),m=Pe(u.created_at),p=m!==a;a=m;let g=t.has(u.id);if(c!==i&&(o.push(...Vt(c)),i=c),g){let I=rs(u,s);o.push(...Yt(u,m,p,I,s))}else o.push(Kt(u,m,p,s))}return o.push(""),o}function pr(r,e,t,s,n,o){return o?_r(r,e,t,s,n):lr(r,e,t,s)}function ns(r,e,t,s,n){let o=[],i=cr(r);for(let[a,d]of i)o.push(...pr(a,d,e,t,s,n));return o}function os(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 is(r,e){let t=[];return e?(t.push(...Y("Investigated",r.investigated,_.blue)),t.push(...Y("Learned",r.learned,_.yellow)),t.push(...Y("Completed",r.completed,_.green)),t.push(...Y("Next Steps",r.next_steps,_.magenta))):(t.push(...K("Investigated",r.investigated)),t.push(...K("Learned",r.learned)),t.push(...K("Completed",r.completed)),t.push(...K("Next Steps",r.next_steps))),t}function as(r,e){return e?Jt(r):kt(r)}function ds(r,e,t){return!ce(e)||r.totalDiscoveryTokens<=0||r.savings<=0?[]:t?Qt(r.totalDiscoveryTokens,r.totalReadTokens):Ft(r.totalDiscoveryTokens,r.totalReadTokens)}var mr=us.default.join((0,cs.homedir)(),".claude","plugins","marketplaces","keepmind","plugin",".install-version");function Er(){try{return new re}catch(r){if(r instanceof Error&&r.code==="ERR_DLOPEN_FAILED"){try{(0,ls.unlinkSync)(mr)}catch(e){e instanceof Error?l.debug("WORKER","Marker file cleanup failed (may not exist)",{},e):l.debug("WORKER","Marker file cleanup failed (may not exist)",{error:String(e)})}return l.error("WORKER","Native module rebuild needed - restart Claude Code to auto-fix"),null}throw r}}function gr(r,e){return e?zt(r):Pt(r)}function Tr(r,e,t,s,n,o,i){let a=[],d=ke(e);a.push(...Zt(r,d,s,i));let u=t.slice(0,s.sessionCount),c=At(u,t),m=It(e,c),p=Nt(e,s.fullObservationCount);a.push(...ns(m,p,s,n,i));let g=t[0],I=e[0];os(s,g,I)&&a.push(...is(g,i));let A=Ot(e,s,o,n);return a.push(...as(A,i)),a.push(...ds(d,s,i)),a.join(`
1005
+ `).trimEnd()}var fr=new Set(["bugfix","discovery","decision","refactor"]);function br(r,e,t){let s=ke(r),n={bugfix:0,discovery:0,decision:0,refactor:0,other:0},o=new Set,i=Number.POSITIVE_INFINITY;for(let d of r){let u=fr.has(d.type)?d.type:"other";n[u]++,d.memory_session_id&&o.add(d.memory_session_id),d.created_at_epoch&&d.created_at_epoch<i&&(i=d.created_at_epoch)}let a=Number.isFinite(i)?Math.max(0,Math.floor((Date.now()-i)/864e5)):0;return{observation_count:r.length,session_count:o.size,timeline_depth_days:a,has_session_summary:e.length>0,obs_type_bugfix:n.bugfix,obs_type_discovery:n.discovery,obs_type_decision:n.decision,obs_type_refactor:n.refactor,obs_type_other:n.other,tokens_injected:s.totalReadTokens,tokens_saved_vs_naive:s.savings,search_strategy:t?"full":"timeline"}}async function $e(r,e=!1){let t=Et(),s=ee(),n=r?.cwd??process.cwd(),o=_t(n),i=r?.projects?.length?r.projects:o.allProjects,a=i[i.length-1]??o.primary,d=s.importance.enabled&&!r?.full,u=t.totalObservationCount;d&&(t.totalObservationCount=Math.max(u,u*Math.max(1,s.injection.candidateMultiplier))),r?.full&&(t.totalObservationCount=999999,t.sessionCount=999999);let c=Er();if(!c)return{text:"",stats:null};try{let m=r?.platformSource?L(r.platformSource):void 0,p=i.length>1?ht(c,i,t,m):bt(c,a,t,m),g=d?Tt(p,{tokenBudget:s.injection.tokenBudget,halfLifeDays:s.importance.halfLifeDays,maxRows:u}):p,I=i.length>1?Rt(c,i,t,m):St(c,a,t,m);return s.expiry.enabled&&g.length>0&&c.markObservationsUsed(g.map(h=>h.id)),g.length===0&&I.length===0?{text:gr(a,e),stats:null}:{text:Tr(a,g,I,t,n,r?.session_id,e),stats:br(g,I,!!r?.full)}}finally{c.close()}}async function _s(r,e=!1){return(await $e(r,e)).text}0&&(module.exports={generateContext,generateContextWithStats});