@membank/core 0.12.0 → 0.13.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.
@@ -0,0 +1 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./global-scope-CgOQm1jp.cjs`);exports.GLOBAL_PROJECT_ID=e.t,exports.GLOBAL_PROJECT_NAME=e.n,exports.GLOBAL_SCOPE_HASH=e.r;
@@ -0,0 +1,2 @@
1
+ import { n as GLOBAL_PROJECT_NAME, r as GLOBAL_SCOPE_HASH, t as GLOBAL_PROJECT_ID } from "./global-scope-Bv4l3n3S.cjs";
2
+ export { GLOBAL_PROJECT_ID, GLOBAL_PROJECT_NAME, GLOBAL_SCOPE_HASH };
@@ -0,0 +1,2 @@
1
+ import { n as GLOBAL_PROJECT_NAME, r as GLOBAL_SCOPE_HASH, t as GLOBAL_PROJECT_ID } from "./global-scope-lgsTOiAt.mjs";
2
+ export { GLOBAL_PROJECT_ID, GLOBAL_PROJECT_NAME, GLOBAL_SCOPE_HASH };
@@ -0,0 +1 @@
1
+ import{n as e,r as t,t as n}from"./global-scope-B463kRq-.mjs";export{n as GLOBAL_PROJECT_ID,e as GLOBAL_PROJECT_NAME,t as GLOBAL_SCOPE_HASH};
@@ -0,0 +1,2 @@
1
+ const e=`00000000-0000-0000-0000-000000000000`,t=`0000000000000000`,n=`global`;export{n,t as r,e as t};
2
+ //# sourceMappingURL=global-scope-B463kRq-.mjs.map
@@ -0,0 +1,7 @@
1
+ //#region src/project/domain/global-scope.d.ts
2
+ declare const GLOBAL_PROJECT_ID: "00000000-0000-0000-0000-000000000000";
3
+ declare const GLOBAL_SCOPE_HASH: "0000000000000000";
4
+ declare const GLOBAL_PROJECT_NAME: "global";
5
+ //#endregion
6
+ export { GLOBAL_PROJECT_NAME as n, GLOBAL_SCOPE_HASH as r, GLOBAL_PROJECT_ID as t };
7
+ //# sourceMappingURL=global-scope-Bv4l3n3S.d.cts.map
@@ -0,0 +1 @@
1
+ Object.defineProperty(exports,`n`,{enumerable:!0,get:function(){return`global`}}),Object.defineProperty(exports,`r`,{enumerable:!0,get:function(){return`0000000000000000`}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return`00000000-0000-0000-0000-000000000000`}});
@@ -0,0 +1,7 @@
1
+ //#region src/project/domain/global-scope.d.ts
2
+ declare const GLOBAL_PROJECT_ID: "00000000-0000-0000-0000-000000000000";
3
+ declare const GLOBAL_SCOPE_HASH: "0000000000000000";
4
+ declare const GLOBAL_PROJECT_NAME: "global";
5
+ //#endregion
6
+ export { GLOBAL_PROJECT_NAME as n, GLOBAL_SCOPE_HASH as r, GLOBAL_PROJECT_ID as t };
7
+ //# sourceMappingURL=global-scope-lgsTOiAt.d.mts.map
package/dist/index.cjs CHANGED
@@ -1,5 +1,5 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let c=require(`node:crypto`),l=require(`zod`),u=require(`node:fs`),d=require(`node:os`),f=require(`node:path`),p=require(`better-sqlite3`);p=s(p,1);let m=require(`sqlite-vec`);m=s(m,1);let ee=require(`node:events`),h=require(`@huggingface/transformers`),g=require(`@anthropic-ai/claude-agent-sdk`),te=require(`node:fs/promises`),ne=require(`node:child_process`),re=require(`node:util`);function ie(e,t){return t.list(e)}const _=[`memory.created`,`memory.updated`,`memory.deleted`,`memory.flagged`,`memory.queried`],v=l.z.enum(_);function y(e,t){let n=new Date,r=n.toISOString();t.insert({id:(0,c.randomUUID)(),projectHash:e.projectHash,eventType:e.eventType,memoryId:e.memoryId??null,payload:e.payload??{},createdAt:r});let i=new Date(n);i.setDate(i.getDate()-30),t.prune(i.toISOString())}function ae(e){return{id:e.id,projectHash:e.project_hash,eventType:v.parse(e.event_type),memoryId:e.memory_id,payload:JSON.parse(e.payload),createdAt:e.created_at}}var b=class{#e;#t=0;#n;#r;constructor(e){this.#e=e,this.#n=e.db.prepare(`INSERT INTO activity_events (id, project_hash, event_type, memory_id, payload, created_at)
2
- VALUES (?, ?, ?, ?, ?, ?)`),this.#r=e.db.prepare(`DELETE FROM activity_events WHERE created_at < ?`)}insert(e){this.#n.run(e.id,e.projectHash,e.eventType,e.memoryId,JSON.stringify(e.payload),e.createdAt)}list(e){let t=[],n=[];e.scope!==void 0&&(t.push(`project_hash = ?`),n.push(e.scope)),e.type!==void 0&&(t.push(`event_type = ?`),n.push(e.type)),e.since!==void 0&&(t.push(`created_at >= ?`),n.push(e.since));let r=t.length>0?`WHERE ${t.join(` AND `)}`:``,i=e.limit===void 0?``:`LIMIT ?`;return e.limit!==void 0&&n.push(e.limit),this.#e.db.prepare(`SELECT * FROM activity_events ${r} ORDER BY created_at DESC ${i}`).all(...n).map(ae)}prune(e){let t=Date.now();t-this.#t<6e4||(this.#r.run(e),this.#t=t)}};function oe(e){return new b(e)}function se(e){let t=new b(e);return{logEvent:e=>y(e,t)}}const x={logEvent(){}};function ce(){let e=(0,f.join)((0,d.homedir)(),`.membank`,`config.json`);try{let t=(0,u.readFileSync)(e,`utf8`);return JSON.parse(t)}catch{return null}}function le(){return ce()?.synthesis?.enabled===!0}const S=[`correction`,`preference`,`decision`,`learning`,`fact`],C=l.z.enum(S),w=l.z.array(l.z.string()),T=l.z.object({id:l.z.string(),name:l.z.string(),scopeHash:l.z.string(),createdAt:l.z.string(),updatedAt:l.z.string()}),E=l.z.enum([`similarity_dedup`]),D=l.z.object({id:l.z.string(),memoryId:l.z.string(),conflictingMemoryId:l.z.string().nullable(),similarity:l.z.number(),conflictContentSnapshot:l.z.string(),reason:E,createdAt:l.z.string(),resolvedAt:l.z.string().nullable()}),O=l.z.object({id:l.z.string(),memory_id:l.z.string(),conflicting_memory_id:l.z.string().nullable(),similarity:l.z.number(),conflict_content_snapshot:l.z.string(),reason:E,created_at:l.z.string(),resolved_at:l.z.string().nullable()}),k=l.z.object({id:l.z.string(),content:l.z.string(),type:C,tags:l.z.array(l.z.string()),projects:l.z.array(T),sourceHarness:l.z.string().nullable(),accessCount:l.z.number().int().nonnegative(),pinned:l.z.boolean(),reviewEvents:l.z.array(D),createdAt:l.z.string(),updatedAt:l.z.string()}),A=l.z.object({query:l.z.string().min(1),type:C.optional(),projectHash:l.z.string().optional(),limit:l.z.number().int().positive().optional(),includePinned:l.z.boolean().optional()}),ue=l.z.object({content:l.z.string().min(1),type:C,tags:l.z.array(l.z.string()).optional(),projectScope:l.z.object({hash:l.z.string(),name:l.z.string()}).optional(),sourceHarness:l.z.string().optional()}),j=l.z.object({content:l.z.string().min(1).optional(),tags:l.z.array(l.z.string()).optional(),type:C.optional()}),M=l.z.object({id:l.z.string(),scope:l.z.string(),content:l.z.string(),sourceMemoryHash:l.z.string(),synthesizedAt:l.z.string(),expiresAt:l.z.string(),inFlightSince:l.z.string().nullable(),createdAt:l.z.string(),updatedAt:l.z.string()}),de=l.z.object({stats:l.z.record(C,l.z.number()),pinnedGlobal:l.z.array(k),pinnedProject:l.z.array(k),synthesis:l.z.string().optional()}),N=l.z.object({id:l.z.string(),content:l.z.string(),type:l.z.string(),tags:l.z.string(),source:l.z.string().nullable(),access_count:l.z.number(),pinned:l.z.number(),created_at:l.z.string(),updated_at:l.z.string()}),P=l.z.object({id:l.z.string(),name:l.z.string(),scope_hash:l.z.string(),created_at:l.z.string(),updated_at:l.z.string()});function F(e,t,n=[]){return{id:e.id,content:e.content,type:C.parse(e.type),tags:w.parse(JSON.parse(e.tags)),projects:t,sourceHarness:e.source,accessCount:e.access_count,pinned:e.pinned!==0,reviewEvents:n,createdAt:e.created_at,updatedAt:e.updated_at}}function I(e){let t=O.parse(e);return{id:t.id,memoryId:t.memory_id,conflictingMemoryId:t.conflicting_memory_id,similarity:t.similarity,conflictContentSnapshot:t.conflict_content_snapshot,reason:t.reason,createdAt:t.created_at,resolvedAt:t.resolved_at}}function L(e){return{id:e.id,name:e.name,scopeHash:e.scope_hash,createdAt:e.created_at,updatedAt:e.updated_at}}var R=class extends Error{constructor(e,t){super(e,t),this.name=`MembankError`}},z=class extends R{constructor(e,t){super(e,t),this.name=`DatabaseError`}};const fe=(0,f.join)((0,d.homedir)(),`.membank`,`memory.db`),pe=[[1,`
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));const c=require(`./global-scope-CgOQm1jp.cjs`);let l=require(`node:crypto`),u=require(`zod`),d=require(`node:fs`),f=require(`node:os`),p=require(`node:path`),m=require(`better-sqlite3`);m=s(m,1);let h=require(`sqlite-vec`);h=s(h,1);let g=require(`node:events`),_=require(`@huggingface/transformers`),v=require(`@anthropic-ai/claude-agent-sdk`),ee=require(`node:fs/promises`),te=require(`node:child_process`),ne=require(`node:util`);function re(e,t){return t.list(e)}const y=[`memory.created`,`memory.updated`,`memory.deleted`,`memory.flagged`,`memory.queried`],b=u.z.enum(y);function x(e,t){let n=new Date,r=n.toISOString();t.insert({id:(0,l.randomUUID)(),projectHash:e.projectHash,eventType:e.eventType,memoryId:e.memoryId??null,payload:e.payload??{},createdAt:r});let i=new Date(n);i.setDate(i.getDate()-30),t.prune(i.toISOString())}function ie(e){return{id:e.id,projectHash:e.project_hash,eventType:b.parse(e.event_type),memoryId:e.memory_id,payload:JSON.parse(e.payload),createdAt:e.created_at}}var S=class{#e;#t=0;#n;#r;constructor(e){this.#e=e,this.#n=e.db.prepare(`INSERT INTO activity_events (id, project_hash, event_type, memory_id, payload, created_at)
2
+ VALUES (?, ?, ?, ?, ?, ?)`),this.#r=e.db.prepare(`DELETE FROM activity_events WHERE created_at < ?`)}insert(e){this.#n.run(e.id,e.projectHash,e.eventType,e.memoryId,JSON.stringify(e.payload),e.createdAt)}list(e){let t=[],n=[];e.scope!==void 0&&(t.push(`project_hash = ?`),n.push(e.scope)),e.type!==void 0&&(t.push(`event_type = ?`),n.push(e.type)),e.since!==void 0&&(t.push(`created_at >= ?`),n.push(e.since));let r=t.length>0?`WHERE ${t.join(` AND `)}`:``,i=e.limit===void 0?``:`LIMIT ?`;return e.limit!==void 0&&n.push(e.limit),this.#e.db.prepare(`SELECT * FROM activity_events ${r} ORDER BY created_at DESC ${i}`).all(...n).map(ie)}prune(e){let t=Date.now();t-this.#t<6e4||(this.#r.run(e),this.#t=t)}};function ae(e){return new S(e)}function oe(e){let t=new S(e);return{logEvent:e=>x(e,t)}}const C={logEvent(){}};function se(){let e=(0,p.join)((0,f.homedir)(),`.membank`,`config.json`);try{let t=(0,d.readFileSync)(e,`utf8`);return JSON.parse(t)}catch{return null}}function ce(){return se()?.synthesis?.enabled===!0}const w=[`correction`,`preference`,`decision`,`learning`,`fact`],T=u.z.enum(w),E=u.z.array(u.z.string()),D=u.z.object({id:u.z.string(),name:u.z.string(),scopeHash:u.z.string(),createdAt:u.z.string(),updatedAt:u.z.string()}),O=u.z.enum([`similarity_dedup`]),k=u.z.object({id:u.z.string(),memoryId:u.z.string(),conflictingMemoryId:u.z.string().nullable(),similarity:u.z.number(),conflictContentSnapshot:u.z.string(),reason:O,createdAt:u.z.string(),resolvedAt:u.z.string().nullable()}),A=u.z.object({id:u.z.string(),memory_id:u.z.string(),conflicting_memory_id:u.z.string().nullable(),similarity:u.z.number(),conflict_content_snapshot:u.z.string(),reason:O,created_at:u.z.string(),resolved_at:u.z.string().nullable()}),j=u.z.object({id:u.z.string(),content:u.z.string(),type:T,tags:u.z.array(u.z.string()),projects:u.z.array(D),sourceHarness:u.z.string().nullable(),accessCount:u.z.number().int().nonnegative(),pinned:u.z.boolean(),reviewEvents:u.z.array(k),createdAt:u.z.string(),updatedAt:u.z.string()}),M=u.z.object({query:u.z.string().min(1),type:T.optional(),projectHash:u.z.string().optional(),limit:u.z.number().int().positive().optional(),includePinned:u.z.boolean().optional()}),N=u.z.object({content:u.z.string().min(1),type:T,tags:u.z.array(u.z.string()).optional(),projectScope:u.z.object({hash:u.z.string(),name:u.z.string()}).optional(),sourceHarness:u.z.string().optional()}),P=u.z.object({content:u.z.string().min(1).optional(),tags:u.z.array(u.z.string()).optional(),type:T.optional()}),F=u.z.object({id:u.z.string(),scope:u.z.string(),content:u.z.string(),sourceMemoryHash:u.z.string(),synthesizedAt:u.z.string(),expiresAt:u.z.string(),inFlightSince:u.z.string().nullable(),createdAt:u.z.string(),updatedAt:u.z.string()}),le=u.z.object({stats:u.z.record(T,u.z.number()),pinnedGlobal:u.z.array(j),pinnedProject:u.z.array(j),synthesis:u.z.string().optional()}),I=u.z.object({id:u.z.string(),content:u.z.string(),type:u.z.string(),tags:u.z.string(),source:u.z.string().nullable(),access_count:u.z.number(),pinned:u.z.number(),created_at:u.z.string(),updated_at:u.z.string()}),L=u.z.object({id:u.z.string(),name:u.z.string(),scope_hash:u.z.string(),created_at:u.z.string(),updated_at:u.z.string()});function R(e,t,n=[]){return{id:e.id,content:e.content,type:T.parse(e.type),tags:E.parse(JSON.parse(e.tags)),projects:t,sourceHarness:e.source,accessCount:e.access_count,pinned:e.pinned!==0,reviewEvents:n,createdAt:e.created_at,updatedAt:e.updated_at}}function z(e){let t=A.parse(e);return{id:t.id,memoryId:t.memory_id,conflictingMemoryId:t.conflicting_memory_id,similarity:t.similarity,conflictContentSnapshot:t.conflict_content_snapshot,reason:t.reason,createdAt:t.created_at,resolvedAt:t.resolved_at}}function B(e){return{id:e.id,name:e.name,scopeHash:e.scope_hash,createdAt:e.created_at,updatedAt:e.updated_at}}var V=class extends Error{constructor(e,t){super(e,t),this.name=`MembankError`}},H=class extends V{constructor(e,t){super(e,t),this.name=`DatabaseError`}};const ue=(0,p.join)((0,f.homedir)(),`.membank`,`memory.db`),de=[[1,`
3
3
  CREATE TABLE IF NOT EXISTS memories (
4
4
  id TEXT PRIMARY KEY,
5
5
  content TEXT NOT NULL,
@@ -227,14 +227,41 @@ DROP TABLE activity_events_old;
227
227
 
228
228
  CREATE INDEX idx_activity_project_created ON activity_events(project_hash, created_at DESC);
229
229
  CREATE INDEX idx_activity_type_created ON activity_events(event_type, created_at DESC);
230
- `]];var me=class e{#e;constructor(e){this.#e=e}static open(t){let n=t??fe;(0,u.mkdirSync)((0,f.dirname)(n),{recursive:!0});let r=new p.default(n);return e.#n(r,m.load)}static openInMemory(){return e.#t(m.load)}static _openInMemoryWithLoader(t){return e.#t(t)}static#t(t){let n=new p.default(`:memory:`);return e.#n(n,t)}static#n(t,n){try{n(t)}catch(e){throw new z(`Failed to load sqlite-vec extension`,{cause:e})}t.pragma(`journal_mode = WAL`),t.pragma(`foreign_keys = ON`);let r=new e(t);return r.#r(),r}#r(){this.#e.exec(`
230
+ `],[11,`
231
+ PRAGMA foreign_keys = OFF;
232
+
233
+ BEGIN;
234
+
235
+ CREATE TABLE memory_review_events_new (
236
+ id TEXT PRIMARY KEY,
237
+ memory_id TEXT NOT NULL REFERENCES memories(id) ON DELETE CASCADE,
238
+ conflicting_memory_id TEXT REFERENCES memories(id) ON DELETE CASCADE,
239
+ similarity REAL NOT NULL,
240
+ conflict_content_snapshot TEXT NOT NULL,
241
+ reason TEXT NOT NULL,
242
+ created_at TEXT NOT NULL,
243
+ resolved_at TEXT
244
+ );
245
+
246
+ INSERT INTO memory_review_events_new SELECT * FROM memory_review_events;
247
+
248
+ DROP TABLE memory_review_events;
249
+ ALTER TABLE memory_review_events_new RENAME TO memory_review_events;
250
+
251
+ CREATE INDEX IF NOT EXISTS idx_review_events_memory_open
252
+ ON memory_review_events(memory_id) WHERE resolved_at IS NULL;
253
+
254
+ COMMIT;
255
+
256
+ PRAGMA foreign_keys = ON;
257
+ `]];var fe=class e{#e;constructor(e){this.#e=e}static open(t){let n=t??ue;(0,d.mkdirSync)((0,p.dirname)(n),{recursive:!0});let r=new m.default(n);return e.#n(r,h.load)}static openInMemory(){return e.#t(h.load)}static _openInMemoryWithLoader(t){return e.#t(t)}static#t(t){let n=new m.default(`:memory:`);return e.#n(n,t)}static#n(t,n){try{n(t)}catch(e){throw new H(`Failed to load sqlite-vec extension`,{cause:e})}t.pragma(`journal_mode = WAL`),t.pragma(`foreign_keys = ON`);let r=new e(t);return r.#r(),r}#r(){this.#e.exec(`
231
258
  CREATE TABLE IF NOT EXISTS meta (
232
259
  key TEXT PRIMARY KEY,
233
260
  value TEXT NOT NULL
234
261
  );
235
- `);let e=this.#e.prepare(`SELECT value FROM meta WHERE key = 'schema_version'`).get(),t=e?Number.parseInt(e.value,10):0;for(let[e,n]of pe)t<e&&(this.#e.exec(n),this.#e.prepare(`INSERT OR REPLACE INTO meta (key, value) VALUES ('schema_version', ?)`).run(String(e)))}get db(){return this.#e}close(){this.#e.close()}};const B=`Xenova/bge-small-en-v1.5`;var V=class extends Error{constructor(e,t){super(e,t),this.name=`ModelDownloadError`}};function he(){return(0,f.join)((0,d.homedir)(),`.membank`,`models`)}function H(e){if(!(0,u.existsSync)(e))return!1;try{return(0,u.readdirSync)(e).length>0}catch{return!1}}var ge=class extends ee.EventEmitter{modelPath;constructor(e){super(),this.modelPath=e??he()}isAlreadyCached(){return H(this.modelPath)}get cachePath(){return this.modelPath}async download(){if(H(this.modelPath))return{skipped:!0};let e=Date.now(),t=0,n=e;try{await(0,h.pipeline)(`feature-extraction`,B,{cache_dir:this.modelPath,progress_callback:e=>{if(e.status!==`progress`||e.total==null||e.loaded==null)return;let r=e.total,i=e.loaded,a=r>0?i/r*100:0,o=Date.now(),s=o-n,c=i-t,l=0;if(s>0&&c>0){let e=c/s;l=(r-i)/e/1e3}t=i,n=o;let u={totalBytes:r,downloadedBytes:i,percentage:a,estimatedSecondsRemaining:l};this.emit(`progress`,u)}})}catch(e){throw new V(`Failed to download model`,{cause:e})}return{skipped:!1}}},_e=class{modelCachePath;onProgress;pipelineInstance=null;constructor(e,t){this.modelCachePath=e??(0,f.join)((0,d.homedir)(),`.membank`,`models`),this.onProgress=t}async getPipeline(){return this.pipelineInstance===null&&(this.pipelineInstance=await(0,h.pipeline)(`feature-extraction`,`Xenova/bge-small-en-v1.5`,{cache_dir:this.modelCachePath,progress_callback:this.onProgress})),this.pipelineInstance}async embed(e){let t=(await(await this.getPipeline())(e,{pooling:`mean`,normalize:!0})).data;return t instanceof Float32Array?t:new Float32Array(t)}};async function ve(e,t){let n=t.now??(()=>new Date);if(!t.repo.tryClaim(e.sessionId,n(),t.config)){let n=t.repo.get(e.sessionId);return{status:`skipped`,reason:n?.status===`completed`&&n.completedAt!==null?`recently_completed`:`in_flight`}}try{let r=await t.transcripts.read(e.transcriptPath);return await t.agent.run({transcript:r,projectHash:e.projectHash,sessionId:e.sessionId}),t.repo.markCompleted(e.sessionId,n()),{status:`completed`}}catch(r){let i=r instanceof Error?r.message:String(r);return t.repo.markFailed(e.sessionId,n(),i),{status:`failed`,error:i}}}const ye=[`You are a memory extractor that runs after a coding session ends. You read the session transcript and CALL save_memory for every durable fact, preference, correction, decision, or learning the user expressed, so that future sessions inherit them.`,``,`Memory types (pick the closest match):`,`- correction: the user told the assistant to stop doing something or to do it differently.`,`- preference: the user stated how they want work done (tools, style, conventions).`,`- decision: the user committed to a choice future work should respect (tech pick, architectural direction, scope cut).`,`- learning: a non-obvious fact about the codebase or tooling that future sessions would otherwise rediscover.`,`- fact: stable info about the user or their project not derivable from the code.`,``,`Bias strongly toward saving. If the user said it in plain language and it would be useful in a future session, save it. Phrasing like 'stop X', 'always Y', 'we use Z', 'don't suggest W', 'we decided', 'from now on' is a clear save signal — even when the assistant in the transcript already acknowledged it, save it so the NEXT session also knows.`,``,`Process:`,`1. Read the supplied transcript end-to-end.`,`2. Identify every distinct durable signal. List them mentally before calling tools.`,`3. Optional: call query_memory with focused search terms to avoid duplicates. If a near-duplicate exists, call update_memory instead of save_memory.`,`4. Call save_memory for each new durable signal. Phrase the content as a standalone instruction or fact — strip session framing ("in this session", "just now"). Good: "Use pnpm, not npm, for all dependency operations." Bad: "User said stop using npm."`,"5. Use `global: true` only when the fact is about the user themselves or applies across every project. Otherwise default to project scope (omit `global`).",``,`Only return without saving when the transcript truly contains no durable signal — pure greetings, time-of-day questions, abandoned tasks. Do not invent facts. If in doubt and the signal is concrete, save it.`].join(`
236
- `);var be=class{#e;constructor(e){this.#e=e}async run(e){let t=(0,g.createSdkMcpServer)({name:`membank-extraction-tools`,version:`1.0.0`,tools:[(0,g.tool)(`query_memory`,`Search memories by semantic similarity to check for existing entries before saving.`,{query:l.z.string().describe(`Search text`),limit:l.z.number().optional().describe(`Maximum results to return`),global:l.z.boolean().optional().describe(`Query global memories when true, otherwise current project scope`)},async({query:t,limit:n,global:r})=>({content:[{type:`text`,text:await this.#e.queryMemory({query:t,limit:n,global:r,projectHash:e.projectHash})}]}),{annotations:{readOnlyHint:!0}}),(0,g.tool)(`save_memory`,`Persist a new memory. The system handles dedup automatically.`,{content:l.z.string().describe(`Memory content — concise, decontextualised`),type:l.z.enum([`correction`,`preference`,`decision`,`learning`,`fact`]).describe(`Memory type`),tags:l.z.array(l.z.string()).optional().describe(`Optional tags`),global:l.z.boolean().optional().describe(`Save as global memory rather than project-scoped`)},async({content:e,type:t,tags:n,global:r})=>({content:[{type:`text`,text:await this.#e.saveMemory({content:e,type:t,tags:n,global:r})}]})),(0,g.tool)(`update_memory`,`Refine an existing memory by id rather than creating a near-duplicate.`,{id:l.z.string().describe(`Memory id`),content:l.z.string().optional(),type:l.z.enum([`correction`,`preference`,`decision`,`learning`,`fact`]).optional(),tags:l.z.array(l.z.string()).optional()},async({id:e,content:t,type:n,tags:r})=>({content:[{type:`text`,text:await this.#e.updateMemory({id:e,content:t,type:n,tags:r})}]}))]}),n=[`Session id: ${e.sessionId}`,``,`Transcript (most recent turns):`,`---`,e.transcript,`---`,``,`Extract durable memories from this transcript following the system instructions.`].join(`
237
- `),r=Object.fromEntries(Object.entries(process.env).filter(e=>e[1]!==void 0)),i=Date.now(),a=(0,g.query)({prompt:n,options:{model:`claude-haiku-4-5-20251001`,systemPrompt:ye,mcpServers:{"membank-extraction-tools":t},allowedTools:[`mcp__membank-extraction-tools__query_memory`,`mcp__membank-extraction-tools__save_memory`,`mcp__membank-extraction-tools__update_memory`],disallowedTools:[`mcp__membank__*`],settingSources:[],permissionMode:`bypassPermissions`,env:r}}),o=process.env.MEMBANK_EXTRACTION_DEBUG===`true`;for await(let e of a)if(o&&process.stderr.write(`[extraction debug] ${JSON.stringify(e).slice(0,600)}\n`),e.type===`result`&&e.subtype!==`success`){let t=`errors`in e&&Array.isArray(e.errors)?`: ${e.errors.join(`; `)}`:``;throw Error(`Extraction agent failed: ${e.subtype}${t}`)}let s=Date.now()-i;process.stderr.write(`membank extraction: session=${e.sessionId} duration=${s}ms\n`)}};function xe(e){return new be(e)}function Se(e,t,n,r){return e===void 0?{kind:`claim`}:e.status===`in_flight`?t.getTime()-e.startedAt.getTime()<n?{kind:`skip`,reason:`in_flight`}:{kind:`claim`}:e.status===`completed`&&e.completedAt!==null&&t.getTime()-e.completedAt.getTime()<r?{kind:`skip`,reason:`recently_completed`}:{kind:`claim`}}function Ce(e){return{sessionId:e.session_id,startedAt:e.started_at,completedAt:e.completed_at,status:e.status,error:e.error}}var we=class{#e;constructor(e){this.#e=e}tryClaim(e,t,n){let r=this.#t(e);if(Se(r===void 0?void 0:{startedAt:new Date(r.started_at),completedAt:r.completed_at===null?null:new Date(r.completed_at),status:r.status},t,n.inFlightTimeoutMs??6e5,n.recentCompletionMs??6e4).kind===`skip`)return!1;let i=t.toISOString();return this.#e.db.prepare(`INSERT INTO extraction_runs (session_id, started_at, completed_at, status, error)
262
+ `);let e=this.#e.prepare(`SELECT value FROM meta WHERE key = 'schema_version'`).get(),t=e?Number.parseInt(e.value,10):0;for(let[e,n]of de)t<e&&(this.#e.exec(n),this.#e.prepare(`INSERT OR REPLACE INTO meta (key, value) VALUES ('schema_version', ?)`).run(String(e)))}get db(){return this.#e}close(){this.#e.close()}};const U=`Xenova/bge-small-en-v1.5`;var W=class extends Error{constructor(e,t){super(e,t),this.name=`ModelDownloadError`}};function pe(){return(0,p.join)((0,f.homedir)(),`.membank`,`models`)}function G(e){if(!(0,d.existsSync)(e))return!1;try{return(0,d.readdirSync)(e).length>0}catch{return!1}}var me=class extends g.EventEmitter{modelPath;constructor(e){super(),this.modelPath=e??pe()}isAlreadyCached(){return G(this.modelPath)}get cachePath(){return this.modelPath}async download(){if(G(this.modelPath))return{skipped:!0};let e=Date.now(),t=0,n=e;try{await(0,_.pipeline)(`feature-extraction`,U,{cache_dir:this.modelPath,progress_callback:e=>{if(e.status!==`progress`||e.total==null||e.loaded==null)return;let r=e.total,i=e.loaded,a=r>0?i/r*100:0,o=Date.now(),s=o-n,c=i-t,l=0;if(s>0&&c>0){let e=c/s;l=(r-i)/e/1e3}t=i,n=o;let u={totalBytes:r,downloadedBytes:i,percentage:a,estimatedSecondsRemaining:l};this.emit(`progress`,u)}})}catch(e){throw new W(`Failed to download model`,{cause:e})}return{skipped:!1}}},he=class{modelCachePath;onProgress;pipelineInstance=null;constructor(e,t){this.modelCachePath=e??(0,p.join)((0,f.homedir)(),`.membank`,`models`),this.onProgress=t}async getPipeline(){return this.pipelineInstance===null&&(this.pipelineInstance=await(0,_.pipeline)(`feature-extraction`,`Xenova/bge-small-en-v1.5`,{cache_dir:this.modelCachePath,progress_callback:this.onProgress})),this.pipelineInstance}async embed(e){let t=(await(await this.getPipeline())(e,{pooling:`mean`,normalize:!0})).data;return t instanceof Float32Array?t:new Float32Array(t)}};async function ge(e,t){let n=t.now??(()=>new Date);if(!t.repo.tryClaim(e.sessionId,n(),t.config)){let n=t.repo.get(e.sessionId);return{status:`skipped`,reason:n?.status===`completed`&&n.completedAt!==null?`recently_completed`:`in_flight`}}try{let r=await t.transcripts.read(e.transcriptPath);return await t.agent.run({transcript:r,projectHash:e.projectHash,sessionId:e.sessionId}),t.repo.markCompleted(e.sessionId,n()),{status:`completed`}}catch(r){let i=r instanceof Error?r.message:String(r);return t.repo.markFailed(e.sessionId,n(),i),{status:`failed`,error:i}}}const _e=[`You are a memory extractor that runs after a coding session ends. You read the session transcript and CALL save_memory for every durable fact, preference, correction, decision, or learning the user expressed, so that future sessions inherit them.`,``,`Memory types (pick the closest match):`,`- correction: the user told the assistant to stop doing something or to do it differently.`,`- preference: the user stated how they want work done (tools, style, conventions).`,`- decision: the user committed to a choice future work should respect (tech pick, architectural direction, scope cut).`,`- learning: a non-obvious fact about the codebase or tooling that future sessions would otherwise rediscover.`,`- fact: stable info about the user or their project not derivable from the code.`,``,`Bias strongly toward saving. If the user said it in plain language and it would be useful in a future session, save it. Phrasing like 'stop X', 'always Y', 'we use Z', 'don't suggest W', 'we decided', 'from now on' is a clear save signal — even when the assistant in the transcript already acknowledged it, save it so the NEXT session also knows.`,``,`Process:`,`1. Read the supplied transcript end-to-end.`,`2. Identify every distinct durable signal. List them mentally before calling tools.`,`3. Optional: call query_memory with focused search terms to avoid duplicates. If a near-duplicate exists, call update_memory instead of save_memory.`,`4. Call save_memory for each new durable signal. Phrase the content as a standalone instruction or fact — strip session framing ("in this session", "just now"). Good: "Use pnpm, not npm, for all dependency operations." Bad: "User said stop using npm."`,"5. Use `global: true` only when the fact is about the user themselves or applies across every project. Otherwise default to project scope (omit `global`).",``,`Only return without saving when the transcript truly contains no durable signal — pure greetings, time-of-day questions, abandoned tasks. Do not invent facts. If in doubt and the signal is concrete, save it.`].join(`
263
+ `);var ve=class{#e;constructor(e){this.#e=e}async run(e){let t=(0,v.createSdkMcpServer)({name:`membank-extraction-tools`,version:`1.0.0`,tools:[(0,v.tool)(`query_memory`,`Search memories by semantic similarity to check for existing entries before saving.`,{query:u.z.string().describe(`Search text`),limit:u.z.number().optional().describe(`Maximum results to return`),global:u.z.boolean().optional().describe(`Query global memories when true, otherwise current project scope`)},async({query:t,limit:n,global:r})=>({content:[{type:`text`,text:await this.#e.queryMemory({query:t,limit:n,global:r,projectHash:e.projectHash})}]}),{annotations:{readOnlyHint:!0}}),(0,v.tool)(`save_memory`,`Persist a new memory. The system handles dedup automatically.`,{content:u.z.string().describe(`Memory content — concise, decontextualised`),type:u.z.enum([`correction`,`preference`,`decision`,`learning`,`fact`]).describe(`Memory type`),tags:u.z.array(u.z.string()).optional().describe(`Optional tags`),global:u.z.boolean().optional().describe(`Save as global memory rather than project-scoped`)},async({content:e,type:t,tags:n,global:r})=>({content:[{type:`text`,text:await this.#e.saveMemory({content:e,type:t,tags:n,global:r})}]})),(0,v.tool)(`update_memory`,`Refine an existing memory by id rather than creating a near-duplicate.`,{id:u.z.string().describe(`Memory id`),content:u.z.string().optional(),type:u.z.enum([`correction`,`preference`,`decision`,`learning`,`fact`]).optional(),tags:u.z.array(u.z.string()).optional()},async({id:e,content:t,type:n,tags:r})=>({content:[{type:`text`,text:await this.#e.updateMemory({id:e,content:t,type:n,tags:r})}]}))]}),n=[`Session id: ${e.sessionId}`,``,`Transcript (most recent turns):`,`---`,e.transcript,`---`,``,`Extract durable memories from this transcript following the system instructions.`].join(`
264
+ `),r=Object.fromEntries(Object.entries(process.env).filter(e=>e[1]!==void 0)),i=Date.now(),a=(0,v.query)({prompt:n,options:{model:`claude-haiku-4-5-20251001`,systemPrompt:_e,mcpServers:{"membank-extraction-tools":t},allowedTools:[`mcp__membank-extraction-tools__query_memory`,`mcp__membank-extraction-tools__save_memory`,`mcp__membank-extraction-tools__update_memory`],disallowedTools:[`mcp__membank__*`],settingSources:[],permissionMode:`bypassPermissions`,env:r}}),o=process.env.MEMBANK_EXTRACTION_DEBUG===`true`;for await(let e of a)if(o&&process.stderr.write(`[extraction debug] ${JSON.stringify(e).slice(0,600)}\n`),e.type===`result`&&e.subtype!==`success`){let t=`errors`in e&&Array.isArray(e.errors)?`: ${e.errors.join(`; `)}`:``;throw Error(`Extraction agent failed: ${e.subtype}${t}`)}let s=Date.now()-i;process.stderr.write(`membank extraction: session=${e.sessionId} duration=${s}ms\n`)}};function ye(e){return new ve(e)}function be(e,t,n,r){return e===void 0?{kind:`claim`}:e.status===`in_flight`?t.getTime()-e.startedAt.getTime()<n?{kind:`skip`,reason:`in_flight`}:{kind:`claim`}:e.status===`completed`&&e.completedAt!==null&&t.getTime()-e.completedAt.getTime()<r?{kind:`skip`,reason:`recently_completed`}:{kind:`claim`}}function xe(e){return{sessionId:e.session_id,startedAt:e.started_at,completedAt:e.completed_at,status:e.status,error:e.error}}var Se=class{#e;constructor(e){this.#e=e}tryClaim(e,t,n){let r=this.#t(e);if(be(r===void 0?void 0:{startedAt:new Date(r.started_at),completedAt:r.completed_at===null?null:new Date(r.completed_at),status:r.status},t,n.inFlightTimeoutMs??6e5,n.recentCompletionMs??6e4).kind===`skip`)return!1;let i=t.toISOString();return this.#e.db.prepare(`INSERT INTO extraction_runs (session_id, started_at, completed_at, status, error)
238
265
  VALUES (?, ?, NULL, 'in_flight', NULL)
239
266
  ON CONFLICT(session_id) DO UPDATE SET
240
267
  started_at = excluded.started_at,
@@ -244,70 +271,84 @@ CREATE INDEX idx_activity_type_created ON activity_events(event_type, created
244
271
  SET status = 'completed', completed_at = ?, error = NULL
245
272
  WHERE session_id = ?`).run(t.toISOString(),e)}markFailed(e,t,n){this.#e.db.prepare(`UPDATE extraction_runs
246
273
  SET status = 'failed', completed_at = ?, error = ?
247
- WHERE session_id = ?`).run(t.toISOString(),n,e)}get(e){let t=this.#t(e);return t===void 0?void 0:Ce(t)}#t(e){return this.#e.db.prepare(`SELECT * FROM extraction_runs WHERE session_id = ?`).get(e)}};function Te(e){return new we(e)}function Ee(e){if(typeof e==`string`)return e;if(!Array.isArray(e))return``;let t=[];for(let n of e){if(typeof n!=`object`||!n)continue;let e=n;e.type===`text`&&typeof e.text==`string`?t.push(e.text):e.type===`tool_use`&&typeof e.name==`string`?t.push(`[tool_use: ${e.name}]`):e.type===`tool_result`&&t.push(`[tool_result]`)}return t.join(`
248
- `)}var De=class{#e;#t;constructor(e={}){this.#e=e.maxTurns??80,this.#t=e.maxChars??6e4}async read(e){let t=(await(0,te.readFile)(e,`utf8`)).split(`
249
- `).filter(e=>e.length>0),n=[];for(let e of t){let t;try{t=JSON.parse(e)}catch{continue}let r=t.message?.role;if(r!==`user`&&r!==`assistant`)continue;let i=Ee(t.message?.content).trim();i.length!==0&&n.push(`${r}: ${i}`)}let r=n.slice(-this.#e).join(`
274
+ WHERE session_id = ?`).run(t.toISOString(),n,e)}get(e){let t=this.#t(e);return t===void 0?void 0:xe(t)}#t(e){return this.#e.db.prepare(`SELECT * FROM extraction_runs WHERE session_id = ?`).get(e)}};function Ce(e){return new Se(e)}function we(e){if(typeof e==`string`)return e;if(!Array.isArray(e))return``;let t=[];for(let n of e){if(typeof n!=`object`||!n)continue;let e=n;e.type===`text`&&typeof e.text==`string`?t.push(e.text):e.type===`tool_use`&&typeof e.name==`string`?t.push(`[tool_use: ${e.name}]`):e.type===`tool_result`&&t.push(`[tool_result]`)}return t.join(`
275
+ `)}var Te=class{#e;#t;constructor(e={}){this.#e=e.maxTurns??80,this.#t=e.maxChars??6e4}async read(e){let t=(await(0,ee.readFile)(e,`utf8`)).split(`
276
+ `).filter(e=>e.length>0),n=[];for(let e of t){let t;try{t=JSON.parse(e)}catch{continue}let r=t.message?.role;if(r!==`user`&&r!==`assistant`)continue;let i=we(t.message?.content).trim();i.length!==0&&n.push(`${r}: ${i}`)}let r=n.slice(-this.#e).join(`
250
277
 
251
- `);return r.length<=this.#t?r:r.slice(r.length-this.#t)}};function Oe(e={}){return new De(e)}const U=`00000000-0000-0000-0000-000000000000`,W=`0000000000000000`,G=`global`;function ke(e,t,n=x){let r=t.findById(e)?.projects[0]?.scopeHash??`0000000000000000`;return t.delete(e),n.logEvent({projectHash:r,eventType:`memory.deleted`,memoryId:e}),Promise.resolve()}function Ae(e,t){t.resolveReviewEvents(e)}function je(e){return e>.92?`overwrite`:e>=.75?`flag`:`none`}async function Me(e,t){let{content:n,type:r,tags:i=[],projectScope:a,sourceHarness:o}=ue.parse(e),{repo:s,embedder:l,activityLogger:u=x}=t,d=a?.hash??`0000000000000000`,f=await l.embed(n),[p]=s.findSimilar(f,r,a?.hash);if(p!==void 0){let e=je(p.similarity);if(e===`overwrite`){let e=s.overwrite(p.id,n,f);return u.logEvent({projectHash:d,eventType:`memory.updated`,memoryId:p.id}),e}if(e===`flag`){let e=s.create({id:(0,c.randomUUID)(),content:n,type:r,tags:i,sourceHarness:o??null,embedding:f,projectScope:a});return s.createReviewEvent({memoryId:p.id,conflictingMemoryId:e.id,similarity:p.similarity,conflictContentSnapshot:n}),u.logEvent({projectHash:d,eventType:`memory.created`,memoryId:e.id}),u.logEvent({projectHash:d,eventType:`memory.flagged`,memoryId:p.id,payload:{conflictingMemoryId:e.id,similarity:p.similarity}}),e}}let m=s.create({id:(0,c.randomUUID)(),content:n,type:r,tags:i,sourceHarness:o??null,embedding:f,projectScope:a});return u.logEvent({projectHash:d,eventType:`memory.created`,memoryId:m.id}),m}async function Ne(e,t,n){let{repo:r,embedder:i,activityLogger:a=x}=n,o=j.parse(t),s=o.content===void 0?void 0:await i.embed(o.content),c=r.update(e,o,s),l=c.projects[0]?.scopeHash??`0000000000000000`;return a.logEvent({projectHash:l,eventType:`memory.updated`,memoryId:e}),c}const K=8e3;function Pe(e){return e>=K}var q=class{#e;#t;constructor(e,t){this.#e=e,this.#t=t}findSimilar(e,t,n){let r=Buffer.from(e.buffer),i;return i=n===void 0?this.#e.db.prepare(`SELECT m.rowid, m.*, (1 - vec_distance_cosine(e.embedding, ?)) AS similarity
278
+ `);return r.length<=this.#t?r:r.slice(r.length-this.#t)}};function Ee(e={}){return new Te(e)}function De(e){let t=new Map;function n(e){t.has(e)||t.set(e,e);let r=t.get(e);if(r!==e){let i=n(r);return t.set(e,i),i}return e}function r(e,r){let i=n(e),a=n(r);i!==a&&t.set(a,i)}for(let{memoryId:t,conflictingMemoryId:n}of e)r(t,n);let i=new Map;for(let e of t.keys()){let t=n(e),r=i.get(t)??[];r.push(e),i.set(t,r)}return Array.from(i.entries()).map(([e,t])=>({clusterId:e,memoryIds:t}))}function K(e,t,n=C){let r=t.findById(e)?.projects[0]?.scopeHash??`0000000000000000`;return t.delete(e),n.logEvent({projectHash:r,eventType:`memory.deleted`,memoryId:e}),Promise.resolve()}async function Oe(e,t,n=C){let r=[];for(let i of e)try{await K(i,t,n),r.push({id:i,status:`ok`})}catch(e){r.push({id:i,status:`error`,error:e instanceof Error?e.message:String(e)})}return r}function q(e){return e>.92?`overwrite`:e>=.75?`flag`:`none`}async function ke(e,t){let{keepId:n,dropIds:r,mergedContent:i}=e,{repo:a,embedder:o,activityLogger:s=C}=t,c=a.findById(n);if(c===void 0)throw Error(`Memory not found: ${n}`);let l=r.map(e=>{let t=a.findById(e);if(t===void 0)throw Error(`Memory not found: ${e}`);return t});for(let e of l)if(e.type!==c.type)throw Error(`Type mismatch: keep memory has type "${c.type}" but drop memory ${e.id} has type "${e.type}"`);let u=[c,...l],d=[...new Set(u.flatMap(e=>e.tags))],f=u.some(e=>e.pinned),p=u.reduce((e,t)=>e+t.accessCount,0),m=await o.embed(i),h=a.overwrite(n,i,m),g=new Set(c.tags);if((d.length!==c.tags.length||d.some(e=>!g.has(e)))&&(h=a.update(n,{tags:d})),f&&!c.pinned&&(h=a.setPin(n,!0)),p>c.accessCount){let e=p-c.accessCount;for(let t=0;t<e;t++)a.incrementAccessCount(n);h=a.findById(n)??h}for(let e of l)a.delete(e.id);let[_]=a.findSimilar(m,c.type,c.projects[0]?.scopeHash);_!==void 0&&_.id!==n&&q(_.similarity)===`flag`&&a.createReviewEvent({memoryId:n,conflictingMemoryId:_.id,similarity:_.similarity,conflictContentSnapshot:i});let v=h.projects[0]?.scopeHash??`0000000000000000`;return s.logEvent({projectHash:v,eventType:`memory.updated`,memoryId:n,payload:{merged:r}}),h=a.findById(n)??h,{kept:h,dropped:r}}function Ae(e,t){t.resolveReviewEvents(e)}function je(e,t){return e.map(e=>{try{return t.findById(e)===void 0?{id:e,status:`error`,error:`Memory not found: ${e}`}:(t.resolveReviewEvents(e),{id:e,status:`ok`})}catch(t){return{id:e,status:`error`,error:t instanceof Error?t.message:String(t)}}})}async function Me(e,t){let{content:n,type:r,tags:i=[],projectScope:a,sourceHarness:o}=N.parse(e),{repo:s,embedder:c,activityLogger:u=C}=t,d=a?.hash??`0000000000000000`,f=await c.embed(n),[p]=s.findSimilar(f,r,a?.hash);if(p!==void 0){let e=q(p.similarity);if(e===`overwrite`){let e=s.overwrite(p.id,n,f);return u.logEvent({projectHash:d,eventType:`memory.updated`,memoryId:p.id}),e}if(e===`flag`){let e=s.create({id:(0,l.randomUUID)(),content:n,type:r,tags:i,sourceHarness:o??null,embedding:f,projectScope:a});return s.createReviewEvent({memoryId:p.id,conflictingMemoryId:e.id,similarity:p.similarity,conflictContentSnapshot:n}),u.logEvent({projectHash:d,eventType:`memory.created`,memoryId:e.id}),u.logEvent({projectHash:d,eventType:`memory.flagged`,memoryId:p.id,payload:{conflictingMemoryId:e.id,similarity:p.similarity}}),e}}let m=s.create({id:(0,l.randomUUID)(),content:n,type:r,tags:i,sourceHarness:o??null,embedding:f,projectScope:a});return u.logEvent({projectHash:d,eventType:`memory.created`,memoryId:m.id}),m}async function Ne(e,t,n){let{repo:r,embedder:i,activityLogger:a=C}=n,o=P.parse(t),s=o.content===void 0?void 0:await i.embed(o.content),c=r.update(e,o,s),l=c.projects[0]?.scopeHash??`0000000000000000`;return a.logEvent({projectHash:l,eventType:`memory.updated`,memoryId:e}),c}const J=8e3;function Pe(e){return e>=J}var Y=class{#e;#t;constructor(e,t){this.#e=e,this.#t=t}findSimilar(e,t,n){let r=Buffer.from(e.buffer),i;return i=n===void 0?this.#e.db.prepare(`SELECT m.rowid, m.*, (1 - vec_distance_cosine(e.embedding, ?)) AS similarity
252
279
  FROM memories m JOIN embeddings e ON e.rowid = m.rowid
253
280
  JOIN memory_projects mp ON mp.memory_id = m.id
254
281
  JOIN projects p ON p.id = mp.project_id
255
282
  WHERE m.type = ? AND p.scope_hash = ?
256
- ORDER BY similarity DESC LIMIT 1`).get(r,t,W):this.#e.db.prepare(`SELECT m.rowid, m.*, (1 - vec_distance_cosine(e.embedding, ?)) AS similarity
283
+ ORDER BY similarity DESC LIMIT 1`).get(r,t,c.r):this.#e.db.prepare(`SELECT m.rowid, m.*, (1 - vec_distance_cosine(e.embedding, ?)) AS similarity
257
284
  FROM memories m JOIN embeddings e ON e.rowid = m.rowid
258
285
  JOIN memory_projects mp ON mp.memory_id = m.id
259
286
  JOIN projects p ON p.id = mp.project_id
260
287
  WHERE m.type = ? AND p.scope_hash = ?
261
288
  ORDER BY similarity DESC LIMIT 1`).get(r,t,n),i===void 0?[]:[{id:i.id,similarity:i.similarity}]}create(e){let{id:t,content:n,type:r,tags:i,sourceHarness:a,embedding:o,projectScope:s}=e,c=new Date().toISOString(),l=Buffer.from(o.buffer);this.#e.db.prepare(`INSERT INTO memories (id, content, type, tags, source, access_count, pinned, created_at, updated_at)
262
- VALUES (?, ?, ?, ?, ?, 0, 0, ?, ?)`).run(t,n,r,JSON.stringify(i),a,c,c),this.#e.db.prepare(`INSERT INTO embeddings (rowid, embedding) SELECT m.rowid, ? FROM memories m WHERE m.id = ?`).run(l,t);let u=s??{hash:`0000000000000000`,name:`global`},d=this.#t.upsertByHash(u.hash,u.name);return this.#t.addAssociation(t,d.id),F(N.parse(this.#e.db.prepare(`SELECT * FROM memories WHERE id = ?`).get(t)),this.#t.getProjectsForMemories([t]).get(t)??[])}overwrite(e,t,n){let r=new Date().toISOString(),i=Buffer.from(n.buffer);this.#e.db.prepare(`UPDATE memories SET content = ?, updated_at = ? WHERE id = ?`).run(t,r,e);let a=this.#e.db.prepare(`SELECT rowid FROM memories WHERE id = ?`).get(e)?.rowid;a!==void 0&&this.#e.db.prepare(`UPDATE embeddings SET embedding = ? WHERE rowid = ?`).run(i,a);let o=N.parse(this.#e.db.prepare(`SELECT * FROM memories WHERE id = ?`).get(e)),s=this.#t.getProjectsForMemories([e]),c=this.#r([e]);return F(o,s.get(e)??[],c.get(e)??[])}findById(e){let t=this.#e.db.prepare(`SELECT * FROM memories WHERE id = ?`).get(e);if(t===void 0)return;let n=this.#t.getProjectsForMemories([e]),r=this.#r([e]);return F(t,n.get(e)??[],r.get(e)??[])}update(e,t,n){let{content:r,tags:i,type:a}=j.parse(t),o=this.#e.db.prepare(`SELECT m.rowid, m.* FROM memories m WHERE m.id = ?`).get(e);if(o===void 0)throw Error(`Memory not found: ${e}`);let s=new Date().toISOString(),c=[`updated_at = ?`],l=[s];if(r!==void 0&&(c.push(`content = ?`),l.push(r)),i!==void 0&&(c.push(`tags = ?`),l.push(JSON.stringify(i))),a!==void 0&&(c.push(`type = ?`),l.push(a)),l.push(e),this.#e.db.prepare(`UPDATE memories SET ${c.join(`, `)} WHERE id = ?`).run(...l),n!==void 0){let e=Buffer.from(n.buffer);this.#e.db.prepare(`UPDATE embeddings SET embedding = ? WHERE rowid = ?`).run(e,o.rowid)}let u=N.parse(this.#e.db.prepare(`SELECT * FROM memories WHERE id = ?`).get(e)),d=this.#t.getProjectsForMemories([e]),f=this.#r([e]);return F(u,d.get(e)??[],f.get(e)??[])}delete(e){let t=this.#e.db.prepare(`SELECT rowid FROM memories WHERE id = ?`).get(e);t!==void 0&&this.#e.db.prepare(`DELETE FROM embeddings WHERE rowid = ?`).run(t.rowid),this.#e.db.prepare(`DELETE FROM memory_projects WHERE memory_id = ?`).run(e),this.#e.db.prepare(`DELETE FROM memories WHERE id = ?`).run(e)}list(e){let t=[],n=[];e?.type!==void 0&&(t.push(`m.type = ?`),n.push(e.type)),e?.pinned===!0&&t.push(`m.pinned = 1`),e?.needsReview===!0&&t.push(`EXISTS (SELECT 1 FROM memory_review_events e WHERE e.memory_id = m.id AND e.resolved_at IS NULL)`),e?.projectId===`global`?(t.push(`EXISTS (SELECT 1 FROM memory_projects mp JOIN projects p ON p.id = mp.project_id WHERE mp.memory_id = m.id AND p.scope_hash = ?)`),n.push(W)):e?.projectId!==void 0&&(t.push(`m.id IN (SELECT memory_id FROM memory_projects WHERE project_id = ?)`),n.push(e.projectId));let r=t.length>0?`WHERE ${t.join(` AND `)}`:``,i=this.#e.db.prepare(`SELECT m.* FROM memories m ${r} ORDER BY m.created_at DESC`).all(...n);if(i.length===0)return[];let a=i.map(e=>e.id),o=this.#t.getProjectsForMemories(a),s=this.#r(a);return i.map(e=>F(e,o.get(e.id)??[],s.get(e.id)??[]))}listPinnedGlobal(){return this.listPinnedForProject(W)}listPinnedForProject(e){return this.#e.db.prepare(`SELECT m.* FROM memories m
289
+ VALUES (?, ?, ?, ?, ?, 0, 0, ?, ?)`).run(t,n,r,JSON.stringify(i),a,c,c),this.#e.db.prepare(`INSERT INTO embeddings (rowid, embedding) SELECT m.rowid, ? FROM memories m WHERE m.id = ?`).run(l,t);let u=s??{hash:`0000000000000000`,name:`global`},d=this.#t.upsertByHash(u.hash,u.name);return this.#t.addAssociation(t,d.id),R(I.parse(this.#e.db.prepare(`SELECT * FROM memories WHERE id = ?`).get(t)),this.#t.getProjectsForMemories([t]).get(t)??[])}overwrite(e,t,n){let r=new Date().toISOString(),i=Buffer.from(n.buffer);this.#e.db.prepare(`UPDATE memories SET content = ?, updated_at = ? WHERE id = ?`).run(t,r,e);let a=this.#e.db.prepare(`SELECT rowid FROM memories WHERE id = ?`).get(e)?.rowid;a!==void 0&&this.#e.db.prepare(`UPDATE embeddings SET embedding = ? WHERE rowid = ?`).run(i,a);let o=I.parse(this.#e.db.prepare(`SELECT * FROM memories WHERE id = ?`).get(e)),s=this.#t.getProjectsForMemories([e]),c=this.#r([e]);return R(o,s.get(e)??[],c.get(e)??[])}findById(e){let t=this.#e.db.prepare(`SELECT * FROM memories WHERE id = ?`).get(e);if(t===void 0)return;let n=this.#t.getProjectsForMemories([e]),r=this.#r([e]);return R(t,n.get(e)??[],r.get(e)??[])}findManyById(e){if(e.length===0)return[];let t=e.map(()=>`?`).join(`, `),n=this.#e.db.prepare(`SELECT * FROM memories WHERE id IN (${t})`).all(...e);if(n.length===0)return[];let r=n.map(e=>e.id),i=this.#t.getProjectsForMemories(r),a=this.#r(r);return n.map(e=>R(e,i.get(e.id)??[],a.get(e.id)??[]))}update(e,t,n){let{content:r,tags:i,type:a}=P.parse(t),o=this.#e.db.prepare(`SELECT m.rowid, m.* FROM memories m WHERE m.id = ?`).get(e);if(o===void 0)throw Error(`Memory not found: ${e}`);let s=new Date().toISOString(),c=[`updated_at = ?`],l=[s];if(r!==void 0&&(c.push(`content = ?`),l.push(r)),i!==void 0&&(c.push(`tags = ?`),l.push(JSON.stringify(i))),a!==void 0&&(c.push(`type = ?`),l.push(a)),l.push(e),this.#e.db.prepare(`UPDATE memories SET ${c.join(`, `)} WHERE id = ?`).run(...l),n!==void 0){let e=Buffer.from(n.buffer);this.#e.db.prepare(`UPDATE embeddings SET embedding = ? WHERE rowid = ?`).run(e,o.rowid)}let u=I.parse(this.#e.db.prepare(`SELECT * FROM memories WHERE id = ?`).get(e)),d=this.#t.getProjectsForMemories([e]),f=this.#r([e]);return R(u,d.get(e)??[],f.get(e)??[])}delete(e){let t=this.#e.db.prepare(`SELECT rowid FROM memories WHERE id = ?`).get(e);t!==void 0&&this.#e.db.prepare(`DELETE FROM embeddings WHERE rowid = ?`).run(t.rowid),this.#e.db.prepare(`DELETE FROM memory_projects WHERE memory_id = ?`).run(e),this.#e.db.prepare(`DELETE FROM memories WHERE id = ?`).run(e)}list(e){let t=[],n=[];e?.type!==void 0&&(t.push(`m.type = ?`),n.push(e.type)),e?.pinned===!0&&t.push(`m.pinned = 1`),e?.needsReview===!0&&t.push(`EXISTS (SELECT 1 FROM memory_review_events e WHERE e.memory_id = m.id AND e.resolved_at IS NULL)`),e?.projectId===`global`?(t.push(`EXISTS (SELECT 1 FROM memory_projects mp JOIN projects p ON p.id = mp.project_id WHERE mp.memory_id = m.id AND p.scope_hash = ?)`),n.push(c.r)):e?.projectId!==void 0&&(t.push(`m.id IN (SELECT memory_id FROM memory_projects WHERE project_id = ?)`),n.push(e.projectId));let r=t.length>0?`WHERE ${t.join(` AND `)}`:``,i=this.#e.db.prepare(`SELECT m.* FROM memories m ${r} ORDER BY m.created_at DESC`).all(...n);if(i.length===0)return[];let a=i.map(e=>e.id),o=this.#t.getProjectsForMemories(a),s=this.#r(a);return i.map(e=>R(e,o.get(e.id)??[],s.get(e.id)??[]))}listPinnedGlobal(){return this.listPinnedForProject(c.r)}listPinnedForProject(e){return this.#e.db.prepare(`SELECT m.* FROM memories m
263
290
  JOIN memory_projects mp ON mp.memory_id = m.id
264
291
  JOIN projects p ON p.id = mp.project_id
265
- WHERE p.scope_hash = ? AND m.pinned = 1`).all(e).map(e=>F(e,[]))}listFlagged(e){let t;if(t=e===void 0?this.#e.db.prepare(`SELECT * FROM memories
266
- WHERE EXISTS (
267
- SELECT 1 FROM memory_review_events e
268
- WHERE e.memory_id = memories.id AND e.resolved_at IS NULL
269
- )
270
- ORDER BY created_at DESC`).all():this.#e.db.prepare(`SELECT * FROM memories
271
- WHERE EXISTS (
292
+ WHERE p.scope_hash = ? AND m.pinned = 1`).all(e).map(e=>R(e,[]))}listFlagged(e){let{projectHash:t,limit:n,minSimilarity:r,maxSimilarity:i}=e??{},a=[`e.resolved_at IS NULL`];r!==void 0&&a.push(`e.similarity >= ?`),i!==void 0&&a.push(`e.similarity <= ?`);let o=[r,i].filter(e=>e!==void 0),s=`EXISTS (
272
293
  SELECT 1 FROM memory_review_events e
273
- WHERE e.memory_id = memories.id AND e.resolved_at IS NULL
274
- )
294
+ WHERE e.memory_id = memories.id AND ${a.join(` AND `)}
295
+ )`,c=n===void 0?``:`LIMIT ?`,l=n===void 0?[]:[n],u;if(u=t===void 0?this.#e.db.prepare(`SELECT * FROM memories
296
+ WHERE ${s}
297
+ ORDER BY created_at DESC ${c}`).all(...o,...l):this.#e.db.prepare(`SELECT * FROM memories
298
+ WHERE ${s}
275
299
  AND ${this.#n()}
276
- ORDER BY created_at DESC`).all(e),t.length===0)return[];let n=t.map(e=>e.id),r=this.#t.getProjectsForMemories(n),i=this.#r(n,{unresolvedOnly:!0});return t.map(e=>F(e,r.get(e.id)??[],i.get(e.id)??[]))}listReviewEvents(e,t){let n=t?.unresolvedOnly===!0?`WHERE memory_id = ? AND resolved_at IS NULL`:`WHERE memory_id = ?`;return this.#e.db.prepare(`SELECT * FROM memory_review_events ${n} ORDER BY created_at DESC`).all(e).map(e=>I(O.parse(e)))}createReviewEvent(e){let t=new Date().toISOString();this.#e.db.prepare(`INSERT INTO memory_review_events
300
+ ORDER BY created_at DESC ${c}`).all(...o,t,...l),u.length===0)return[];let d=u.map(e=>e.id),f=this.#t.getProjectsForMemories(d),p=this.#r(d,{unresolvedOnly:!0});return u.map(e=>R(e,f.get(e.id)??[],p.get(e.id)??[]))}listReviewEdges(e){return e===void 0?this.#e.db.prepare(`SELECT memory_id, conflicting_memory_id FROM memory_review_events
301
+ WHERE resolved_at IS NULL AND conflicting_memory_id IS NOT NULL`).all().map(e=>({memoryId:e.memory_id,conflictingMemoryId:e.conflicting_memory_id})):this.#e.db.prepare(`SELECT e.memory_id, e.conflicting_memory_id
302
+ FROM memory_review_events e
303
+ JOIN memories m ON m.id = e.memory_id
304
+ WHERE e.resolved_at IS NULL
305
+ AND e.conflicting_memory_id IS NOT NULL
306
+ AND ${this.#n(`m`)}`).all(e).map(e=>({memoryId:e.memory_id,conflictingMemoryId:e.conflicting_memory_id}))}listReviewEvents(e,t){let n=t?.unresolvedOnly===!0?`WHERE memory_id = ? AND resolved_at IS NULL`:`WHERE memory_id = ?`;return this.#e.db.prepare(`SELECT * FROM memory_review_events ${n} ORDER BY created_at DESC`).all(e).map(e=>z(A.parse(e)))}createReviewEvent(e){let t=new Date().toISOString();this.#e.db.prepare(`INSERT INTO memory_review_events
277
307
  (id, memory_id, conflicting_memory_id, similarity, conflict_content_snapshot, reason, created_at)
278
- VALUES (?, ?, ?, ?, ?, 'similarity_dedup', ?)`).run((0,c.randomUUID)(),e.memoryId,e.conflictingMemoryId,e.similarity,e.conflictContentSnapshot,t)}resolveReviewEvents(e){let t=new Date().toISOString();this.#e.db.prepare(`UPDATE memory_review_events SET resolved_at = ? WHERE memory_id = ? AND resolved_at IS NULL`).run(t,e)}getPinnedCharCount(e){return e===void 0?(this.#e.db.prepare(`SELECT COALESCE(SUM(LENGTH(content)), 0) as total FROM memories WHERE pinned = 1`).get()??{total:0}).total:(this.#e.db.prepare(`SELECT COALESCE(SUM(LENGTH(content)), 0) as total FROM memories
279
- WHERE pinned = 1 AND ${this.#n()}`).get(e)??{total:0}).total}stats(e){let t=Object.fromEntries(S.map(e=>[e,0]));if(e!==void 0){let n=this.#e.db.prepare(`SELECT type, COUNT(*) as count FROM memories
308
+ VALUES (?, ?, ?, ?, ?, 'similarity_dedup', ?)`).run((0,l.randomUUID)(),e.memoryId,e.conflictingMemoryId,e.similarity,e.conflictContentSnapshot,t)}resolveReviewEvents(e){let t=new Date().toISOString();this.#e.db.prepare(`UPDATE memory_review_events SET resolved_at = ? WHERE memory_id = ? AND resolved_at IS NULL`).run(t,e)}getPinnedCharCount(e){return e===void 0?(this.#e.db.prepare(`SELECT COALESCE(SUM(LENGTH(content)), 0) as total FROM memories WHERE pinned = 1`).get()??{total:0}).total:(this.#e.db.prepare(`SELECT COALESCE(SUM(LENGTH(content)), 0) as total FROM memories
309
+ WHERE pinned = 1 AND ${this.#n()}`).get(e)??{total:0}).total}stats(e){let t=Object.fromEntries(w.map(e=>[e,0]));if(e!==void 0){let n=this.#e.db.prepare(`SELECT type, COUNT(*) as count FROM memories
280
310
  WHERE ${this.#n()}
281
- GROUP BY type`).all(e);for(let e of n){let n=C.safeParse(e.type);n.success&&(t[n.data]=e.count)}let r=this.#e.db.prepare(`SELECT COUNT(*) as total, SUM(pinned) as pinned,
311
+ GROUP BY type`).all(e);for(let e of n){let n=T.safeParse(e.type);n.success&&(t[n.data]=e.count)}let r=this.#e.db.prepare(`SELECT COUNT(*) as total, SUM(pinned) as pinned,
282
312
  COALESCE(SUM(CASE WHEN pinned = 1 THEN LENGTH(content) ELSE 0 END), 0) as pinBudgetChars
283
313
  FROM memories WHERE ${this.#n()}`).get(e)??{total:0,pinned:0,pinBudgetChars:0},i=this.#e.db.prepare(`SELECT COUNT(DISTINCT e.memory_id) as needsReview
284
314
  FROM memory_review_events e
285
315
  JOIN memories m ON m.id = e.memory_id
286
316
  WHERE e.resolved_at IS NULL
287
- AND ${this.#n(`m`)}`).get(e)??{needsReview:0};return{byType:t,total:r.total,pinned:r.pinned??0,needsReview:i.needsReview,pinBudgetChars:r.pinBudgetChars}}let n=this.#e.db.prepare(`SELECT type, COUNT(*) as count FROM memories GROUP BY type`).all();for(let e of n){let n=C.safeParse(e.type);n.success&&(t[n.data]=e.count)}let r=this.#e.db.prepare(`SELECT COUNT(*) as total, SUM(pinned) as pinned FROM memories`).get()??{total:0,pinned:0},i=this.#e.db.prepare(`SELECT COUNT(DISTINCT memory_id) as needsReview FROM memory_review_events WHERE resolved_at IS NULL`).get()??{needsReview:0};return{byType:t,total:r.total,pinned:r.pinned??0,needsReview:i.needsReview,pinBudgetChars:this.getPinnedCharCount()}}setPin(e,t){if(this.#e.db.prepare(`SELECT * FROM memories WHERE id = ?`).get(e)===void 0)throw Error(`Memory not found: ${e}`);let n=new Date().toISOString();this.#e.db.prepare(`UPDATE memories SET pinned = ?, updated_at = ? WHERE id = ?`).run(+!!t,n,e);let r=N.parse(this.#e.db.prepare(`SELECT * FROM memories WHERE id = ?`).get(e)),i=this.#t.getProjectsForMemories([e]),a=this.#r([e]);return F(r,i.get(e)??[],a.get(e)??[])}incrementAccessCount(e){this.#e.db.prepare(`UPDATE memories SET access_count = access_count + 1 WHERE id = ?`).run(e)}exportAll(){return this.#e.db.prepare(`SELECT m.*, e.embedding FROM memories m LEFT JOIN embeddings e ON e.rowid = m.rowid ORDER BY m.created_at DESC`).all().map(e=>({id:e.id,content:e.content,type:C.parse(e.type),tags:w.parse(JSON.parse(e.tags)),sourceHarness:e.source,accessCount:e.access_count,pinned:e.pinned!==0,createdAt:e.created_at,updatedAt:e.updated_at,embedding:e.embedding===null?null:new Float32Array(e.embedding.buffer,e.embedding.byteOffset,e.embedding.byteLength/4)}))}importAll(e){let t=this.#e.db.prepare(`INSERT OR REPLACE INTO memories (id, content, type, tags, source, access_count, pinned, created_at, updated_at)
317
+ AND ${this.#n(`m`)}`).get(e)??{needsReview:0};return{byType:t,total:r.total,pinned:r.pinned??0,needsReview:i.needsReview,pinBudgetChars:r.pinBudgetChars}}let n=this.#e.db.prepare(`SELECT type, COUNT(*) as count FROM memories GROUP BY type`).all();for(let e of n){let n=T.safeParse(e.type);n.success&&(t[n.data]=e.count)}let r=this.#e.db.prepare(`SELECT COUNT(*) as total, SUM(pinned) as pinned FROM memories`).get()??{total:0,pinned:0},i=this.#e.db.prepare(`SELECT COUNT(DISTINCT memory_id) as needsReview FROM memory_review_events WHERE resolved_at IS NULL`).get()??{needsReview:0};return{byType:t,total:r.total,pinned:r.pinned??0,needsReview:i.needsReview,pinBudgetChars:this.getPinnedCharCount()}}reviewQueueStats(e){let t=e===void 0?`JOIN memories m ON m.id = e.memory_id WHERE e.resolved_at IS NULL`:`JOIN memories m ON m.id = e.memory_id
318
+ WHERE e.resolved_at IS NULL AND ${this.#n(`m`)}`,n=e===void 0?[]:[e],r=this.#e.db.prepare(`SELECT
319
+ CASE
320
+ WHEN e.similarity >= 0.85 THEN 'high'
321
+ WHEN e.similarity >= 0.80 THEN 'mid'
322
+ ELSE 'low'
323
+ END AS band,
324
+ COUNT(DISTINCT e.memory_id) AS count
325
+ FROM memory_review_events e ${t}
326
+ GROUP BY band`).all(...n),i=this.#e.db.prepare(`SELECT m.type, COUNT(DISTINCT e.memory_id) AS count
327
+ FROM memory_review_events e ${t}
328
+ GROUP BY m.type`).all(...n),a=this.#e.db.prepare(`SELECT COUNT(*) AS pairs FROM memory_review_events e ${t}`).get(...n)??{pairs:0},o={high:0,mid:0,low:0};for(let e of r)(e.band===`high`||e.band===`mid`||e.band===`low`)&&(o[e.band]=e.count);let s={};for(let e of i){let t=T.safeParse(e.type);t.success&&(s[t.data]=e.count)}return{pairs:a.pairs,byBand:o,byType:s}}setPin(e,t){if(this.#e.db.prepare(`SELECT * FROM memories WHERE id = ?`).get(e)===void 0)throw Error(`Memory not found: ${e}`);let n=new Date().toISOString();this.#e.db.prepare(`UPDATE memories SET pinned = ?, updated_at = ? WHERE id = ?`).run(+!!t,n,e);let r=I.parse(this.#e.db.prepare(`SELECT * FROM memories WHERE id = ?`).get(e)),i=this.#t.getProjectsForMemories([e]),a=this.#r([e]);return R(r,i.get(e)??[],a.get(e)??[])}incrementAccessCount(e){this.#e.db.prepare(`UPDATE memories SET access_count = access_count + 1 WHERE id = ?`).run(e)}exportAll(){return this.#e.db.prepare(`SELECT m.*, e.embedding FROM memories m LEFT JOIN embeddings e ON e.rowid = m.rowid ORDER BY m.created_at DESC`).all().map(e=>({id:e.id,content:e.content,type:T.parse(e.type),tags:E.parse(JSON.parse(e.tags)),sourceHarness:e.source,accessCount:e.access_count,pinned:e.pinned!==0,createdAt:e.created_at,updatedAt:e.updated_at,embedding:e.embedding===null?null:new Float32Array(e.embedding.buffer,e.embedding.byteOffset,e.embedding.byteLength/4)}))}importAll(e){let t=this.#e.db.prepare(`INSERT OR REPLACE INTO memories (id, content, type, tags, source, access_count, pinned, created_at, updated_at)
288
329
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`),n=this.#e.db.prepare(`INSERT OR REPLACE INTO embeddings (rowid, embedding) SELECT m.rowid, ? FROM memories m WHERE m.id = ?`);this.#e.db.transaction(()=>{for(let r of e)t.run(r.id,r.content,r.type,JSON.stringify(r.tags),r.sourceHarness,r.accessCount,+!!r.pinned,r.createdAt,r.updatedAt),r.embedding!==null&&n.run(Buffer.from(r.embedding.buffer,r.embedding.byteOffset,r.embedding.byteLength),r.id)})()}#n(e=`memories`){return`EXISTS (
289
330
  SELECT 1 FROM memory_projects mp JOIN projects p ON p.id = mp.project_id
290
- WHERE mp.memory_id = ${e}.id AND (p.scope_hash = ? OR p.scope_hash = '${W}')
331
+ WHERE mp.memory_id = ${e}.id AND (p.scope_hash = ? OR p.scope_hash = '${c.r}')
291
332
  )`}#r(e,t){if(e.length===0)return new Map;let n=e.map(()=>`?`).join(`, `),r=t?.unresolvedOnly===!0?`AND resolved_at IS NULL`:``,i=this.#e.db.prepare(`SELECT * FROM memory_review_events
292
333
  WHERE memory_id IN (${n}) ${r}
293
- ORDER BY created_at DESC`).all(...e),a=new Map;for(let e of i){let t=I(O.parse(e)),n=a.get(t.memoryId)??[];n.push(t),a.set(t.memoryId,n)}return a}};function Fe(e,t){return new q(e,t)}const J=(0,re.promisify)(ne.execFile);function Y(e){return(0,c.createHash)(`sha256`).update(e).digest(`hex`).slice(0,16)}async function X(){try{let{stdout:e}=await J(`git`,[`remote`,`get-url`,`origin`]),t=e.trim();if(t){let e=Y(t);return{hash:e,name:t.split(`/`).pop()?.replace(/\.git$/,``)??e.slice(0,8)}}}catch{}let e=process.cwd(),t=Y(e);return{hash:t,name:e.split(/[/\\]/).filter(Boolean).pop()??t.slice(0,8)}}async function Ie(){try{let{stdout:e}=await J(`git`,[`remote`,`get-url`,`origin`]),t=e.trim();if(t)return Y(t)}catch{}return Y(process.cwd())}const Le=[{name:`scope-to-projects`,description:`Rename the auto-migrated project for the current directory from its generic hash-derived name to the resolved repo/directory name.`}];async function Re(e){let t=await X(),n=e.getByHash(t.hash);if(n===void 0)return null;let r=n.name,i=e.countMemories(n.id);return e.rename(n.id,t.name),{migration:`scope-to-projects`,oldName:r,newName:t.name,memoryCount:i}}var ze=class{#e;constructor(e){this.#e=e}upsertByHash(e,t){if(!/^[0-9a-f]{16}$/.test(e))throw Error(`Invalid scope hash "${e}": expected 16 lowercase hex characters`);let n=new Date().toISOString(),r=e===`0000000000000000`?U:(0,c.randomUUID)(),i=e===`0000000000000000`?G:t;return this.#e.db.prepare(`INSERT OR IGNORE INTO projects (id, name, scope_hash, created_at, updated_at) VALUES (?, ?, ?, ?, ?)`).run(r,i,e,n,n),L(P.parse(this.#e.db.prepare(`SELECT * FROM projects WHERE scope_hash = ?`).get(e)))}rename(e,t){let n=new Date().toISOString();this.#e.db.prepare(`UPDATE projects SET name = ?, updated_at = ? WHERE id = ?`).run(t,n,e);let r=this.#e.db.prepare(`SELECT * FROM projects WHERE id = ?`).get(e);if(r===void 0)throw Error(`Project not found: ${e}`);return L(r)}list(){return this.#e.db.prepare(`SELECT * FROM projects ORDER BY name ASC`).all().map(L)}getByHash(e){let t=this.#e.db.prepare(`SELECT * FROM projects WHERE scope_hash = ?`).get(e);return t===void 0?void 0:L(t)}getByName(e){let t=this.#e.db.prepare(`SELECT * FROM projects WHERE name = ? LIMIT 1`).get(e);return t===void 0?void 0:L(t)}addAssociation(e,t){this.#e.db.prepare(`INSERT OR IGNORE INTO memory_projects (memory_id, project_id) VALUES (?, ?)`).run(e,t)}removeAssociation(e,t){this.#e.db.prepare(`DELETE FROM memory_projects WHERE memory_id = ? AND project_id = ?`).run(e,t)}countMemories(e){return this.#e.db.prepare(`SELECT COUNT(*) AS count FROM memory_projects WHERE project_id = ?`).get(e)?.count??0}getProjectsForMemories(e){if(e.length===0)return new Map;let t=e.map(()=>`?`).join(`,`),n=this.#e.db.prepare(`SELECT p.*, mp.memory_id FROM projects p
334
+ ORDER BY created_at DESC`).all(...e),a=new Map;for(let e of i){let t=z(A.parse(e)),n=a.get(t.memoryId)??[];n.push(t),a.set(t.memoryId,n)}return a}};function Fe(e,t){return new Y(e,t)}const X=(0,ne.promisify)(te.execFile);function Z(e){return(0,l.createHash)(`sha256`).update(e).digest(`hex`).slice(0,16)}async function Ie(){try{let{stdout:e}=await X(`git`,[`remote`,`get-url`,`origin`]),t=e.trim();if(t){let e=Z(t);return{hash:e,name:t.split(`/`).pop()?.replace(/\.git$/,``)??e.slice(0,8)}}}catch{}let e=process.cwd(),t=Z(e);return{hash:t,name:e.split(/[/\\]/).filter(Boolean).pop()??t.slice(0,8)}}async function Le(){try{let{stdout:e}=await X(`git`,[`remote`,`get-url`,`origin`]),t=e.trim();if(t)return Z(t)}catch{}return Z(process.cwd())}const Re=[{name:`scope-to-projects`,description:`Rename the auto-migrated project for the current directory from its generic hash-derived name to the resolved repo/directory name.`}];async function ze(e){let t=await Ie(),n=e.getByHash(t.hash);if(n===void 0)return null;let r=n.name,i=e.countMemories(n.id);return e.rename(n.id,t.name),{migration:`scope-to-projects`,oldName:r,newName:t.name,memoryCount:i}}var Be=class{#e;constructor(e){this.#e=e}upsertByHash(e,t){if(!/^[0-9a-f]{16}$/.test(e))throw Error(`Invalid scope hash "${e}": expected 16 lowercase hex characters`);let n=new Date().toISOString(),r=e===`0000000000000000`?c.t:(0,l.randomUUID)(),i=e===`0000000000000000`?c.n:t;return this.#e.db.prepare(`INSERT OR IGNORE INTO projects (id, name, scope_hash, created_at, updated_at) VALUES (?, ?, ?, ?, ?)`).run(r,i,e,n,n),B(L.parse(this.#e.db.prepare(`SELECT * FROM projects WHERE scope_hash = ?`).get(e)))}rename(e,t){let n=new Date().toISOString();this.#e.db.prepare(`UPDATE projects SET name = ?, updated_at = ? WHERE id = ?`).run(t,n,e);let r=this.#e.db.prepare(`SELECT * FROM projects WHERE id = ?`).get(e);if(r===void 0)throw Error(`Project not found: ${e}`);return B(r)}list(){return this.#e.db.prepare(`SELECT * FROM projects ORDER BY name ASC`).all().map(B)}getByHash(e){let t=this.#e.db.prepare(`SELECT * FROM projects WHERE scope_hash = ?`).get(e);return t===void 0?void 0:B(t)}getByName(e){let t=this.#e.db.prepare(`SELECT * FROM projects WHERE name = ? LIMIT 1`).get(e);return t===void 0?void 0:B(t)}addAssociation(e,t){this.#e.db.prepare(`INSERT OR IGNORE INTO memory_projects (memory_id, project_id) VALUES (?, ?)`).run(e,t)}removeAssociation(e,t){this.#e.db.prepare(`DELETE FROM memory_projects WHERE memory_id = ? AND project_id = ?`).run(e,t)}countMemories(e){return this.#e.db.prepare(`SELECT COUNT(*) AS count FROM memory_projects WHERE project_id = ?`).get(e)?.count??0}getProjectsForMemories(e){if(e.length===0)return new Map;let t=e.map(()=>`?`).join(`,`),n=this.#e.db.prepare(`SELECT p.*, mp.memory_id FROM projects p
294
335
  JOIN memory_projects mp ON mp.project_id = p.id
295
- WHERE mp.memory_id IN (${t})`).all(...e),r=new Map;for(let e of n){let t=r.get(e.memory_id)??[];t.push(L(e)),r.set(e.memory_id,t)}return r}};function Be(e){return new ze(e)}const Ve={correction:1,preference:.8,decision:.6,learning:.4,fact:.2};function He(e,t,n){let r=Ve[e.type],i=e.accessCount/(e.accessCount+10),a=1/(1+(n-new Date(e.updatedAt).getTime())/864e5),o=+!!e.pinned;return t*.4+r*.25+i*.2+a*.1+o*.05}async function Z(e,t){let{query:n,type:r,projectHash:i,limit:a=10,includePinned:o}=A.parse(e),{activityLogger:s=x}=t,c=await t.embedder.embed(n),l=Buffer.from(c.buffer),u=t.adapter.findByEmbedding(l,{type:r,projectHash:i,includePinned:o}),d=Date.now(),f=u.filter(e=>e.cosineSim>0).map(e=>{let{cosineSim:t,...n}=e;return{...n,score:He(n,t,d)}});f.sort((e,t)=>t.score-e.score);let p=f.slice(0,a);for(let e of p)t.repo.incrementAccessCount(e.id);return s.logEvent({projectHash:i??`0000000000000000`,eventType:`memory.queried`,payload:{resultCount:p.length,topScores:p.slice(0,3).map(e=>e.score)}}),p}var Ue=class{#e;constructor(e){this.#e=e}findByEmbedding(e,t){let{type:n,projectHash:r,includePinned:i}=t,a=[],o=[e],s=``;i||a.push(`m.pinned = 0`),n!==void 0&&(a.push(`m.type = ?`),o.push(n)),r!==void 0&&(s=`JOIN memory_projects mp ON mp.memory_id = m.id JOIN projects p ON p.id = mp.project_id`,a.push(`(p.scope_hash = ? OR p.scope_hash = ?)`),o.push(r,W));let c=a.length>0?`WHERE ${a.join(` AND `)}`:``,l=`
336
+ WHERE mp.memory_id IN (${t})`).all(...e),r=new Map;for(let e of n){let t=r.get(e.memory_id)??[];t.push(B(e)),r.set(e.memory_id,t)}return r}};function Ve(e){return new Be(e)}const He={correction:1,preference:.8,decision:.6,learning:.4,fact:.2};function Ue(e,t,n){let r=He[e.type],i=e.accessCount/(e.accessCount+10),a=1/(1+(n-new Date(e.updatedAt).getTime())/864e5),o=+!!e.pinned;return t*.4+r*.25+i*.2+a*.1+o*.05}async function We(e,t){let{query:n,type:r,projectHash:i,limit:a=10,includePinned:o}=M.parse(e),{activityLogger:s=C}=t,c=await t.embedder.embed(n),l=Buffer.from(c.buffer),u=t.adapter.findByEmbedding(l,{type:r,projectHash:i,includePinned:o}),d=Date.now(),f=u.filter(e=>e.cosineSim>0).map(e=>{let{cosineSim:t,...n}=e;return{...n,score:Ue(n,t,d)}});f.sort((e,t)=>t.score-e.score);let p=f.slice(0,a);for(let e of p)t.repo.incrementAccessCount(e.id);return s.logEvent({projectHash:i??`0000000000000000`,eventType:`memory.queried`,payload:{resultCount:p.length,topScores:p.slice(0,3).map(e=>e.score)}}),p}var Ge=class{#e;constructor(e){this.#e=e}findByEmbedding(e,t){let{type:n,projectHash:r,includePinned:i}=t,a=[],o=[e],s=``;i||a.push(`m.pinned = 0`),n!==void 0&&(a.push(`m.type = ?`),o.push(n)),r!==void 0&&(s=`JOIN memory_projects mp ON mp.memory_id = m.id JOIN projects p ON p.id = mp.project_id`,a.push(`(p.scope_hash = ? OR p.scope_hash = ?)`),o.push(r,c.r));let l=a.length>0?`WHERE ${a.join(` AND `)}`:``,u=`
296
337
  SELECT m.*, (1 - vec_distance_cosine(e.embedding, ?)) AS cosine_sim
297
338
  FROM memories m JOIN embeddings e ON e.rowid = m.rowid
298
339
  ${s}
299
- ${c}
300
- `;return this.#e.db.prepare(l).all(...o).map(e=>({...F(e,[]),cosineSim:e.cosine_sim}))}},We=class{#e;#t;#n;#r;constructor(e,t,n,r=x){this.#e=e,this.#t=t,this.#n=n,this.#r=r}async query(e){return Z(e,{adapter:new Ue(this.#e),repo:this.#n,embedder:this.#t,activityLogger:this.#r})}};function Q(e,t){let n=t.repo.stats(e.projectHash);return e.synthesis!==void 0&&e.synthesis.length>0?{stats:n.byType,pinnedGlobal:[],pinnedProject:[],synthesis:e.synthesis}:{stats:n.byType,pinnedGlobal:t.repo.listPinnedGlobal(),pinnedProject:t.repo.listPinnedForProject(e.projectHash)}}function Ge(){return[...S]}var Ke=class{#e;constructor(e){this.#e=e}getSessionContext(e,t){return Q({projectHash:e,synthesis:t},{repo:this.#e})}},qe=class{#e;#t;#n;#r=new Set;#i=new Map;#a=!1;#o;#s=new Map;constructor(e,t,n){this.#e=e,this.#t=t,this.#n=n}async init(){this.#e.clearStaleInFlight(this.#t.inFlightTimeoutMs??12e4),this.#e.expireStale();let e=this.#e.getExpiredOrDirtyScopes();for(let{scope:t}of e)this.#r.add(t);this.#a=!0,await this.#l()}shutdown(){this.#a=!1,this.#o!==void 0&&(clearTimeout(this.#o),this.#o=void 0);let e=[...this.#s.values()];return e.length===0?Promise.resolve():Promise.race([Promise.allSettled(e).then(()=>void 0),new Promise(e=>setTimeout(e,5e3))])}markDirty(e){this.#r.add(e)}#c(){if(!this.#a)return;let e=this.#t.debounceMs??45e3;this.#o=setTimeout(()=>{this.#l()},e)}async#l(){let e=[...this.#r];for(let t of e){let e=this.#t.inFlightTimeoutMs??12e4,n=this.#e.getSynthesis(t);if(n?.inFlightSince!==null&&n?.inFlightSince!==void 0){if(Date.now()-new Date(n.inFlightSince).getTime()<e)continue;this.#e.clearInFlight(t)}this.#r.delete(t);let r=this.#u(t).finally(()=>{this.#s.delete(t)});this.#s.set(t,r)}this.#c()}async#u(e){this.#e.markInFlight(e);try{let t=e===`0000000000000000`?void 0:e,n=await this.#n.run(e,t),r=this.#e.computeSourceMemoryHash(e);this.#e.saveSynthesis(e,n,r),this.#i.delete(e)}catch(t){let n=(this.#i.get(e)??0)+1;this.#i.set(e,n);let r=Math.min(n,5),i=(this.#t.debounceMs??45e3)*r;process.stderr.write(`membank synthesis: error for scope=${e} failures=${n} backoff=${i}ms: ${t instanceof Error?t.message:String(t)}\n`),setTimeout(()=>{this.#r.add(e)},i),this.#e.clearInFlight(e)}}};async function Je(e,t){let n=e===`0000000000000000`?void 0:e;t.synthRepo.markInFlight(e);try{let[r,i]=await Promise.all([t.agentRunner.run(e,n),Promise.resolve(t.synthRepo.computeSourceMemoryHash(e))]);return t.synthRepo.saveSynthesis(e,r,i),r}catch(n){throw t.synthRepo.clearInFlight(e),n}}var Ye=class{#e;constructor(e,t){this.#e=e}async run(e,t){let n=(0,g.createSdkMcpServer)({name:`membank-synthesis-tools`,version:`1.0.0`,tools:[(0,g.tool)(`query_memory`,`Search memories by semantic similarity`,{query:l.z.string().describe(`Search text`),limit:l.z.number().optional().describe(`Maximum results to return`),global:l.z.boolean().optional().describe(`Query global memories only when true, otherwise current project scope`)},async({query:e,limit:n,global:r})=>({content:[{type:`text`,text:await this.#e.queryMemory({query:e,limit:n,global:r,projectHash:t})}]}),{annotations:{readOnlyHint:!0}}),(0,g.tool)(`get_memory_summary`,`Returns aggregate stats: total memories, counts by type, pinned count, review queue size`,{},async()=>({content:[{type:`text`,text:await this.#e.getMemorySummary()}]}),{annotations:{readOnlyHint:!0}})]}),r=`Synthesize the memories for ${e===`0000000000000000`?`global (across all projects)`:`project scope: ${e}`}. Use get_memory_summary first to understand the overall state, then use query_memory to retrieve relevant memories (query with broad terms like "preferences", "corrections", "decisions", "key facts"). After gathering information, produce a concise synthesis of the most important things to remember about this user. Output only the synthesis text — no preamble, no metadata.`,i=Date.now(),a=Object.fromEntries(Object.entries(process.env).filter(e=>e[1]!==void 0)),o=(0,g.query)({prompt:r,options:{model:`claude-haiku-4-5-20251001`,systemPrompt:`You are a memory synthesizer. Your job is to read the user's stored memories and produce a concise, well-structured summary of what's most important to remember about this user — their preferences, corrections, decisions, and key facts. Pinned memories are higher fidelity and should be weighted more heavily. Exclude transient or ephemeral details. Output plain text suitable for injection into an LLM context window. Be concise — target 200-400 words.`,mcpServers:{"membank-synthesis-tools":n},allowedTools:[`mcp__membank-synthesis-tools__query_memory`,`mcp__membank-synthesis-tools__get_memory_summary`],disallowedTools:[`mcp__membank__*`],settingSources:[],permissionMode:`bypassPermissions`,env:a}}),s=``;for await(let e of o)if(e.type===`result`)if(e.subtype===`success`)s=e.result;else{let t=`errors`in e&&Array.isArray(e.errors)?`: ${e.errors.join(`; `)}`:``;throw Error(`Synthesis agent failed: ${e.subtype}${t}`)}let c=Date.now()-i;if(process.stderr.write(`membank synthesis: scope=${e} duration=${c}ms\n`),s===``)throw Error(`Synthesis agent returned empty result`);return s}};function Xe(e,t){return new Ye(e,t)}function $(e){return M.parse({id:e.id,scope:e.scope,content:e.content,sourceMemoryHash:e.source_memory_hash,synthesizedAt:e.synthesized_at,expiresAt:e.expires_at,inFlightSince:e.in_flight_since,createdAt:e.created_at,updatedAt:e.updated_at})}var Ze=class{#e;constructor(e){this.#e=e}saveSynthesis(e,t,n){let r=new Date().toISOString(),i=new Date(Date.now()+720*60*60*1e3).toISOString();if(this.#e.db.prepare(`SELECT id FROM syntheses WHERE scope = ?`).get(e)!==void 0)this.#e.db.prepare(`UPDATE syntheses
340
+ ${l}
341
+ `;return this.#e.db.prepare(u).all(...o).map(e=>({...R(e,[]),cosineSim:e.cosine_sim}))}},Ke=class{#e;#t;#n;#r;constructor(e,t,n,r=C){this.#e=e,this.#t=t,this.#n=n,this.#r=r}async query(e){return We(e,{adapter:new Ge(this.#e),repo:this.#n,embedder:this.#t,activityLogger:this.#r})}};function Q(e,t){let n=t.repo.stats(e.projectHash);return e.synthesis!==void 0&&e.synthesis.length>0?{stats:n.byType,pinnedGlobal:[],pinnedProject:[],synthesis:e.synthesis}:{stats:n.byType,pinnedGlobal:t.repo.listPinnedGlobal(),pinnedProject:t.repo.listPinnedForProject(e.projectHash)}}function qe(){return[...w]}var Je=class{#e;constructor(e){this.#e=e}getSessionContext(e,t){return Q({projectHash:e,synthesis:t},{repo:this.#e})}},Ye=class{#e;#t;#n;#r=new Set;#i=new Map;#a=!1;#o;#s=new Map;constructor(e,t,n){this.#e=e,this.#t=t,this.#n=n}async init(){this.#e.clearStaleInFlight(this.#t.inFlightTimeoutMs??12e4),this.#e.expireStale();let e=this.#e.getExpiredOrDirtyScopes();for(let{scope:t}of e)this.#r.add(t);this.#a=!0,await this.#l()}shutdown(){this.#a=!1,this.#o!==void 0&&(clearTimeout(this.#o),this.#o=void 0);let e=[...this.#s.values()];return e.length===0?Promise.resolve():Promise.race([Promise.allSettled(e).then(()=>void 0),new Promise(e=>setTimeout(e,5e3))])}markDirty(e){this.#r.add(e)}#c(){if(!this.#a)return;let e=this.#t.debounceMs??45e3;this.#o=setTimeout(()=>{this.#l()},e)}async#l(){let e=[...this.#r];for(let t of e){let e=this.#t.inFlightTimeoutMs??12e4,n=this.#e.getSynthesis(t);if(n?.inFlightSince!==null&&n?.inFlightSince!==void 0){if(Date.now()-new Date(n.inFlightSince).getTime()<e)continue;this.#e.clearInFlight(t)}this.#r.delete(t);let r=this.#u(t).finally(()=>{this.#s.delete(t)});this.#s.set(t,r)}this.#c()}async#u(e){this.#e.markInFlight(e);try{let t=e===`0000000000000000`?void 0:e,n=await this.#n.run(e,t),r=this.#e.computeSourceMemoryHash(e);this.#e.saveSynthesis(e,n,r),this.#i.delete(e)}catch(t){let n=(this.#i.get(e)??0)+1;this.#i.set(e,n);let r=Math.min(n,5),i=(this.#t.debounceMs??45e3)*r;process.stderr.write(`membank synthesis: error for scope=${e} failures=${n} backoff=${i}ms: ${t instanceof Error?t.message:String(t)}\n`),setTimeout(()=>{this.#r.add(e)},i),this.#e.clearInFlight(e)}}};async function Xe(e,t){let n=e===`0000000000000000`?void 0:e;t.synthRepo.markInFlight(e);try{let[r,i]=await Promise.all([t.agentRunner.run(e,n),Promise.resolve(t.synthRepo.computeSourceMemoryHash(e))]);return t.synthRepo.saveSynthesis(e,r,i),r}catch(n){throw t.synthRepo.clearInFlight(e),n}}var Ze=class{#e;constructor(e,t){this.#e=e}async run(e,t){let n=(0,v.createSdkMcpServer)({name:`membank-synthesis-tools`,version:`1.0.0`,tools:[(0,v.tool)(`query_memory`,`Search memories by semantic similarity`,{query:u.z.string().describe(`Search text`),limit:u.z.number().optional().describe(`Maximum results to return`),global:u.z.boolean().optional().describe(`Query global memories only when true, otherwise current project scope`)},async({query:e,limit:n,global:r})=>({content:[{type:`text`,text:await this.#e.queryMemory({query:e,limit:n,global:r,projectHash:t})}]}),{annotations:{readOnlyHint:!0}}),(0,v.tool)(`get_memory_summary`,`Returns aggregate stats: total memories, counts by type, pinned count, review queue size`,{},async()=>({content:[{type:`text`,text:await this.#e.getMemorySummary()}]}),{annotations:{readOnlyHint:!0}})]}),r=`Synthesize the memories for ${e===`0000000000000000`?`global (across all projects)`:`project scope: ${e}`}. Use get_memory_summary first to understand the overall state, then use query_memory to retrieve relevant memories (query with broad terms like "preferences", "corrections", "decisions", "key facts"). After gathering information, produce a concise synthesis of the most important things to remember about this user. Output only the synthesis text — no preamble, no metadata.`,i=Date.now(),a=Object.fromEntries(Object.entries(process.env).filter(e=>e[1]!==void 0)),o=(0,v.query)({prompt:r,options:{model:`claude-haiku-4-5-20251001`,systemPrompt:`You are a memory synthesizer. Your job is to read the user's stored memories and produce a concise, well-structured summary of what's most important to remember about this user — their preferences, corrections, decisions, and key facts. Pinned memories are higher fidelity and should be weighted more heavily. Exclude transient or ephemeral details. Output plain text suitable for injection into an LLM context window. Be concise — target 200-400 words.`,mcpServers:{"membank-synthesis-tools":n},allowedTools:[`mcp__membank-synthesis-tools__query_memory`,`mcp__membank-synthesis-tools__get_memory_summary`],disallowedTools:[`mcp__membank__*`],settingSources:[],permissionMode:`bypassPermissions`,env:a}}),s=``;for await(let e of o)if(e.type===`result`)if(e.subtype===`success`)s=e.result;else{let t=`errors`in e&&Array.isArray(e.errors)?`: ${e.errors.join(`; `)}`:``;throw Error(`Synthesis agent failed: ${e.subtype}${t}`)}let c=Date.now()-i;if(process.stderr.write(`membank synthesis: scope=${e} duration=${c}ms\n`),s===``)throw Error(`Synthesis agent returned empty result`);return s}};function Qe(e,t){return new Ze(e,t)}function $(e){return F.parse({id:e.id,scope:e.scope,content:e.content,sourceMemoryHash:e.source_memory_hash,synthesizedAt:e.synthesized_at,expiresAt:e.expires_at,inFlightSince:e.in_flight_since,createdAt:e.created_at,updatedAt:e.updated_at})}var $e=class{#e;constructor(e){this.#e=e}saveSynthesis(e,t,n){let r=new Date().toISOString(),i=new Date(Date.now()+720*60*60*1e3).toISOString();if(this.#e.db.prepare(`SELECT id FROM syntheses WHERE scope = ?`).get(e)!==void 0)this.#e.db.prepare(`UPDATE syntheses
301
342
  SET content = ?, source_memory_hash = ?, synthesized_at = ?, expires_at = ?,
302
343
  in_flight_since = NULL, updated_at = ?
303
- WHERE scope = ?`).run(t,n,r,i,r,e);else{let a=(0,c.randomUUID)();this.#e.db.prepare(`INSERT INTO syntheses
344
+ WHERE scope = ?`).run(t,n,r,i,r,e);else{let a=(0,l.randomUUID)();this.#e.db.prepare(`INSERT INTO syntheses
304
345
  (id, scope, content, source_memory_hash, synthesized_at, expires_at,
305
346
  in_flight_since, created_at, updated_at)
306
- VALUES (?, ?, ?, ?, ?, ?, NULL, ?, ?)`).run(a,e,t,n,r,i,r,r)}let a=this.#e.db.prepare(`SELECT * FROM syntheses WHERE scope = ?`).get(e);if(a===void 0)throw Error(`Failed to save synthesis for scope: ${e}`);return $(a)}getSynthesis(e){let t=this.#e.db.prepare(`SELECT * FROM syntheses WHERE scope = ?`).get(e);return t===void 0?void 0:$(t)}listAll(){return this.#e.db.prepare(`SELECT * FROM syntheses ORDER BY scope`).all().map($)}markInFlight(e){let t=new Date().toISOString();if(this.#e.db.prepare(`SELECT id FROM syntheses WHERE scope = ?`).get(e)!==void 0)this.#e.db.prepare(`UPDATE syntheses SET in_flight_since = ?, updated_at = ? WHERE scope = ?`).run(t,t,e);else{let n=(0,c.randomUUID)(),r=new Date(Date.now()+720*60*60*1e3).toISOString();this.#e.db.prepare(`INSERT INTO syntheses
347
+ VALUES (?, ?, ?, ?, ?, ?, NULL, ?, ?)`).run(a,e,t,n,r,i,r,r)}let a=this.#e.db.prepare(`SELECT * FROM syntheses WHERE scope = ?`).get(e);if(a===void 0)throw Error(`Failed to save synthesis for scope: ${e}`);return $(a)}getSynthesis(e){let t=this.#e.db.prepare(`SELECT * FROM syntheses WHERE scope = ?`).get(e);return t===void 0?void 0:$(t)}listAll(){return this.#e.db.prepare(`SELECT * FROM syntheses ORDER BY scope`).all().map($)}markInFlight(e){let t=new Date().toISOString();if(this.#e.db.prepare(`SELECT id FROM syntheses WHERE scope = ?`).get(e)!==void 0)this.#e.db.prepare(`UPDATE syntheses SET in_flight_since = ?, updated_at = ? WHERE scope = ?`).run(t,t,e);else{let n=(0,l.randomUUID)(),r=new Date(Date.now()+720*60*60*1e3).toISOString();this.#e.db.prepare(`INSERT INTO syntheses
307
348
  (id, scope, content, source_memory_hash, synthesized_at, expires_at,
308
349
  in_flight_since, created_at, updated_at)
309
350
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(n,e,`pending`,``,t,r,t,t,t)}}clearInFlight(e){let t=new Date().toISOString();this.#e.db.prepare(`UPDATE syntheses SET in_flight_since = NULL, updated_at = ? WHERE scope = ?`).run(t,e)}clearStaleInFlight(e){let t=new Date(Date.now()-e).toISOString(),n=new Date().toISOString();this.#e.db.prepare(`UPDATE syntheses SET in_flight_since = NULL, updated_at = ? WHERE in_flight_since IS NOT NULL AND in_flight_since < ?`).run(n,t)}computeSourceMemoryHash(e){let t=this.#e.db.prepare(`SELECT m.content FROM memories m
310
351
  JOIN memory_projects mp ON mp.memory_id = m.id
311
352
  JOIN projects p ON p.id = mp.project_id
312
353
  WHERE p.scope_hash = ?
313
- ORDER BY m.id`).all(e);return(0,c.createHash)(`sha256`).update(JSON.stringify(t.map(e=>e.content))).digest(`hex`)}getExpiredOrDirtyScopes(){let e=this.getAllActiveScopes(),t=new Date().toISOString(),n=[];for(let r of e){let e=this.#e.db.prepare(`SELECT * FROM syntheses WHERE scope = ?`).get(r);if(e===void 0||e.content===`pending`&&e.source_memory_hash===``){n.push({scope:r,reason:`missing`});continue}if(e.expires_at<=t){n.push({scope:r,reason:`expired`});continue}this.computeSourceMemoryHash(r)!==e.source_memory_hash&&n.push({scope:r,reason:`dirty`})}return n}getAllActiveScopes(){return this.#e.db.prepare(`SELECT DISTINCT scope_hash FROM projects`).all().map(e=>e.scope_hash)}expireStale(){let e=new Date().toISOString();this.#e.db.prepare(`DELETE FROM syntheses WHERE expires_at < ?`).run(e)}};function Qe(e){return new Ze(e)}exports.ACTIVITY_EVENT_TYPE_VALUES=_,exports.ActivityEventTypeSchema=v,exports.DatabaseError=z,exports.DatabaseManager=me,exports.EmbeddingService=_e,exports.GLOBAL_PROJECT_ID=U,exports.GLOBAL_PROJECT_NAME=G,exports.GLOBAL_SCOPE_HASH=W,exports.MEMORY_TYPE_VALUES=S,exports.MIGRATIONS=Le,exports.MODEL_NAME=B,exports.MembankError=R,exports.MemoryPatchSchema=j,exports.MemoryRowSchema=N,exports.MemorySchema=k,exports.MemoryTypeSchema=C,exports.ModelDownloadError=V,exports.ModelDownloader=ge,exports.PIN_BUDGET_THRESHOLD=K,exports.ProjectRowSchema=P,exports.ProjectSchema=T,exports.QueryEngine=We,exports.QueryOptionsSchema=A,exports.RETENTION_DAYS=30,exports.ReviewEventRowSchema=O,exports.ReviewEventSchema=D,exports.ReviewReasonSchema=E,exports.SaveOptionsSchema=ue,exports.SessionContextBuilder=Ke,exports.SessionContextSchema=de,exports.SqliteMemoryRepository=q,exports.SynthesisEngine=qe,exports.SynthesisSchema=M,exports.TagsJsonSchema=w,exports.createActivityLogger=se,exports.createActivityRepository=oe,exports.createClaudeCodeTranscriptReader=Oe,exports.createExtractionAgentRunner=xe,exports.createExtractionRunRepository=Te,exports.createMemoryRepository=Fe,exports.createProjectRepository=Be,exports.createSynthesisAgentRunner=Xe,exports.createSynthesisRepository=Qe,exports.deleteMemory=ke,exports.getSessionContext=Q,exports.isOverBudget=Pe,exports.isSynthesisEnabled=le,exports.listEvents=ie,exports.listMemoryTypes=Ge,exports.logEvent=y,exports.noopActivityLogger=x,exports.queryMemories=Z,exports.resolveProject=X,exports.resolveReview=Ae,exports.resolveScope=Ie,exports.rowToMemory=F,exports.rowToProject=L,exports.runExtraction=ve,exports.runScopeToProjectsMigration=Re,exports.runSynthesis=Je,exports.saveMemory=Me,exports.updateMemory=Ne;
354
+ ORDER BY m.id`).all(e);return(0,l.createHash)(`sha256`).update(JSON.stringify(t.map(e=>e.content))).digest(`hex`)}getExpiredOrDirtyScopes(){let e=this.getAllActiveScopes(),t=new Date().toISOString(),n=[];for(let r of e){let e=this.#e.db.prepare(`SELECT * FROM syntheses WHERE scope = ?`).get(r);if(e===void 0||e.content===`pending`&&e.source_memory_hash===``){n.push({scope:r,reason:`missing`});continue}if(e.expires_at<=t){n.push({scope:r,reason:`expired`});continue}this.computeSourceMemoryHash(r)!==e.source_memory_hash&&n.push({scope:r,reason:`dirty`})}return n}getAllActiveScopes(){return this.#e.db.prepare(`SELECT DISTINCT scope_hash FROM projects`).all().map(e=>e.scope_hash)}expireStale(){let e=new Date().toISOString();this.#e.db.prepare(`DELETE FROM syntheses WHERE expires_at < ?`).run(e)}};function et(e){return new $e(e)}exports.ACTIVITY_EVENT_TYPE_VALUES=y,exports.ActivityEventTypeSchema=b,exports.DatabaseError=H,exports.DatabaseManager=fe,exports.EmbeddingService=he,exports.GLOBAL_PROJECT_ID=c.t,exports.GLOBAL_PROJECT_NAME=c.n,exports.GLOBAL_SCOPE_HASH=c.r,exports.MEMORY_TYPE_VALUES=w,exports.MIGRATIONS=Re,exports.MODEL_NAME=U,exports.MembankError=V,exports.MemoryPatchSchema=P,exports.MemoryRowSchema=I,exports.MemorySchema=j,exports.MemoryTypeSchema=T,exports.ModelDownloadError=W,exports.ModelDownloader=me,exports.PIN_BUDGET_THRESHOLD=J,exports.ProjectRowSchema=L,exports.ProjectSchema=D,exports.QueryEngine=Ke,exports.QueryOptionsSchema=M,exports.RETENTION_DAYS=30,exports.ReviewEventRowSchema=A,exports.ReviewEventSchema=k,exports.ReviewReasonSchema=O,exports.SaveOptionsSchema=N,exports.SessionContextBuilder=Je,exports.SessionContextSchema=le,exports.SqliteMemoryRepository=Y,exports.SynthesisEngine=Ye,exports.SynthesisSchema=F,exports.TagsJsonSchema=E,exports.clusterFlagged=De,exports.createActivityLogger=oe,exports.createActivityRepository=ae,exports.createClaudeCodeTranscriptReader=Ee,exports.createExtractionAgentRunner=ye,exports.createExtractionRunRepository=Ce,exports.createMemoryRepository=Fe,exports.createProjectRepository=Ve,exports.createSynthesisAgentRunner=Qe,exports.createSynthesisRepository=et,exports.deleteManyMemories=Oe,exports.deleteMemory=K,exports.getSessionContext=Q,exports.isOverBudget=Pe,exports.isSynthesisEnabled=ce,exports.listEvents=re,exports.listMemoryTypes=qe,exports.logEvent=x,exports.mergeMemories=ke,exports.noopActivityLogger=C,exports.queryMemories=We,exports.resolveProject=Ie,exports.resolveReview=Ae,exports.resolveReviewMany=je,exports.resolveScope=Le,exports.rowToMemory=R,exports.rowToProject=B,exports.runExtraction=ge,exports.runScopeToProjectsMigration=ze,exports.runSynthesis=Xe,exports.saveMemory=Me,exports.updateMemory=Ne;
package/dist/index.d.cts CHANGED
@@ -1,3 +1,4 @@
1
+ import { n as GLOBAL_PROJECT_NAME, r as GLOBAL_SCOPE_HASH, t as GLOBAL_PROJECT_ID } from "./global-scope-Bv4l3n3S.cjs";
1
2
  import { z } from "zod";
2
3
  import BetterSqlite3 from "better-sqlite3";
3
4
  import { EventEmitter } from "node:events";
@@ -393,6 +394,26 @@ interface StatsResult {
393
394
  needsReview: number;
394
395
  pinBudgetChars: number;
395
396
  }
397
+ interface ReviewQueueStats {
398
+ pairs: number;
399
+ clusters: number;
400
+ byBand: {
401
+ high: number;
402
+ mid: number;
403
+ low: number;
404
+ };
405
+ byType: Partial<Record<MemoryType, number>>;
406
+ }
407
+ interface BulkOpResult {
408
+ id: string;
409
+ status: "ok" | "error";
410
+ error?: string;
411
+ }
412
+ interface MergeMemoriesOpts {
413
+ keepId: string;
414
+ dropIds: string[];
415
+ mergedContent: string;
416
+ }
396
417
  interface MemoryExportRecord {
397
418
  id: string;
398
419
  content: string;
@@ -425,6 +446,7 @@ interface CreateReviewEventOpts {
425
446
  }
426
447
  interface MemoryRepository {
427
448
  findById(id: string): Memory | undefined;
449
+ findManyById(ids: string[]): Memory[];
428
450
  findSimilar(embedding: Float32Array, type: MemoryType, projectHash?: string): SimilarMemoryResult[];
429
451
  list(opts?: {
430
452
  type?: MemoryType;
@@ -434,12 +456,22 @@ interface MemoryRepository {
434
456
  }): Memory[];
435
457
  listPinnedGlobal(): Memory[];
436
458
  listPinnedForProject(projectHash: string): Memory[];
437
- listFlagged(projectHash?: string): Memory[];
459
+ listFlagged(opts?: {
460
+ projectHash?: string;
461
+ limit?: number;
462
+ minSimilarity?: number;
463
+ maxSimilarity?: number;
464
+ }): Memory[];
465
+ listReviewEdges(projectHash?: string): Array<{
466
+ memoryId: string;
467
+ conflictingMemoryId: string;
468
+ }>;
438
469
  listReviewEvents(memoryId: string, opts?: {
439
470
  unresolvedOnly?: boolean;
440
471
  }): ReviewEvent[];
441
472
  getPinnedCharCount(projectHash?: string): number;
442
473
  stats(projectHash?: string): StatsResult;
474
+ reviewQueueStats(projectHash?: string): Omit<ReviewQueueStats, "clusters">;
443
475
  create(opts: CreateMemoryOpts): Memory;
444
476
  overwrite(id: string, content: string, embedding: Float32Array): Memory;
445
477
  update(id: string, patch: MemoryPatch, embedding?: Float32Array): Memory;
@@ -559,12 +591,39 @@ interface TranscriptReaderOptions {
559
591
  }
560
592
  declare function createClaudeCodeTranscriptReader(opts?: TranscriptReaderOptions): TranscriptReader;
561
593
  //#endregion
594
+ //#region src/memory/application/cluster-flagged.d.ts
595
+ interface FlagCluster {
596
+ clusterId: string;
597
+ memoryIds: string[];
598
+ }
599
+ declare function clusterFlagged(edges: Array<{
600
+ memoryId: string;
601
+ conflictingMemoryId: string;
602
+ }>): FlagCluster[];
603
+ //#endregion
604
+ //#region src/memory/application/delete-many.d.ts
605
+ declare function deleteManyMemories(ids: string[], repo: MemoryRepository, activityLogger?: ActivityLogger): Promise<BulkOpResult[]>;
606
+ //#endregion
562
607
  //#region src/memory/application/delete-memory.d.ts
563
608
  declare function deleteMemory(id: string, repo: MemoryRepository, activityLogger?: ActivityLogger): Promise<void>;
564
609
  //#endregion
610
+ //#region src/memory/application/merge-memories.d.ts
611
+ interface MergeMemoriesResult {
612
+ kept: Memory;
613
+ dropped: string[];
614
+ }
615
+ declare function mergeMemories(opts: MergeMemoriesOpts, deps: {
616
+ repo: MemoryRepository;
617
+ embedder: Embedder;
618
+ activityLogger?: ActivityLogger;
619
+ }): Promise<MergeMemoriesResult>;
620
+ //#endregion
565
621
  //#region src/memory/application/resolve-review.d.ts
566
622
  declare function resolveReview(memoryId: string, repo: MemoryRepository): void;
567
623
  //#endregion
624
+ //#region src/memory/application/resolve-review-many.d.ts
625
+ declare function resolveReviewMany(ids: string[], repo: MemoryRepository): BulkOpResult[];
626
+ //#endregion
568
627
  //#region src/memory/application/save-memory.d.ts
569
628
  declare function saveMemory(opts: SaveOptions, deps: {
570
629
  repo: MemoryRepository;
@@ -604,6 +663,7 @@ declare class SqliteMemoryRepository implements MemoryRepository {
604
663
  create(opts: CreateMemoryOpts): Memory;
605
664
  overwrite(id: string, content: string, embedding: Float32Array): Memory;
606
665
  findById(id: string): Memory | undefined;
666
+ findManyById(ids: string[]): Memory[];
607
667
  update(id: string, patch: MemoryPatch, embedding?: Float32Array): Memory;
608
668
  delete(id: string): void;
609
669
  list(opts?: {
@@ -614,7 +674,16 @@ declare class SqliteMemoryRepository implements MemoryRepository {
614
674
  }): Memory[];
615
675
  listPinnedGlobal(): Memory[];
616
676
  listPinnedForProject(projectHash: string): Memory[];
617
- listFlagged(projectHash?: string): Memory[];
677
+ listFlagged(opts?: {
678
+ projectHash?: string;
679
+ limit?: number;
680
+ minSimilarity?: number;
681
+ maxSimilarity?: number;
682
+ }): Memory[];
683
+ listReviewEdges(projectHash?: string): Array<{
684
+ memoryId: string;
685
+ conflictingMemoryId: string;
686
+ }>;
618
687
  listReviewEvents(memoryId: string, opts?: {
619
688
  unresolvedOnly?: boolean;
620
689
  }): ReviewEvent[];
@@ -622,6 +691,7 @@ declare class SqliteMemoryRepository implements MemoryRepository {
622
691
  resolveReviewEvents(memoryId: string): void;
623
692
  getPinnedCharCount(projectHash?: string): number;
624
693
  stats(projectHash?: string): StatsResult;
694
+ reviewQueueStats(projectHash?: string): Omit<ReviewQueueStats, "clusters">;
625
695
  setPin(id: string, pinned: boolean): Memory;
626
696
  incrementAccessCount(id: string): void;
627
697
  exportAll(): MemoryExportRecord[];
@@ -629,11 +699,6 @@ declare class SqliteMemoryRepository implements MemoryRepository {
629
699
  }
630
700
  declare function createMemoryRepository(db: DatabaseManager, projects: ProjectRepository): MemoryRepository;
631
701
  //#endregion
632
- //#region src/project/domain/global-scope.d.ts
633
- declare const GLOBAL_PROJECT_ID: "00000000-0000-0000-0000-000000000000";
634
- declare const GLOBAL_SCOPE_HASH: "0000000000000000";
635
- declare const GLOBAL_PROJECT_NAME: "global";
636
- //#endregion
637
702
  //#region src/project/infrastructure/sqlite-project-repository.d.ts
638
703
  declare function createProjectRepository(db: DatabaseManager): ProjectRepository;
639
704
  //#endregion
@@ -767,5 +832,5 @@ declare function createSynthesisAgentRunner(tools: SynthesisTools, config: Synth
767
832
  //#region src/synthesis/infrastructure/sqlite-synthesis-repository.d.ts
768
833
  declare function createSynthesisRepository(db: DatabaseManager): SynthesisRepository;
769
834
  //#endregion
770
- export { ACTIVITY_EVENT_TYPE_VALUES, type ActivityEvent, type ActivityEventInput, type ActivityEventType, ActivityEventTypeSchema, type ActivityLogger, type ActivityRepository, type AgentRunner, type CreateMemoryOpts, type CreateReviewEventOpts, DatabaseError, DatabaseManager, type DownloadProgress, type DownloadResult, type Embedder, EmbeddingService, type ExtractionAgentRunner, type ExtractionConfig, type ExtractionRunRecord, type ExtractionRunRepository, type ExtractionTools, GLOBAL_PROJECT_ID, GLOBAL_PROJECT_NAME, GLOBAL_SCOPE_HASH, type ListEventsFilter, MEMORY_TYPE_VALUES, MIGRATIONS, MODEL_NAME, MembankError, type Memory, type MemoryExportRecord, type MemoryPatch, MemoryPatchSchema, type MemoryRepository, type MemoryRow, MemoryRowSchema, MemorySchema, type MemoryType, MemoryTypeSchema, MigrationMeta, ModelDownloadError, ModelDownloader, PIN_BUDGET_THRESHOLD, type ProgressCallback, Project, type ProjectRepository, ProjectRow, ProjectRowSchema, ProjectSchema, type Querier, type QueryAdapter, QueryEngine, QueryOptions, QueryOptionsSchema, RETENTION_DAYS, type ReviewEvent, type ReviewEventRow, ReviewEventRowSchema, ReviewEventSchema, ReviewReason, ReviewReasonSchema, type RunExtractionInput, type RunExtractionResult, type SaveOptions, SaveOptionsSchema, ScopeToProjectsResult, type ScoredMemory, SessionContext, SessionContextBuilder, SessionContextSchema, type SimilarMemoryResult, SqliteMemoryRepository, type StatsResult, Synthesis, type SynthesisConfig, SynthesisEngine, type SynthesisRepository, SynthesisSchema, type SynthesisTools, TagsJsonSchema, type TranscriptReader, createActivityLogger, createActivityRepository, createClaudeCodeTranscriptReader, createExtractionAgentRunner, createExtractionRunRepository, createMemoryRepository, createProjectRepository, createSynthesisAgentRunner, createSynthesisRepository, deleteMemory, getSessionContext, isOverBudget, isSynthesisEnabled, listEvents, listMemoryTypes, logEvent, noopActivityLogger, queryMemories, resolveProject, resolveReview, resolveScope, rowToMemory, rowToProject, runExtraction, runScopeToProjectsMigration, runSynthesis, saveMemory, updateMemory };
835
+ export { ACTIVITY_EVENT_TYPE_VALUES, type ActivityEvent, type ActivityEventInput, type ActivityEventType, ActivityEventTypeSchema, type ActivityLogger, type ActivityRepository, type AgentRunner, type BulkOpResult, type CreateMemoryOpts, type CreateReviewEventOpts, DatabaseError, DatabaseManager, type DownloadProgress, type DownloadResult, type Embedder, EmbeddingService, type ExtractionAgentRunner, type ExtractionConfig, type ExtractionRunRecord, type ExtractionRunRepository, type ExtractionTools, type FlagCluster, GLOBAL_PROJECT_ID, GLOBAL_PROJECT_NAME, GLOBAL_SCOPE_HASH, type ListEventsFilter, MEMORY_TYPE_VALUES, MIGRATIONS, MODEL_NAME, MembankError, type Memory, type MemoryExportRecord, type MemoryPatch, MemoryPatchSchema, type MemoryRepository, type MemoryRow, MemoryRowSchema, MemorySchema, type MemoryType, MemoryTypeSchema, type MergeMemoriesOpts, type MergeMemoriesResult, MigrationMeta, ModelDownloadError, ModelDownloader, PIN_BUDGET_THRESHOLD, type ProgressCallback, Project, type ProjectRepository, ProjectRow, ProjectRowSchema, ProjectSchema, type Querier, type QueryAdapter, QueryEngine, QueryOptions, QueryOptionsSchema, RETENTION_DAYS, type ReviewEvent, type ReviewEventRow, ReviewEventRowSchema, ReviewEventSchema, type ReviewQueueStats, ReviewReason, ReviewReasonSchema, type RunExtractionInput, type RunExtractionResult, type SaveOptions, SaveOptionsSchema, ScopeToProjectsResult, type ScoredMemory, SessionContext, SessionContextBuilder, SessionContextSchema, type SimilarMemoryResult, SqliteMemoryRepository, type StatsResult, Synthesis, type SynthesisConfig, SynthesisEngine, type SynthesisRepository, SynthesisSchema, type SynthesisTools, TagsJsonSchema, type TranscriptReader, clusterFlagged, createActivityLogger, createActivityRepository, createClaudeCodeTranscriptReader, createExtractionAgentRunner, createExtractionRunRepository, createMemoryRepository, createProjectRepository, createSynthesisAgentRunner, createSynthesisRepository, deleteManyMemories, deleteMemory, getSessionContext, isOverBudget, isSynthesisEnabled, listEvents, listMemoryTypes, logEvent, mergeMemories, noopActivityLogger, queryMemories, resolveProject, resolveReview, resolveReviewMany, resolveScope, rowToMemory, rowToProject, runExtraction, runScopeToProjectsMigration, runSynthesis, saveMemory, updateMemory };
771
836
  //# sourceMappingURL=index.d.cts.map
package/dist/index.d.mts CHANGED
@@ -1,3 +1,4 @@
1
+ import { n as GLOBAL_PROJECT_NAME, r as GLOBAL_SCOPE_HASH, t as GLOBAL_PROJECT_ID } from "./global-scope-lgsTOiAt.mjs";
1
2
  import { z } from "zod";
2
3
  import BetterSqlite3 from "better-sqlite3";
3
4
  import { EventEmitter } from "node:events";
@@ -393,6 +394,26 @@ interface StatsResult {
393
394
  needsReview: number;
394
395
  pinBudgetChars: number;
395
396
  }
397
+ interface ReviewQueueStats {
398
+ pairs: number;
399
+ clusters: number;
400
+ byBand: {
401
+ high: number;
402
+ mid: number;
403
+ low: number;
404
+ };
405
+ byType: Partial<Record<MemoryType, number>>;
406
+ }
407
+ interface BulkOpResult {
408
+ id: string;
409
+ status: "ok" | "error";
410
+ error?: string;
411
+ }
412
+ interface MergeMemoriesOpts {
413
+ keepId: string;
414
+ dropIds: string[];
415
+ mergedContent: string;
416
+ }
396
417
  interface MemoryExportRecord {
397
418
  id: string;
398
419
  content: string;
@@ -425,6 +446,7 @@ interface CreateReviewEventOpts {
425
446
  }
426
447
  interface MemoryRepository {
427
448
  findById(id: string): Memory | undefined;
449
+ findManyById(ids: string[]): Memory[];
428
450
  findSimilar(embedding: Float32Array, type: MemoryType, projectHash?: string): SimilarMemoryResult[];
429
451
  list(opts?: {
430
452
  type?: MemoryType;
@@ -434,12 +456,22 @@ interface MemoryRepository {
434
456
  }): Memory[];
435
457
  listPinnedGlobal(): Memory[];
436
458
  listPinnedForProject(projectHash: string): Memory[];
437
- listFlagged(projectHash?: string): Memory[];
459
+ listFlagged(opts?: {
460
+ projectHash?: string;
461
+ limit?: number;
462
+ minSimilarity?: number;
463
+ maxSimilarity?: number;
464
+ }): Memory[];
465
+ listReviewEdges(projectHash?: string): Array<{
466
+ memoryId: string;
467
+ conflictingMemoryId: string;
468
+ }>;
438
469
  listReviewEvents(memoryId: string, opts?: {
439
470
  unresolvedOnly?: boolean;
440
471
  }): ReviewEvent[];
441
472
  getPinnedCharCount(projectHash?: string): number;
442
473
  stats(projectHash?: string): StatsResult;
474
+ reviewQueueStats(projectHash?: string): Omit<ReviewQueueStats, "clusters">;
443
475
  create(opts: CreateMemoryOpts): Memory;
444
476
  overwrite(id: string, content: string, embedding: Float32Array): Memory;
445
477
  update(id: string, patch: MemoryPatch, embedding?: Float32Array): Memory;
@@ -559,12 +591,39 @@ interface TranscriptReaderOptions {
559
591
  }
560
592
  declare function createClaudeCodeTranscriptReader(opts?: TranscriptReaderOptions): TranscriptReader;
561
593
  //#endregion
594
+ //#region src/memory/application/cluster-flagged.d.ts
595
+ interface FlagCluster {
596
+ clusterId: string;
597
+ memoryIds: string[];
598
+ }
599
+ declare function clusterFlagged(edges: Array<{
600
+ memoryId: string;
601
+ conflictingMemoryId: string;
602
+ }>): FlagCluster[];
603
+ //#endregion
604
+ //#region src/memory/application/delete-many.d.ts
605
+ declare function deleteManyMemories(ids: string[], repo: MemoryRepository, activityLogger?: ActivityLogger): Promise<BulkOpResult[]>;
606
+ //#endregion
562
607
  //#region src/memory/application/delete-memory.d.ts
563
608
  declare function deleteMemory(id: string, repo: MemoryRepository, activityLogger?: ActivityLogger): Promise<void>;
564
609
  //#endregion
610
+ //#region src/memory/application/merge-memories.d.ts
611
+ interface MergeMemoriesResult {
612
+ kept: Memory;
613
+ dropped: string[];
614
+ }
615
+ declare function mergeMemories(opts: MergeMemoriesOpts, deps: {
616
+ repo: MemoryRepository;
617
+ embedder: Embedder;
618
+ activityLogger?: ActivityLogger;
619
+ }): Promise<MergeMemoriesResult>;
620
+ //#endregion
565
621
  //#region src/memory/application/resolve-review.d.ts
566
622
  declare function resolveReview(memoryId: string, repo: MemoryRepository): void;
567
623
  //#endregion
624
+ //#region src/memory/application/resolve-review-many.d.ts
625
+ declare function resolveReviewMany(ids: string[], repo: MemoryRepository): BulkOpResult[];
626
+ //#endregion
568
627
  //#region src/memory/application/save-memory.d.ts
569
628
  declare function saveMemory(opts: SaveOptions, deps: {
570
629
  repo: MemoryRepository;
@@ -604,6 +663,7 @@ declare class SqliteMemoryRepository implements MemoryRepository {
604
663
  create(opts: CreateMemoryOpts): Memory;
605
664
  overwrite(id: string, content: string, embedding: Float32Array): Memory;
606
665
  findById(id: string): Memory | undefined;
666
+ findManyById(ids: string[]): Memory[];
607
667
  update(id: string, patch: MemoryPatch, embedding?: Float32Array): Memory;
608
668
  delete(id: string): void;
609
669
  list(opts?: {
@@ -614,7 +674,16 @@ declare class SqliteMemoryRepository implements MemoryRepository {
614
674
  }): Memory[];
615
675
  listPinnedGlobal(): Memory[];
616
676
  listPinnedForProject(projectHash: string): Memory[];
617
- listFlagged(projectHash?: string): Memory[];
677
+ listFlagged(opts?: {
678
+ projectHash?: string;
679
+ limit?: number;
680
+ minSimilarity?: number;
681
+ maxSimilarity?: number;
682
+ }): Memory[];
683
+ listReviewEdges(projectHash?: string): Array<{
684
+ memoryId: string;
685
+ conflictingMemoryId: string;
686
+ }>;
618
687
  listReviewEvents(memoryId: string, opts?: {
619
688
  unresolvedOnly?: boolean;
620
689
  }): ReviewEvent[];
@@ -622,6 +691,7 @@ declare class SqliteMemoryRepository implements MemoryRepository {
622
691
  resolveReviewEvents(memoryId: string): void;
623
692
  getPinnedCharCount(projectHash?: string): number;
624
693
  stats(projectHash?: string): StatsResult;
694
+ reviewQueueStats(projectHash?: string): Omit<ReviewQueueStats, "clusters">;
625
695
  setPin(id: string, pinned: boolean): Memory;
626
696
  incrementAccessCount(id: string): void;
627
697
  exportAll(): MemoryExportRecord[];
@@ -629,11 +699,6 @@ declare class SqliteMemoryRepository implements MemoryRepository {
629
699
  }
630
700
  declare function createMemoryRepository(db: DatabaseManager, projects: ProjectRepository): MemoryRepository;
631
701
  //#endregion
632
- //#region src/project/domain/global-scope.d.ts
633
- declare const GLOBAL_PROJECT_ID: "00000000-0000-0000-0000-000000000000";
634
- declare const GLOBAL_SCOPE_HASH: "0000000000000000";
635
- declare const GLOBAL_PROJECT_NAME: "global";
636
- //#endregion
637
702
  //#region src/project/infrastructure/sqlite-project-repository.d.ts
638
703
  declare function createProjectRepository(db: DatabaseManager): ProjectRepository;
639
704
  //#endregion
@@ -767,5 +832,5 @@ declare function createSynthesisAgentRunner(tools: SynthesisTools, config: Synth
767
832
  //#region src/synthesis/infrastructure/sqlite-synthesis-repository.d.ts
768
833
  declare function createSynthesisRepository(db: DatabaseManager): SynthesisRepository;
769
834
  //#endregion
770
- export { ACTIVITY_EVENT_TYPE_VALUES, type ActivityEvent, type ActivityEventInput, type ActivityEventType, ActivityEventTypeSchema, type ActivityLogger, type ActivityRepository, type AgentRunner, type CreateMemoryOpts, type CreateReviewEventOpts, DatabaseError, DatabaseManager, type DownloadProgress, type DownloadResult, type Embedder, EmbeddingService, type ExtractionAgentRunner, type ExtractionConfig, type ExtractionRunRecord, type ExtractionRunRepository, type ExtractionTools, GLOBAL_PROJECT_ID, GLOBAL_PROJECT_NAME, GLOBAL_SCOPE_HASH, type ListEventsFilter, MEMORY_TYPE_VALUES, MIGRATIONS, MODEL_NAME, MembankError, type Memory, type MemoryExportRecord, type MemoryPatch, MemoryPatchSchema, type MemoryRepository, type MemoryRow, MemoryRowSchema, MemorySchema, type MemoryType, MemoryTypeSchema, MigrationMeta, ModelDownloadError, ModelDownloader, PIN_BUDGET_THRESHOLD, type ProgressCallback, Project, type ProjectRepository, ProjectRow, ProjectRowSchema, ProjectSchema, type Querier, type QueryAdapter, QueryEngine, QueryOptions, QueryOptionsSchema, RETENTION_DAYS, type ReviewEvent, type ReviewEventRow, ReviewEventRowSchema, ReviewEventSchema, ReviewReason, ReviewReasonSchema, type RunExtractionInput, type RunExtractionResult, type SaveOptions, SaveOptionsSchema, ScopeToProjectsResult, type ScoredMemory, SessionContext, SessionContextBuilder, SessionContextSchema, type SimilarMemoryResult, SqliteMemoryRepository, type StatsResult, Synthesis, type SynthesisConfig, SynthesisEngine, type SynthesisRepository, SynthesisSchema, type SynthesisTools, TagsJsonSchema, type TranscriptReader, createActivityLogger, createActivityRepository, createClaudeCodeTranscriptReader, createExtractionAgentRunner, createExtractionRunRepository, createMemoryRepository, createProjectRepository, createSynthesisAgentRunner, createSynthesisRepository, deleteMemory, getSessionContext, isOverBudget, isSynthesisEnabled, listEvents, listMemoryTypes, logEvent, noopActivityLogger, queryMemories, resolveProject, resolveReview, resolveScope, rowToMemory, rowToProject, runExtraction, runScopeToProjectsMigration, runSynthesis, saveMemory, updateMemory };
835
+ export { ACTIVITY_EVENT_TYPE_VALUES, type ActivityEvent, type ActivityEventInput, type ActivityEventType, ActivityEventTypeSchema, type ActivityLogger, type ActivityRepository, type AgentRunner, type BulkOpResult, type CreateMemoryOpts, type CreateReviewEventOpts, DatabaseError, DatabaseManager, type DownloadProgress, type DownloadResult, type Embedder, EmbeddingService, type ExtractionAgentRunner, type ExtractionConfig, type ExtractionRunRecord, type ExtractionRunRepository, type ExtractionTools, type FlagCluster, GLOBAL_PROJECT_ID, GLOBAL_PROJECT_NAME, GLOBAL_SCOPE_HASH, type ListEventsFilter, MEMORY_TYPE_VALUES, MIGRATIONS, MODEL_NAME, MembankError, type Memory, type MemoryExportRecord, type MemoryPatch, MemoryPatchSchema, type MemoryRepository, type MemoryRow, MemoryRowSchema, MemorySchema, type MemoryType, MemoryTypeSchema, type MergeMemoriesOpts, type MergeMemoriesResult, MigrationMeta, ModelDownloadError, ModelDownloader, PIN_BUDGET_THRESHOLD, type ProgressCallback, Project, type ProjectRepository, ProjectRow, ProjectRowSchema, ProjectSchema, type Querier, type QueryAdapter, QueryEngine, QueryOptions, QueryOptionsSchema, RETENTION_DAYS, type ReviewEvent, type ReviewEventRow, ReviewEventRowSchema, ReviewEventSchema, type ReviewQueueStats, ReviewReason, ReviewReasonSchema, type RunExtractionInput, type RunExtractionResult, type SaveOptions, SaveOptionsSchema, ScopeToProjectsResult, type ScoredMemory, SessionContext, SessionContextBuilder, SessionContextSchema, type SimilarMemoryResult, SqliteMemoryRepository, type StatsResult, Synthesis, type SynthesisConfig, SynthesisEngine, type SynthesisRepository, SynthesisSchema, type SynthesisTools, TagsJsonSchema, type TranscriptReader, clusterFlagged, createActivityLogger, createActivityRepository, createClaudeCodeTranscriptReader, createExtractionAgentRunner, createExtractionRunRepository, createMemoryRepository, createProjectRepository, createSynthesisAgentRunner, createSynthesisRepository, deleteManyMemories, deleteMemory, getSessionContext, isOverBudget, isSynthesisEnabled, listEvents, listMemoryTypes, logEvent, mergeMemories, noopActivityLogger, queryMemories, resolveProject, resolveReview, resolveReviewMany, resolveScope, rowToMemory, rowToProject, runExtraction, runScopeToProjectsMigration, runSynthesis, saveMemory, updateMemory };
771
836
  //# sourceMappingURL=index.d.mts.map
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import{createHash as e,randomUUID as t}from"node:crypto";import{z as n}from"zod";import{existsSync as r,mkdirSync as i,readFileSync as a,readdirSync as o}from"node:fs";import{homedir as s}from"node:os";import{dirname as c,join as l}from"node:path";import u from"better-sqlite3";import*as d from"sqlite-vec";import{EventEmitter as f}from"node:events";import{pipeline as p}from"@huggingface/transformers";import{createSdkMcpServer as m,query as h,tool as g}from"@anthropic-ai/claude-agent-sdk";import{readFile as ee}from"node:fs/promises";import{execFile as te}from"node:child_process";import{promisify as ne}from"node:util";function re(e,t){return t.list(e)}const _=[`memory.created`,`memory.updated`,`memory.deleted`,`memory.flagged`,`memory.queried`],v=n.enum(_),ie=30;function y(e,n){let r=new Date,i=r.toISOString();n.insert({id:t(),projectHash:e.projectHash,eventType:e.eventType,memoryId:e.memoryId??null,payload:e.payload??{},createdAt:i});let a=new Date(r);a.setDate(a.getDate()-30),n.prune(a.toISOString())}function ae(e){return{id:e.id,projectHash:e.project_hash,eventType:v.parse(e.event_type),memoryId:e.memory_id,payload:JSON.parse(e.payload),createdAt:e.created_at}}var b=class{#e;#t=0;#n;#r;constructor(e){this.#e=e,this.#n=e.db.prepare(`INSERT INTO activity_events (id, project_hash, event_type, memory_id, payload, created_at)
2
- VALUES (?, ?, ?, ?, ?, ?)`),this.#r=e.db.prepare(`DELETE FROM activity_events WHERE created_at < ?`)}insert(e){this.#n.run(e.id,e.projectHash,e.eventType,e.memoryId,JSON.stringify(e.payload),e.createdAt)}list(e){let t=[],n=[];e.scope!==void 0&&(t.push(`project_hash = ?`),n.push(e.scope)),e.type!==void 0&&(t.push(`event_type = ?`),n.push(e.type)),e.since!==void 0&&(t.push(`created_at >= ?`),n.push(e.since));let r=t.length>0?`WHERE ${t.join(` AND `)}`:``,i=e.limit===void 0?``:`LIMIT ?`;return e.limit!==void 0&&n.push(e.limit),this.#e.db.prepare(`SELECT * FROM activity_events ${r} ORDER BY created_at DESC ${i}`).all(...n).map(ae)}prune(e){let t=Date.now();t-this.#t<6e4||(this.#r.run(e),this.#t=t)}};function oe(e){return new b(e)}function se(e){let t=new b(e);return{logEvent:e=>y(e,t)}}const x={logEvent(){}};function ce(){let e=l(s(),`.membank`,`config.json`);try{let t=a(e,`utf8`);return JSON.parse(t)}catch{return null}}function le(){return ce()?.synthesis?.enabled===!0}const S=[`correction`,`preference`,`decision`,`learning`,`fact`],C=n.enum(S),w=n.array(n.string()),T=n.object({id:n.string(),name:n.string(),scopeHash:n.string(),createdAt:n.string(),updatedAt:n.string()}),E=n.enum([`similarity_dedup`]),D=n.object({id:n.string(),memoryId:n.string(),conflictingMemoryId:n.string().nullable(),similarity:n.number(),conflictContentSnapshot:n.string(),reason:E,createdAt:n.string(),resolvedAt:n.string().nullable()}),O=n.object({id:n.string(),memory_id:n.string(),conflicting_memory_id:n.string().nullable(),similarity:n.number(),conflict_content_snapshot:n.string(),reason:E,created_at:n.string(),resolved_at:n.string().nullable()}),k=n.object({id:n.string(),content:n.string(),type:C,tags:n.array(n.string()),projects:n.array(T),sourceHarness:n.string().nullable(),accessCount:n.number().int().nonnegative(),pinned:n.boolean(),reviewEvents:n.array(D),createdAt:n.string(),updatedAt:n.string()}),A=n.object({query:n.string().min(1),type:C.optional(),projectHash:n.string().optional(),limit:n.number().int().positive().optional(),includePinned:n.boolean().optional()}),ue=n.object({content:n.string().min(1),type:C,tags:n.array(n.string()).optional(),projectScope:n.object({hash:n.string(),name:n.string()}).optional(),sourceHarness:n.string().optional()}),j=n.object({content:n.string().min(1).optional(),tags:n.array(n.string()).optional(),type:C.optional()}),M=n.object({id:n.string(),scope:n.string(),content:n.string(),sourceMemoryHash:n.string(),synthesizedAt:n.string(),expiresAt:n.string(),inFlightSince:n.string().nullable(),createdAt:n.string(),updatedAt:n.string()}),de=n.object({stats:n.record(C,n.number()),pinnedGlobal:n.array(k),pinnedProject:n.array(k),synthesis:n.string().optional()}),N=n.object({id:n.string(),content:n.string(),type:n.string(),tags:n.string(),source:n.string().nullable(),access_count:n.number(),pinned:n.number(),created_at:n.string(),updated_at:n.string()}),P=n.object({id:n.string(),name:n.string(),scope_hash:n.string(),created_at:n.string(),updated_at:n.string()});function F(e,t,n=[]){return{id:e.id,content:e.content,type:C.parse(e.type),tags:w.parse(JSON.parse(e.tags)),projects:t,sourceHarness:e.source,accessCount:e.access_count,pinned:e.pinned!==0,reviewEvents:n,createdAt:e.created_at,updatedAt:e.updated_at}}function I(e){let t=O.parse(e);return{id:t.id,memoryId:t.memory_id,conflictingMemoryId:t.conflicting_memory_id,similarity:t.similarity,conflictContentSnapshot:t.conflict_content_snapshot,reason:t.reason,createdAt:t.created_at,resolvedAt:t.resolved_at}}function L(e){return{id:e.id,name:e.name,scopeHash:e.scope_hash,createdAt:e.created_at,updatedAt:e.updated_at}}var R=class extends Error{constructor(e,t){super(e,t),this.name=`MembankError`}},z=class extends R{constructor(e,t){super(e,t),this.name=`DatabaseError`}};const fe=l(s(),`.membank`,`memory.db`),pe=[[1,`
1
+ import{n as e,r as t,t as n}from"./global-scope-B463kRq-.mjs";import{createHash as r,randomUUID as i}from"node:crypto";import{z as a}from"zod";import{existsSync as o,mkdirSync as s,readFileSync as c,readdirSync as l}from"node:fs";import{homedir as u}from"node:os";import{dirname as d,join as f}from"node:path";import p from"better-sqlite3";import*as m from"sqlite-vec";import{EventEmitter as h}from"node:events";import{pipeline as g}from"@huggingface/transformers";import{createSdkMcpServer as _,query as v,tool as y}from"@anthropic-ai/claude-agent-sdk";import{readFile as ee}from"node:fs/promises";import{execFile as te}from"node:child_process";import{promisify as ne}from"node:util";function re(e,t){return t.list(e)}const b=[`memory.created`,`memory.updated`,`memory.deleted`,`memory.flagged`,`memory.queried`],x=a.enum(b),ie=30;function S(e,t){let n=new Date,r=n.toISOString();t.insert({id:i(),projectHash:e.projectHash,eventType:e.eventType,memoryId:e.memoryId??null,payload:e.payload??{},createdAt:r});let a=new Date(n);a.setDate(a.getDate()-30),t.prune(a.toISOString())}function ae(e){return{id:e.id,projectHash:e.project_hash,eventType:x.parse(e.event_type),memoryId:e.memory_id,payload:JSON.parse(e.payload),createdAt:e.created_at}}var C=class{#e;#t=0;#n;#r;constructor(e){this.#e=e,this.#n=e.db.prepare(`INSERT INTO activity_events (id, project_hash, event_type, memory_id, payload, created_at)
2
+ VALUES (?, ?, ?, ?, ?, ?)`),this.#r=e.db.prepare(`DELETE FROM activity_events WHERE created_at < ?`)}insert(e){this.#n.run(e.id,e.projectHash,e.eventType,e.memoryId,JSON.stringify(e.payload),e.createdAt)}list(e){let t=[],n=[];e.scope!==void 0&&(t.push(`project_hash = ?`),n.push(e.scope)),e.type!==void 0&&(t.push(`event_type = ?`),n.push(e.type)),e.since!==void 0&&(t.push(`created_at >= ?`),n.push(e.since));let r=t.length>0?`WHERE ${t.join(` AND `)}`:``,i=e.limit===void 0?``:`LIMIT ?`;return e.limit!==void 0&&n.push(e.limit),this.#e.db.prepare(`SELECT * FROM activity_events ${r} ORDER BY created_at DESC ${i}`).all(...n).map(ae)}prune(e){let t=Date.now();t-this.#t<6e4||(this.#r.run(e),this.#t=t)}};function oe(e){return new C(e)}function se(e){let t=new C(e);return{logEvent:e=>S(e,t)}}const w={logEvent(){}};function ce(){let e=f(u(),`.membank`,`config.json`);try{let t=c(e,`utf8`);return JSON.parse(t)}catch{return null}}function le(){return ce()?.synthesis?.enabled===!0}const T=[`correction`,`preference`,`decision`,`learning`,`fact`],E=a.enum(T),D=a.array(a.string()),O=a.object({id:a.string(),name:a.string(),scopeHash:a.string(),createdAt:a.string(),updatedAt:a.string()}),k=a.enum([`similarity_dedup`]),A=a.object({id:a.string(),memoryId:a.string(),conflictingMemoryId:a.string().nullable(),similarity:a.number(),conflictContentSnapshot:a.string(),reason:k,createdAt:a.string(),resolvedAt:a.string().nullable()}),j=a.object({id:a.string(),memory_id:a.string(),conflicting_memory_id:a.string().nullable(),similarity:a.number(),conflict_content_snapshot:a.string(),reason:k,created_at:a.string(),resolved_at:a.string().nullable()}),M=a.object({id:a.string(),content:a.string(),type:E,tags:a.array(a.string()),projects:a.array(O),sourceHarness:a.string().nullable(),accessCount:a.number().int().nonnegative(),pinned:a.boolean(),reviewEvents:a.array(A),createdAt:a.string(),updatedAt:a.string()}),N=a.object({query:a.string().min(1),type:E.optional(),projectHash:a.string().optional(),limit:a.number().int().positive().optional(),includePinned:a.boolean().optional()}),P=a.object({content:a.string().min(1),type:E,tags:a.array(a.string()).optional(),projectScope:a.object({hash:a.string(),name:a.string()}).optional(),sourceHarness:a.string().optional()}),F=a.object({content:a.string().min(1).optional(),tags:a.array(a.string()).optional(),type:E.optional()}),I=a.object({id:a.string(),scope:a.string(),content:a.string(),sourceMemoryHash:a.string(),synthesizedAt:a.string(),expiresAt:a.string(),inFlightSince:a.string().nullable(),createdAt:a.string(),updatedAt:a.string()}),ue=a.object({stats:a.record(E,a.number()),pinnedGlobal:a.array(M),pinnedProject:a.array(M),synthesis:a.string().optional()}),L=a.object({id:a.string(),content:a.string(),type:a.string(),tags:a.string(),source:a.string().nullable(),access_count:a.number(),pinned:a.number(),created_at:a.string(),updated_at:a.string()}),R=a.object({id:a.string(),name:a.string(),scope_hash:a.string(),created_at:a.string(),updated_at:a.string()});function z(e,t,n=[]){return{id:e.id,content:e.content,type:E.parse(e.type),tags:D.parse(JSON.parse(e.tags)),projects:t,sourceHarness:e.source,accessCount:e.access_count,pinned:e.pinned!==0,reviewEvents:n,createdAt:e.created_at,updatedAt:e.updated_at}}function B(e){let t=j.parse(e);return{id:t.id,memoryId:t.memory_id,conflictingMemoryId:t.conflicting_memory_id,similarity:t.similarity,conflictContentSnapshot:t.conflict_content_snapshot,reason:t.reason,createdAt:t.created_at,resolvedAt:t.resolved_at}}function V(e){return{id:e.id,name:e.name,scopeHash:e.scope_hash,createdAt:e.created_at,updatedAt:e.updated_at}}var H=class extends Error{constructor(e,t){super(e,t),this.name=`MembankError`}},U=class extends H{constructor(e,t){super(e,t),this.name=`DatabaseError`}};const de=f(u(),`.membank`,`memory.db`),fe=[[1,`
3
3
  CREATE TABLE IF NOT EXISTS memories (
4
4
  id TEXT PRIMARY KEY,
5
5
  content TEXT NOT NULL,
@@ -227,14 +227,41 @@ DROP TABLE activity_events_old;
227
227
 
228
228
  CREATE INDEX idx_activity_project_created ON activity_events(project_hash, created_at DESC);
229
229
  CREATE INDEX idx_activity_type_created ON activity_events(event_type, created_at DESC);
230
- `]];var me=class e{#e;constructor(e){this.#e=e}static open(t){let n=t??fe;i(c(n),{recursive:!0});let r=new u(n);return e.#n(r,d.load)}static openInMemory(){return e.#t(d.load)}static _openInMemoryWithLoader(t){return e.#t(t)}static#t(t){let n=new u(`:memory:`);return e.#n(n,t)}static#n(t,n){try{n(t)}catch(e){throw new z(`Failed to load sqlite-vec extension`,{cause:e})}t.pragma(`journal_mode = WAL`),t.pragma(`foreign_keys = ON`);let r=new e(t);return r.#r(),r}#r(){this.#e.exec(`
230
+ `],[11,`
231
+ PRAGMA foreign_keys = OFF;
232
+
233
+ BEGIN;
234
+
235
+ CREATE TABLE memory_review_events_new (
236
+ id TEXT PRIMARY KEY,
237
+ memory_id TEXT NOT NULL REFERENCES memories(id) ON DELETE CASCADE,
238
+ conflicting_memory_id TEXT REFERENCES memories(id) ON DELETE CASCADE,
239
+ similarity REAL NOT NULL,
240
+ conflict_content_snapshot TEXT NOT NULL,
241
+ reason TEXT NOT NULL,
242
+ created_at TEXT NOT NULL,
243
+ resolved_at TEXT
244
+ );
245
+
246
+ INSERT INTO memory_review_events_new SELECT * FROM memory_review_events;
247
+
248
+ DROP TABLE memory_review_events;
249
+ ALTER TABLE memory_review_events_new RENAME TO memory_review_events;
250
+
251
+ CREATE INDEX IF NOT EXISTS idx_review_events_memory_open
252
+ ON memory_review_events(memory_id) WHERE resolved_at IS NULL;
253
+
254
+ COMMIT;
255
+
256
+ PRAGMA foreign_keys = ON;
257
+ `]];var pe=class e{#e;constructor(e){this.#e=e}static open(t){let n=t??de;s(d(n),{recursive:!0});let r=new p(n);return e.#n(r,m.load)}static openInMemory(){return e.#t(m.load)}static _openInMemoryWithLoader(t){return e.#t(t)}static#t(t){let n=new p(`:memory:`);return e.#n(n,t)}static#n(t,n){try{n(t)}catch(e){throw new U(`Failed to load sqlite-vec extension`,{cause:e})}t.pragma(`journal_mode = WAL`),t.pragma(`foreign_keys = ON`);let r=new e(t);return r.#r(),r}#r(){this.#e.exec(`
231
258
  CREATE TABLE IF NOT EXISTS meta (
232
259
  key TEXT PRIMARY KEY,
233
260
  value TEXT NOT NULL
234
261
  );
235
- `);let e=this.#e.prepare(`SELECT value FROM meta WHERE key = 'schema_version'`).get(),t=e?Number.parseInt(e.value,10):0;for(let[e,n]of pe)t<e&&(this.#e.exec(n),this.#e.prepare(`INSERT OR REPLACE INTO meta (key, value) VALUES ('schema_version', ?)`).run(String(e)))}get db(){return this.#e}close(){this.#e.close()}};const B=`Xenova/bge-small-en-v1.5`;var V=class extends Error{constructor(e,t){super(e,t),this.name=`ModelDownloadError`}};function he(){return l(s(),`.membank`,`models`)}function H(e){if(!r(e))return!1;try{return o(e).length>0}catch{return!1}}var ge=class extends f{modelPath;constructor(e){super(),this.modelPath=e??he()}isAlreadyCached(){return H(this.modelPath)}get cachePath(){return this.modelPath}async download(){if(H(this.modelPath))return{skipped:!0};let e=Date.now(),t=0,n=e;try{await p(`feature-extraction`,B,{cache_dir:this.modelPath,progress_callback:e=>{if(e.status!==`progress`||e.total==null||e.loaded==null)return;let r=e.total,i=e.loaded,a=r>0?i/r*100:0,o=Date.now(),s=o-n,c=i-t,l=0;if(s>0&&c>0){let e=c/s;l=(r-i)/e/1e3}t=i,n=o;let u={totalBytes:r,downloadedBytes:i,percentage:a,estimatedSecondsRemaining:l};this.emit(`progress`,u)}})}catch(e){throw new V(`Failed to download model`,{cause:e})}return{skipped:!1}}},_e=class{modelCachePath;onProgress;pipelineInstance=null;constructor(e,t){this.modelCachePath=e??l(s(),`.membank`,`models`),this.onProgress=t}async getPipeline(){return this.pipelineInstance===null&&(this.pipelineInstance=await p(`feature-extraction`,`Xenova/bge-small-en-v1.5`,{cache_dir:this.modelCachePath,progress_callback:this.onProgress})),this.pipelineInstance}async embed(e){let t=(await(await this.getPipeline())(e,{pooling:`mean`,normalize:!0})).data;return t instanceof Float32Array?t:new Float32Array(t)}};async function ve(e,t){let n=t.now??(()=>new Date);if(!t.repo.tryClaim(e.sessionId,n(),t.config)){let n=t.repo.get(e.sessionId);return{status:`skipped`,reason:n?.status===`completed`&&n.completedAt!==null?`recently_completed`:`in_flight`}}try{let r=await t.transcripts.read(e.transcriptPath);return await t.agent.run({transcript:r,projectHash:e.projectHash,sessionId:e.sessionId}),t.repo.markCompleted(e.sessionId,n()),{status:`completed`}}catch(r){let i=r instanceof Error?r.message:String(r);return t.repo.markFailed(e.sessionId,n(),i),{status:`failed`,error:i}}}const ye=[`You are a memory extractor that runs after a coding session ends. You read the session transcript and CALL save_memory for every durable fact, preference, correction, decision, or learning the user expressed, so that future sessions inherit them.`,``,`Memory types (pick the closest match):`,`- correction: the user told the assistant to stop doing something or to do it differently.`,`- preference: the user stated how they want work done (tools, style, conventions).`,`- decision: the user committed to a choice future work should respect (tech pick, architectural direction, scope cut).`,`- learning: a non-obvious fact about the codebase or tooling that future sessions would otherwise rediscover.`,`- fact: stable info about the user or their project not derivable from the code.`,``,`Bias strongly toward saving. If the user said it in plain language and it would be useful in a future session, save it. Phrasing like 'stop X', 'always Y', 'we use Z', 'don't suggest W', 'we decided', 'from now on' is a clear save signal — even when the assistant in the transcript already acknowledged it, save it so the NEXT session also knows.`,``,`Process:`,`1. Read the supplied transcript end-to-end.`,`2. Identify every distinct durable signal. List them mentally before calling tools.`,`3. Optional: call query_memory with focused search terms to avoid duplicates. If a near-duplicate exists, call update_memory instead of save_memory.`,`4. Call save_memory for each new durable signal. Phrase the content as a standalone instruction or fact — strip session framing ("in this session", "just now"). Good: "Use pnpm, not npm, for all dependency operations." Bad: "User said stop using npm."`,"5. Use `global: true` only when the fact is about the user themselves or applies across every project. Otherwise default to project scope (omit `global`).",``,`Only return without saving when the transcript truly contains no durable signal — pure greetings, time-of-day questions, abandoned tasks. Do not invent facts. If in doubt and the signal is concrete, save it.`].join(`
236
- `);var be=class{#e;constructor(e){this.#e=e}async run(e){let t=m({name:`membank-extraction-tools`,version:`1.0.0`,tools:[g(`query_memory`,`Search memories by semantic similarity to check for existing entries before saving.`,{query:n.string().describe(`Search text`),limit:n.number().optional().describe(`Maximum results to return`),global:n.boolean().optional().describe(`Query global memories when true, otherwise current project scope`)},async({query:t,limit:n,global:r})=>({content:[{type:`text`,text:await this.#e.queryMemory({query:t,limit:n,global:r,projectHash:e.projectHash})}]}),{annotations:{readOnlyHint:!0}}),g(`save_memory`,`Persist a new memory. The system handles dedup automatically.`,{content:n.string().describe(`Memory content — concise, decontextualised`),type:n.enum([`correction`,`preference`,`decision`,`learning`,`fact`]).describe(`Memory type`),tags:n.array(n.string()).optional().describe(`Optional tags`),global:n.boolean().optional().describe(`Save as global memory rather than project-scoped`)},async({content:e,type:t,tags:n,global:r})=>({content:[{type:`text`,text:await this.#e.saveMemory({content:e,type:t,tags:n,global:r})}]})),g(`update_memory`,`Refine an existing memory by id rather than creating a near-duplicate.`,{id:n.string().describe(`Memory id`),content:n.string().optional(),type:n.enum([`correction`,`preference`,`decision`,`learning`,`fact`]).optional(),tags:n.array(n.string()).optional()},async({id:e,content:t,type:n,tags:r})=>({content:[{type:`text`,text:await this.#e.updateMemory({id:e,content:t,type:n,tags:r})}]}))]}),r=[`Session id: ${e.sessionId}`,``,`Transcript (most recent turns):`,`---`,e.transcript,`---`,``,`Extract durable memories from this transcript following the system instructions.`].join(`
237
- `),i=Object.fromEntries(Object.entries(process.env).filter(e=>e[1]!==void 0)),a=Date.now(),o=h({prompt:r,options:{model:`claude-haiku-4-5-20251001`,systemPrompt:ye,mcpServers:{"membank-extraction-tools":t},allowedTools:[`mcp__membank-extraction-tools__query_memory`,`mcp__membank-extraction-tools__save_memory`,`mcp__membank-extraction-tools__update_memory`],disallowedTools:[`mcp__membank__*`],settingSources:[],permissionMode:`bypassPermissions`,env:i}}),s=process.env.MEMBANK_EXTRACTION_DEBUG===`true`;for await(let e of o)if(s&&process.stderr.write(`[extraction debug] ${JSON.stringify(e).slice(0,600)}\n`),e.type===`result`&&e.subtype!==`success`){let t=`errors`in e&&Array.isArray(e.errors)?`: ${e.errors.join(`; `)}`:``;throw Error(`Extraction agent failed: ${e.subtype}${t}`)}let c=Date.now()-a;process.stderr.write(`membank extraction: session=${e.sessionId} duration=${c}ms\n`)}};function xe(e){return new be(e)}function Se(e,t,n,r){return e===void 0?{kind:`claim`}:e.status===`in_flight`?t.getTime()-e.startedAt.getTime()<n?{kind:`skip`,reason:`in_flight`}:{kind:`claim`}:e.status===`completed`&&e.completedAt!==null&&t.getTime()-e.completedAt.getTime()<r?{kind:`skip`,reason:`recently_completed`}:{kind:`claim`}}function Ce(e){return{sessionId:e.session_id,startedAt:e.started_at,completedAt:e.completed_at,status:e.status,error:e.error}}var we=class{#e;constructor(e){this.#e=e}tryClaim(e,t,n){let r=this.#t(e);if(Se(r===void 0?void 0:{startedAt:new Date(r.started_at),completedAt:r.completed_at===null?null:new Date(r.completed_at),status:r.status},t,n.inFlightTimeoutMs??6e5,n.recentCompletionMs??6e4).kind===`skip`)return!1;let i=t.toISOString();return this.#e.db.prepare(`INSERT INTO extraction_runs (session_id, started_at, completed_at, status, error)
262
+ `);let e=this.#e.prepare(`SELECT value FROM meta WHERE key = 'schema_version'`).get(),t=e?Number.parseInt(e.value,10):0;for(let[e,n]of fe)t<e&&(this.#e.exec(n),this.#e.prepare(`INSERT OR REPLACE INTO meta (key, value) VALUES ('schema_version', ?)`).run(String(e)))}get db(){return this.#e}close(){this.#e.close()}};const W=`Xenova/bge-small-en-v1.5`;var G=class extends Error{constructor(e,t){super(e,t),this.name=`ModelDownloadError`}};function me(){return f(u(),`.membank`,`models`)}function K(e){if(!o(e))return!1;try{return l(e).length>0}catch{return!1}}var he=class extends h{modelPath;constructor(e){super(),this.modelPath=e??me()}isAlreadyCached(){return K(this.modelPath)}get cachePath(){return this.modelPath}async download(){if(K(this.modelPath))return{skipped:!0};let e=Date.now(),t=0,n=e;try{await g(`feature-extraction`,W,{cache_dir:this.modelPath,progress_callback:e=>{if(e.status!==`progress`||e.total==null||e.loaded==null)return;let r=e.total,i=e.loaded,a=r>0?i/r*100:0,o=Date.now(),s=o-n,c=i-t,l=0;if(s>0&&c>0){let e=c/s;l=(r-i)/e/1e3}t=i,n=o;let u={totalBytes:r,downloadedBytes:i,percentage:a,estimatedSecondsRemaining:l};this.emit(`progress`,u)}})}catch(e){throw new G(`Failed to download model`,{cause:e})}return{skipped:!1}}},ge=class{modelCachePath;onProgress;pipelineInstance=null;constructor(e,t){this.modelCachePath=e??f(u(),`.membank`,`models`),this.onProgress=t}async getPipeline(){return this.pipelineInstance===null&&(this.pipelineInstance=await g(`feature-extraction`,`Xenova/bge-small-en-v1.5`,{cache_dir:this.modelCachePath,progress_callback:this.onProgress})),this.pipelineInstance}async embed(e){let t=(await(await this.getPipeline())(e,{pooling:`mean`,normalize:!0})).data;return t instanceof Float32Array?t:new Float32Array(t)}};async function _e(e,t){let n=t.now??(()=>new Date);if(!t.repo.tryClaim(e.sessionId,n(),t.config)){let n=t.repo.get(e.sessionId);return{status:`skipped`,reason:n?.status===`completed`&&n.completedAt!==null?`recently_completed`:`in_flight`}}try{let r=await t.transcripts.read(e.transcriptPath);return await t.agent.run({transcript:r,projectHash:e.projectHash,sessionId:e.sessionId}),t.repo.markCompleted(e.sessionId,n()),{status:`completed`}}catch(r){let i=r instanceof Error?r.message:String(r);return t.repo.markFailed(e.sessionId,n(),i),{status:`failed`,error:i}}}const ve=[`You are a memory extractor that runs after a coding session ends. You read the session transcript and CALL save_memory for every durable fact, preference, correction, decision, or learning the user expressed, so that future sessions inherit them.`,``,`Memory types (pick the closest match):`,`- correction: the user told the assistant to stop doing something or to do it differently.`,`- preference: the user stated how they want work done (tools, style, conventions).`,`- decision: the user committed to a choice future work should respect (tech pick, architectural direction, scope cut).`,`- learning: a non-obvious fact about the codebase or tooling that future sessions would otherwise rediscover.`,`- fact: stable info about the user or their project not derivable from the code.`,``,`Bias strongly toward saving. If the user said it in plain language and it would be useful in a future session, save it. Phrasing like 'stop X', 'always Y', 'we use Z', 'don't suggest W', 'we decided', 'from now on' is a clear save signal — even when the assistant in the transcript already acknowledged it, save it so the NEXT session also knows.`,``,`Process:`,`1. Read the supplied transcript end-to-end.`,`2. Identify every distinct durable signal. List them mentally before calling tools.`,`3. Optional: call query_memory with focused search terms to avoid duplicates. If a near-duplicate exists, call update_memory instead of save_memory.`,`4. Call save_memory for each new durable signal. Phrase the content as a standalone instruction or fact — strip session framing ("in this session", "just now"). Good: "Use pnpm, not npm, for all dependency operations." Bad: "User said stop using npm."`,"5. Use `global: true` only when the fact is about the user themselves or applies across every project. Otherwise default to project scope (omit `global`).",``,`Only return without saving when the transcript truly contains no durable signal — pure greetings, time-of-day questions, abandoned tasks. Do not invent facts. If in doubt and the signal is concrete, save it.`].join(`
263
+ `);var ye=class{#e;constructor(e){this.#e=e}async run(e){let t=_({name:`membank-extraction-tools`,version:`1.0.0`,tools:[y(`query_memory`,`Search memories by semantic similarity to check for existing entries before saving.`,{query:a.string().describe(`Search text`),limit:a.number().optional().describe(`Maximum results to return`),global:a.boolean().optional().describe(`Query global memories when true, otherwise current project scope`)},async({query:t,limit:n,global:r})=>({content:[{type:`text`,text:await this.#e.queryMemory({query:t,limit:n,global:r,projectHash:e.projectHash})}]}),{annotations:{readOnlyHint:!0}}),y(`save_memory`,`Persist a new memory. The system handles dedup automatically.`,{content:a.string().describe(`Memory content — concise, decontextualised`),type:a.enum([`correction`,`preference`,`decision`,`learning`,`fact`]).describe(`Memory type`),tags:a.array(a.string()).optional().describe(`Optional tags`),global:a.boolean().optional().describe(`Save as global memory rather than project-scoped`)},async({content:e,type:t,tags:n,global:r})=>({content:[{type:`text`,text:await this.#e.saveMemory({content:e,type:t,tags:n,global:r})}]})),y(`update_memory`,`Refine an existing memory by id rather than creating a near-duplicate.`,{id:a.string().describe(`Memory id`),content:a.string().optional(),type:a.enum([`correction`,`preference`,`decision`,`learning`,`fact`]).optional(),tags:a.array(a.string()).optional()},async({id:e,content:t,type:n,tags:r})=>({content:[{type:`text`,text:await this.#e.updateMemory({id:e,content:t,type:n,tags:r})}]}))]}),n=[`Session id: ${e.sessionId}`,``,`Transcript (most recent turns):`,`---`,e.transcript,`---`,``,`Extract durable memories from this transcript following the system instructions.`].join(`
264
+ `),r=Object.fromEntries(Object.entries(process.env).filter(e=>e[1]!==void 0)),i=Date.now(),o=v({prompt:n,options:{model:`claude-haiku-4-5-20251001`,systemPrompt:ve,mcpServers:{"membank-extraction-tools":t},allowedTools:[`mcp__membank-extraction-tools__query_memory`,`mcp__membank-extraction-tools__save_memory`,`mcp__membank-extraction-tools__update_memory`],disallowedTools:[`mcp__membank__*`],settingSources:[],permissionMode:`bypassPermissions`,env:r}}),s=process.env.MEMBANK_EXTRACTION_DEBUG===`true`;for await(let e of o)if(s&&process.stderr.write(`[extraction debug] ${JSON.stringify(e).slice(0,600)}\n`),e.type===`result`&&e.subtype!==`success`){let t=`errors`in e&&Array.isArray(e.errors)?`: ${e.errors.join(`; `)}`:``;throw Error(`Extraction agent failed: ${e.subtype}${t}`)}let c=Date.now()-i;process.stderr.write(`membank extraction: session=${e.sessionId} duration=${c}ms\n`)}};function be(e){return new ye(e)}function xe(e,t,n,r){return e===void 0?{kind:`claim`}:e.status===`in_flight`?t.getTime()-e.startedAt.getTime()<n?{kind:`skip`,reason:`in_flight`}:{kind:`claim`}:e.status===`completed`&&e.completedAt!==null&&t.getTime()-e.completedAt.getTime()<r?{kind:`skip`,reason:`recently_completed`}:{kind:`claim`}}function Se(e){return{sessionId:e.session_id,startedAt:e.started_at,completedAt:e.completed_at,status:e.status,error:e.error}}var Ce=class{#e;constructor(e){this.#e=e}tryClaim(e,t,n){let r=this.#t(e);if(xe(r===void 0?void 0:{startedAt:new Date(r.started_at),completedAt:r.completed_at===null?null:new Date(r.completed_at),status:r.status},t,n.inFlightTimeoutMs??6e5,n.recentCompletionMs??6e4).kind===`skip`)return!1;let i=t.toISOString();return this.#e.db.prepare(`INSERT INTO extraction_runs (session_id, started_at, completed_at, status, error)
238
265
  VALUES (?, ?, NULL, 'in_flight', NULL)
239
266
  ON CONFLICT(session_id) DO UPDATE SET
240
267
  started_at = excluded.started_at,
@@ -244,71 +271,85 @@ CREATE INDEX idx_activity_type_created ON activity_events(event_type, created
244
271
  SET status = 'completed', completed_at = ?, error = NULL
245
272
  WHERE session_id = ?`).run(t.toISOString(),e)}markFailed(e,t,n){this.#e.db.prepare(`UPDATE extraction_runs
246
273
  SET status = 'failed', completed_at = ?, error = ?
247
- WHERE session_id = ?`).run(t.toISOString(),n,e)}get(e){let t=this.#t(e);return t===void 0?void 0:Ce(t)}#t(e){return this.#e.db.prepare(`SELECT * FROM extraction_runs WHERE session_id = ?`).get(e)}};function Te(e){return new we(e)}function Ee(e){if(typeof e==`string`)return e;if(!Array.isArray(e))return``;let t=[];for(let n of e){if(typeof n!=`object`||!n)continue;let e=n;e.type===`text`&&typeof e.text==`string`?t.push(e.text):e.type===`tool_use`&&typeof e.name==`string`?t.push(`[tool_use: ${e.name}]`):e.type===`tool_result`&&t.push(`[tool_result]`)}return t.join(`
248
- `)}var De=class{#e;#t;constructor(e={}){this.#e=e.maxTurns??80,this.#t=e.maxChars??6e4}async read(e){let t=(await ee(e,`utf8`)).split(`
249
- `).filter(e=>e.length>0),n=[];for(let e of t){let t;try{t=JSON.parse(e)}catch{continue}let r=t.message?.role;if(r!==`user`&&r!==`assistant`)continue;let i=Ee(t.message?.content).trim();i.length!==0&&n.push(`${r}: ${i}`)}let r=n.slice(-this.#e).join(`
274
+ WHERE session_id = ?`).run(t.toISOString(),n,e)}get(e){let t=this.#t(e);return t===void 0?void 0:Se(t)}#t(e){return this.#e.db.prepare(`SELECT * FROM extraction_runs WHERE session_id = ?`).get(e)}};function we(e){return new Ce(e)}function Te(e){if(typeof e==`string`)return e;if(!Array.isArray(e))return``;let t=[];for(let n of e){if(typeof n!=`object`||!n)continue;let e=n;e.type===`text`&&typeof e.text==`string`?t.push(e.text):e.type===`tool_use`&&typeof e.name==`string`?t.push(`[tool_use: ${e.name}]`):e.type===`tool_result`&&t.push(`[tool_result]`)}return t.join(`
275
+ `)}var Ee=class{#e;#t;constructor(e={}){this.#e=e.maxTurns??80,this.#t=e.maxChars??6e4}async read(e){let t=(await ee(e,`utf8`)).split(`
276
+ `).filter(e=>e.length>0),n=[];for(let e of t){let t;try{t=JSON.parse(e)}catch{continue}let r=t.message?.role;if(r!==`user`&&r!==`assistant`)continue;let i=Te(t.message?.content).trim();i.length!==0&&n.push(`${r}: ${i}`)}let r=n.slice(-this.#e).join(`
250
277
 
251
- `);return r.length<=this.#t?r:r.slice(r.length-this.#t)}};function Oe(e={}){return new De(e)}const U=`00000000-0000-0000-0000-000000000000`,W=`0000000000000000`,G=`global`;function ke(e,t,n=x){let r=t.findById(e)?.projects[0]?.scopeHash??`0000000000000000`;return t.delete(e),n.logEvent({projectHash:r,eventType:`memory.deleted`,memoryId:e}),Promise.resolve()}function Ae(e,t){t.resolveReviewEvents(e)}function je(e){return e>.92?`overwrite`:e>=.75?`flag`:`none`}async function Me(e,n){let{content:r,type:i,tags:a=[],projectScope:o,sourceHarness:s}=ue.parse(e),{repo:c,embedder:l,activityLogger:u=x}=n,d=o?.hash??`0000000000000000`,f=await l.embed(r),[p]=c.findSimilar(f,i,o?.hash);if(p!==void 0){let e=je(p.similarity);if(e===`overwrite`){let e=c.overwrite(p.id,r,f);return u.logEvent({projectHash:d,eventType:`memory.updated`,memoryId:p.id}),e}if(e===`flag`){let e=c.create({id:t(),content:r,type:i,tags:a,sourceHarness:s??null,embedding:f,projectScope:o});return c.createReviewEvent({memoryId:p.id,conflictingMemoryId:e.id,similarity:p.similarity,conflictContentSnapshot:r}),u.logEvent({projectHash:d,eventType:`memory.created`,memoryId:e.id}),u.logEvent({projectHash:d,eventType:`memory.flagged`,memoryId:p.id,payload:{conflictingMemoryId:e.id,similarity:p.similarity}}),e}}let m=c.create({id:t(),content:r,type:i,tags:a,sourceHarness:s??null,embedding:f,projectScope:o});return u.logEvent({projectHash:d,eventType:`memory.created`,memoryId:m.id}),m}async function Ne(e,t,n){let{repo:r,embedder:i,activityLogger:a=x}=n,o=j.parse(t),s=o.content===void 0?void 0:await i.embed(o.content),c=r.update(e,o,s),l=c.projects[0]?.scopeHash??`0000000000000000`;return a.logEvent({projectHash:l,eventType:`memory.updated`,memoryId:e}),c}const K=8e3;function Pe(e){return e>=K}var q=class{#e;#t;constructor(e,t){this.#e=e,this.#t=t}findSimilar(e,t,n){let r=Buffer.from(e.buffer),i;return i=n===void 0?this.#e.db.prepare(`SELECT m.rowid, m.*, (1 - vec_distance_cosine(e.embedding, ?)) AS similarity
278
+ `);return r.length<=this.#t?r:r.slice(r.length-this.#t)}};function De(e={}){return new Ee(e)}function Oe(e){let t=new Map;function n(e){t.has(e)||t.set(e,e);let r=t.get(e);if(r!==e){let i=n(r);return t.set(e,i),i}return e}function r(e,r){let i=n(e),a=n(r);i!==a&&t.set(a,i)}for(let{memoryId:t,conflictingMemoryId:n}of e)r(t,n);let i=new Map;for(let e of t.keys()){let t=n(e),r=i.get(t)??[];r.push(e),i.set(t,r)}return Array.from(i.entries()).map(([e,t])=>({clusterId:e,memoryIds:t}))}function q(e,t,n=w){let r=t.findById(e)?.projects[0]?.scopeHash??`0000000000000000`;return t.delete(e),n.logEvent({projectHash:r,eventType:`memory.deleted`,memoryId:e}),Promise.resolve()}async function ke(e,t,n=w){let r=[];for(let i of e)try{await q(i,t,n),r.push({id:i,status:`ok`})}catch(e){r.push({id:i,status:`error`,error:e instanceof Error?e.message:String(e)})}return r}function J(e){return e>.92?`overwrite`:e>=.75?`flag`:`none`}async function Ae(e,t){let{keepId:n,dropIds:r,mergedContent:i}=e,{repo:a,embedder:o,activityLogger:s=w}=t,c=a.findById(n);if(c===void 0)throw Error(`Memory not found: ${n}`);let l=r.map(e=>{let t=a.findById(e);if(t===void 0)throw Error(`Memory not found: ${e}`);return t});for(let e of l)if(e.type!==c.type)throw Error(`Type mismatch: keep memory has type "${c.type}" but drop memory ${e.id} has type "${e.type}"`);let u=[c,...l],d=[...new Set(u.flatMap(e=>e.tags))],f=u.some(e=>e.pinned),p=u.reduce((e,t)=>e+t.accessCount,0),m=await o.embed(i),h=a.overwrite(n,i,m),g=new Set(c.tags);if((d.length!==c.tags.length||d.some(e=>!g.has(e)))&&(h=a.update(n,{tags:d})),f&&!c.pinned&&(h=a.setPin(n,!0)),p>c.accessCount){let e=p-c.accessCount;for(let t=0;t<e;t++)a.incrementAccessCount(n);h=a.findById(n)??h}for(let e of l)a.delete(e.id);let[_]=a.findSimilar(m,c.type,c.projects[0]?.scopeHash);_!==void 0&&_.id!==n&&J(_.similarity)===`flag`&&a.createReviewEvent({memoryId:n,conflictingMemoryId:_.id,similarity:_.similarity,conflictContentSnapshot:i});let v=h.projects[0]?.scopeHash??`0000000000000000`;return s.logEvent({projectHash:v,eventType:`memory.updated`,memoryId:n,payload:{merged:r}}),h=a.findById(n)??h,{kept:h,dropped:r}}function je(e,t){t.resolveReviewEvents(e)}function Me(e,t){return e.map(e=>{try{return t.findById(e)===void 0?{id:e,status:`error`,error:`Memory not found: ${e}`}:(t.resolveReviewEvents(e),{id:e,status:`ok`})}catch(t){return{id:e,status:`error`,error:t instanceof Error?t.message:String(t)}}})}async function Ne(e,t){let{content:n,type:r,tags:a=[],projectScope:o,sourceHarness:s}=P.parse(e),{repo:c,embedder:l,activityLogger:u=w}=t,d=o?.hash??`0000000000000000`,f=await l.embed(n),[p]=c.findSimilar(f,r,o?.hash);if(p!==void 0){let e=J(p.similarity);if(e===`overwrite`){let e=c.overwrite(p.id,n,f);return u.logEvent({projectHash:d,eventType:`memory.updated`,memoryId:p.id}),e}if(e===`flag`){let e=c.create({id:i(),content:n,type:r,tags:a,sourceHarness:s??null,embedding:f,projectScope:o});return c.createReviewEvent({memoryId:p.id,conflictingMemoryId:e.id,similarity:p.similarity,conflictContentSnapshot:n}),u.logEvent({projectHash:d,eventType:`memory.created`,memoryId:e.id}),u.logEvent({projectHash:d,eventType:`memory.flagged`,memoryId:p.id,payload:{conflictingMemoryId:e.id,similarity:p.similarity}}),e}}let m=c.create({id:i(),content:n,type:r,tags:a,sourceHarness:s??null,embedding:f,projectScope:o});return u.logEvent({projectHash:d,eventType:`memory.created`,memoryId:m.id}),m}async function Pe(e,t,n){let{repo:r,embedder:i,activityLogger:a=w}=n,o=F.parse(t),s=o.content===void 0?void 0:await i.embed(o.content),c=r.update(e,o,s),l=c.projects[0]?.scopeHash??`0000000000000000`;return a.logEvent({projectHash:l,eventType:`memory.updated`,memoryId:e}),c}const Y=8e3;function Fe(e){return e>=Y}var X=class{#e;#t;constructor(e,t){this.#e=e,this.#t=t}findSimilar(e,n,r){let i=Buffer.from(e.buffer),a;return a=r===void 0?this.#e.db.prepare(`SELECT m.rowid, m.*, (1 - vec_distance_cosine(e.embedding, ?)) AS similarity
252
279
  FROM memories m JOIN embeddings e ON e.rowid = m.rowid
253
280
  JOIN memory_projects mp ON mp.memory_id = m.id
254
281
  JOIN projects p ON p.id = mp.project_id
255
282
  WHERE m.type = ? AND p.scope_hash = ?
256
- ORDER BY similarity DESC LIMIT 1`).get(r,t,W):this.#e.db.prepare(`SELECT m.rowid, m.*, (1 - vec_distance_cosine(e.embedding, ?)) AS similarity
283
+ ORDER BY similarity DESC LIMIT 1`).get(i,n,t):this.#e.db.prepare(`SELECT m.rowid, m.*, (1 - vec_distance_cosine(e.embedding, ?)) AS similarity
257
284
  FROM memories m JOIN embeddings e ON e.rowid = m.rowid
258
285
  JOIN memory_projects mp ON mp.memory_id = m.id
259
286
  JOIN projects p ON p.id = mp.project_id
260
287
  WHERE m.type = ? AND p.scope_hash = ?
261
- ORDER BY similarity DESC LIMIT 1`).get(r,t,n),i===void 0?[]:[{id:i.id,similarity:i.similarity}]}create(e){let{id:t,content:n,type:r,tags:i,sourceHarness:a,embedding:o,projectScope:s}=e,c=new Date().toISOString(),l=Buffer.from(o.buffer);this.#e.db.prepare(`INSERT INTO memories (id, content, type, tags, source, access_count, pinned, created_at, updated_at)
262
- VALUES (?, ?, ?, ?, ?, 0, 0, ?, ?)`).run(t,n,r,JSON.stringify(i),a,c,c),this.#e.db.prepare(`INSERT INTO embeddings (rowid, embedding) SELECT m.rowid, ? FROM memories m WHERE m.id = ?`).run(l,t);let u=s??{hash:`0000000000000000`,name:`global`},d=this.#t.upsertByHash(u.hash,u.name);return this.#t.addAssociation(t,d.id),F(N.parse(this.#e.db.prepare(`SELECT * FROM memories WHERE id = ?`).get(t)),this.#t.getProjectsForMemories([t]).get(t)??[])}overwrite(e,t,n){let r=new Date().toISOString(),i=Buffer.from(n.buffer);this.#e.db.prepare(`UPDATE memories SET content = ?, updated_at = ? WHERE id = ?`).run(t,r,e);let a=this.#e.db.prepare(`SELECT rowid FROM memories WHERE id = ?`).get(e)?.rowid;a!==void 0&&this.#e.db.prepare(`UPDATE embeddings SET embedding = ? WHERE rowid = ?`).run(i,a);let o=N.parse(this.#e.db.prepare(`SELECT * FROM memories WHERE id = ?`).get(e)),s=this.#t.getProjectsForMemories([e]),c=this.#r([e]);return F(o,s.get(e)??[],c.get(e)??[])}findById(e){let t=this.#e.db.prepare(`SELECT * FROM memories WHERE id = ?`).get(e);if(t===void 0)return;let n=this.#t.getProjectsForMemories([e]),r=this.#r([e]);return F(t,n.get(e)??[],r.get(e)??[])}update(e,t,n){let{content:r,tags:i,type:a}=j.parse(t),o=this.#e.db.prepare(`SELECT m.rowid, m.* FROM memories m WHERE m.id = ?`).get(e);if(o===void 0)throw Error(`Memory not found: ${e}`);let s=new Date().toISOString(),c=[`updated_at = ?`],l=[s];if(r!==void 0&&(c.push(`content = ?`),l.push(r)),i!==void 0&&(c.push(`tags = ?`),l.push(JSON.stringify(i))),a!==void 0&&(c.push(`type = ?`),l.push(a)),l.push(e),this.#e.db.prepare(`UPDATE memories SET ${c.join(`, `)} WHERE id = ?`).run(...l),n!==void 0){let e=Buffer.from(n.buffer);this.#e.db.prepare(`UPDATE embeddings SET embedding = ? WHERE rowid = ?`).run(e,o.rowid)}let u=N.parse(this.#e.db.prepare(`SELECT * FROM memories WHERE id = ?`).get(e)),d=this.#t.getProjectsForMemories([e]),f=this.#r([e]);return F(u,d.get(e)??[],f.get(e)??[])}delete(e){let t=this.#e.db.prepare(`SELECT rowid FROM memories WHERE id = ?`).get(e);t!==void 0&&this.#e.db.prepare(`DELETE FROM embeddings WHERE rowid = ?`).run(t.rowid),this.#e.db.prepare(`DELETE FROM memory_projects WHERE memory_id = ?`).run(e),this.#e.db.prepare(`DELETE FROM memories WHERE id = ?`).run(e)}list(e){let t=[],n=[];e?.type!==void 0&&(t.push(`m.type = ?`),n.push(e.type)),e?.pinned===!0&&t.push(`m.pinned = 1`),e?.needsReview===!0&&t.push(`EXISTS (SELECT 1 FROM memory_review_events e WHERE e.memory_id = m.id AND e.resolved_at IS NULL)`),e?.projectId===`global`?(t.push(`EXISTS (SELECT 1 FROM memory_projects mp JOIN projects p ON p.id = mp.project_id WHERE mp.memory_id = m.id AND p.scope_hash = ?)`),n.push(W)):e?.projectId!==void 0&&(t.push(`m.id IN (SELECT memory_id FROM memory_projects WHERE project_id = ?)`),n.push(e.projectId));let r=t.length>0?`WHERE ${t.join(` AND `)}`:``,i=this.#e.db.prepare(`SELECT m.* FROM memories m ${r} ORDER BY m.created_at DESC`).all(...n);if(i.length===0)return[];let a=i.map(e=>e.id),o=this.#t.getProjectsForMemories(a),s=this.#r(a);return i.map(e=>F(e,o.get(e.id)??[],s.get(e.id)??[]))}listPinnedGlobal(){return this.listPinnedForProject(W)}listPinnedForProject(e){return this.#e.db.prepare(`SELECT m.* FROM memories m
288
+ ORDER BY similarity DESC LIMIT 1`).get(i,n,r),a===void 0?[]:[{id:a.id,similarity:a.similarity}]}create(e){let{id:t,content:n,type:r,tags:i,sourceHarness:a,embedding:o,projectScope:s}=e,c=new Date().toISOString(),l=Buffer.from(o.buffer);this.#e.db.prepare(`INSERT INTO memories (id, content, type, tags, source, access_count, pinned, created_at, updated_at)
289
+ VALUES (?, ?, ?, ?, ?, 0, 0, ?, ?)`).run(t,n,r,JSON.stringify(i),a,c,c),this.#e.db.prepare(`INSERT INTO embeddings (rowid, embedding) SELECT m.rowid, ? FROM memories m WHERE m.id = ?`).run(l,t);let u=s??{hash:`0000000000000000`,name:`global`},d=this.#t.upsertByHash(u.hash,u.name);return this.#t.addAssociation(t,d.id),z(L.parse(this.#e.db.prepare(`SELECT * FROM memories WHERE id = ?`).get(t)),this.#t.getProjectsForMemories([t]).get(t)??[])}overwrite(e,t,n){let r=new Date().toISOString(),i=Buffer.from(n.buffer);this.#e.db.prepare(`UPDATE memories SET content = ?, updated_at = ? WHERE id = ?`).run(t,r,e);let a=this.#e.db.prepare(`SELECT rowid FROM memories WHERE id = ?`).get(e)?.rowid;a!==void 0&&this.#e.db.prepare(`UPDATE embeddings SET embedding = ? WHERE rowid = ?`).run(i,a);let o=L.parse(this.#e.db.prepare(`SELECT * FROM memories WHERE id = ?`).get(e)),s=this.#t.getProjectsForMemories([e]),c=this.#r([e]);return z(o,s.get(e)??[],c.get(e)??[])}findById(e){let t=this.#e.db.prepare(`SELECT * FROM memories WHERE id = ?`).get(e);if(t===void 0)return;let n=this.#t.getProjectsForMemories([e]),r=this.#r([e]);return z(t,n.get(e)??[],r.get(e)??[])}findManyById(e){if(e.length===0)return[];let t=e.map(()=>`?`).join(`, `),n=this.#e.db.prepare(`SELECT * FROM memories WHERE id IN (${t})`).all(...e);if(n.length===0)return[];let r=n.map(e=>e.id),i=this.#t.getProjectsForMemories(r),a=this.#r(r);return n.map(e=>z(e,i.get(e.id)??[],a.get(e.id)??[]))}update(e,t,n){let{content:r,tags:i,type:a}=F.parse(t),o=this.#e.db.prepare(`SELECT m.rowid, m.* FROM memories m WHERE m.id = ?`).get(e);if(o===void 0)throw Error(`Memory not found: ${e}`);let s=new Date().toISOString(),c=[`updated_at = ?`],l=[s];if(r!==void 0&&(c.push(`content = ?`),l.push(r)),i!==void 0&&(c.push(`tags = ?`),l.push(JSON.stringify(i))),a!==void 0&&(c.push(`type = ?`),l.push(a)),l.push(e),this.#e.db.prepare(`UPDATE memories SET ${c.join(`, `)} WHERE id = ?`).run(...l),n!==void 0){let e=Buffer.from(n.buffer);this.#e.db.prepare(`UPDATE embeddings SET embedding = ? WHERE rowid = ?`).run(e,o.rowid)}let u=L.parse(this.#e.db.prepare(`SELECT * FROM memories WHERE id = ?`).get(e)),d=this.#t.getProjectsForMemories([e]),f=this.#r([e]);return z(u,d.get(e)??[],f.get(e)??[])}delete(e){let t=this.#e.db.prepare(`SELECT rowid FROM memories WHERE id = ?`).get(e);t!==void 0&&this.#e.db.prepare(`DELETE FROM embeddings WHERE rowid = ?`).run(t.rowid),this.#e.db.prepare(`DELETE FROM memory_projects WHERE memory_id = ?`).run(e),this.#e.db.prepare(`DELETE FROM memories WHERE id = ?`).run(e)}list(e){let n=[],r=[];e?.type!==void 0&&(n.push(`m.type = ?`),r.push(e.type)),e?.pinned===!0&&n.push(`m.pinned = 1`),e?.needsReview===!0&&n.push(`EXISTS (SELECT 1 FROM memory_review_events e WHERE e.memory_id = m.id AND e.resolved_at IS NULL)`),e?.projectId===`global`?(n.push(`EXISTS (SELECT 1 FROM memory_projects mp JOIN projects p ON p.id = mp.project_id WHERE mp.memory_id = m.id AND p.scope_hash = ?)`),r.push(t)):e?.projectId!==void 0&&(n.push(`m.id IN (SELECT memory_id FROM memory_projects WHERE project_id = ?)`),r.push(e.projectId));let i=n.length>0?`WHERE ${n.join(` AND `)}`:``,a=this.#e.db.prepare(`SELECT m.* FROM memories m ${i} ORDER BY m.created_at DESC`).all(...r);if(a.length===0)return[];let o=a.map(e=>e.id),s=this.#t.getProjectsForMemories(o),c=this.#r(o);return a.map(e=>z(e,s.get(e.id)??[],c.get(e.id)??[]))}listPinnedGlobal(){return this.listPinnedForProject(t)}listPinnedForProject(e){return this.#e.db.prepare(`SELECT m.* FROM memories m
263
290
  JOIN memory_projects mp ON mp.memory_id = m.id
264
291
  JOIN projects p ON p.id = mp.project_id
265
- WHERE p.scope_hash = ? AND m.pinned = 1`).all(e).map(e=>F(e,[]))}listFlagged(e){let t;if(t=e===void 0?this.#e.db.prepare(`SELECT * FROM memories
266
- WHERE EXISTS (
267
- SELECT 1 FROM memory_review_events e
268
- WHERE e.memory_id = memories.id AND e.resolved_at IS NULL
269
- )
270
- ORDER BY created_at DESC`).all():this.#e.db.prepare(`SELECT * FROM memories
271
- WHERE EXISTS (
292
+ WHERE p.scope_hash = ? AND m.pinned = 1`).all(e).map(e=>z(e,[]))}listFlagged(e){let{projectHash:t,limit:n,minSimilarity:r,maxSimilarity:i}=e??{},a=[`e.resolved_at IS NULL`];r!==void 0&&a.push(`e.similarity >= ?`),i!==void 0&&a.push(`e.similarity <= ?`);let o=[r,i].filter(e=>e!==void 0),s=`EXISTS (
272
293
  SELECT 1 FROM memory_review_events e
273
- WHERE e.memory_id = memories.id AND e.resolved_at IS NULL
274
- )
294
+ WHERE e.memory_id = memories.id AND ${a.join(` AND `)}
295
+ )`,c=n===void 0?``:`LIMIT ?`,l=n===void 0?[]:[n],u;if(u=t===void 0?this.#e.db.prepare(`SELECT * FROM memories
296
+ WHERE ${s}
297
+ ORDER BY created_at DESC ${c}`).all(...o,...l):this.#e.db.prepare(`SELECT * FROM memories
298
+ WHERE ${s}
275
299
  AND ${this.#n()}
276
- ORDER BY created_at DESC`).all(e),t.length===0)return[];let n=t.map(e=>e.id),r=this.#t.getProjectsForMemories(n),i=this.#r(n,{unresolvedOnly:!0});return t.map(e=>F(e,r.get(e.id)??[],i.get(e.id)??[]))}listReviewEvents(e,t){let n=t?.unresolvedOnly===!0?`WHERE memory_id = ? AND resolved_at IS NULL`:`WHERE memory_id = ?`;return this.#e.db.prepare(`SELECT * FROM memory_review_events ${n} ORDER BY created_at DESC`).all(e).map(e=>I(O.parse(e)))}createReviewEvent(e){let n=new Date().toISOString();this.#e.db.prepare(`INSERT INTO memory_review_events
300
+ ORDER BY created_at DESC ${c}`).all(...o,t,...l),u.length===0)return[];let d=u.map(e=>e.id),f=this.#t.getProjectsForMemories(d),p=this.#r(d,{unresolvedOnly:!0});return u.map(e=>z(e,f.get(e.id)??[],p.get(e.id)??[]))}listReviewEdges(e){return e===void 0?this.#e.db.prepare(`SELECT memory_id, conflicting_memory_id FROM memory_review_events
301
+ WHERE resolved_at IS NULL AND conflicting_memory_id IS NOT NULL`).all().map(e=>({memoryId:e.memory_id,conflictingMemoryId:e.conflicting_memory_id})):this.#e.db.prepare(`SELECT e.memory_id, e.conflicting_memory_id
302
+ FROM memory_review_events e
303
+ JOIN memories m ON m.id = e.memory_id
304
+ WHERE e.resolved_at IS NULL
305
+ AND e.conflicting_memory_id IS NOT NULL
306
+ AND ${this.#n(`m`)}`).all(e).map(e=>({memoryId:e.memory_id,conflictingMemoryId:e.conflicting_memory_id}))}listReviewEvents(e,t){let n=t?.unresolvedOnly===!0?`WHERE memory_id = ? AND resolved_at IS NULL`:`WHERE memory_id = ?`;return this.#e.db.prepare(`SELECT * FROM memory_review_events ${n} ORDER BY created_at DESC`).all(e).map(e=>B(j.parse(e)))}createReviewEvent(e){let t=new Date().toISOString();this.#e.db.prepare(`INSERT INTO memory_review_events
277
307
  (id, memory_id, conflicting_memory_id, similarity, conflict_content_snapshot, reason, created_at)
278
- VALUES (?, ?, ?, ?, ?, 'similarity_dedup', ?)`).run(t(),e.memoryId,e.conflictingMemoryId,e.similarity,e.conflictContentSnapshot,n)}resolveReviewEvents(e){let t=new Date().toISOString();this.#e.db.prepare(`UPDATE memory_review_events SET resolved_at = ? WHERE memory_id = ? AND resolved_at IS NULL`).run(t,e)}getPinnedCharCount(e){return e===void 0?(this.#e.db.prepare(`SELECT COALESCE(SUM(LENGTH(content)), 0) as total FROM memories WHERE pinned = 1`).get()??{total:0}).total:(this.#e.db.prepare(`SELECT COALESCE(SUM(LENGTH(content)), 0) as total FROM memories
279
- WHERE pinned = 1 AND ${this.#n()}`).get(e)??{total:0}).total}stats(e){let t=Object.fromEntries(S.map(e=>[e,0]));if(e!==void 0){let n=this.#e.db.prepare(`SELECT type, COUNT(*) as count FROM memories
308
+ VALUES (?, ?, ?, ?, ?, 'similarity_dedup', ?)`).run(i(),e.memoryId,e.conflictingMemoryId,e.similarity,e.conflictContentSnapshot,t)}resolveReviewEvents(e){let t=new Date().toISOString();this.#e.db.prepare(`UPDATE memory_review_events SET resolved_at = ? WHERE memory_id = ? AND resolved_at IS NULL`).run(t,e)}getPinnedCharCount(e){return e===void 0?(this.#e.db.prepare(`SELECT COALESCE(SUM(LENGTH(content)), 0) as total FROM memories WHERE pinned = 1`).get()??{total:0}).total:(this.#e.db.prepare(`SELECT COALESCE(SUM(LENGTH(content)), 0) as total FROM memories
309
+ WHERE pinned = 1 AND ${this.#n()}`).get(e)??{total:0}).total}stats(e){let t=Object.fromEntries(T.map(e=>[e,0]));if(e!==void 0){let n=this.#e.db.prepare(`SELECT type, COUNT(*) as count FROM memories
280
310
  WHERE ${this.#n()}
281
- GROUP BY type`).all(e);for(let e of n){let n=C.safeParse(e.type);n.success&&(t[n.data]=e.count)}let r=this.#e.db.prepare(`SELECT COUNT(*) as total, SUM(pinned) as pinned,
311
+ GROUP BY type`).all(e);for(let e of n){let n=E.safeParse(e.type);n.success&&(t[n.data]=e.count)}let r=this.#e.db.prepare(`SELECT COUNT(*) as total, SUM(pinned) as pinned,
282
312
  COALESCE(SUM(CASE WHEN pinned = 1 THEN LENGTH(content) ELSE 0 END), 0) as pinBudgetChars
283
313
  FROM memories WHERE ${this.#n()}`).get(e)??{total:0,pinned:0,pinBudgetChars:0},i=this.#e.db.prepare(`SELECT COUNT(DISTINCT e.memory_id) as needsReview
284
314
  FROM memory_review_events e
285
315
  JOIN memories m ON m.id = e.memory_id
286
316
  WHERE e.resolved_at IS NULL
287
- AND ${this.#n(`m`)}`).get(e)??{needsReview:0};return{byType:t,total:r.total,pinned:r.pinned??0,needsReview:i.needsReview,pinBudgetChars:r.pinBudgetChars}}let n=this.#e.db.prepare(`SELECT type, COUNT(*) as count FROM memories GROUP BY type`).all();for(let e of n){let n=C.safeParse(e.type);n.success&&(t[n.data]=e.count)}let r=this.#e.db.prepare(`SELECT COUNT(*) as total, SUM(pinned) as pinned FROM memories`).get()??{total:0,pinned:0},i=this.#e.db.prepare(`SELECT COUNT(DISTINCT memory_id) as needsReview FROM memory_review_events WHERE resolved_at IS NULL`).get()??{needsReview:0};return{byType:t,total:r.total,pinned:r.pinned??0,needsReview:i.needsReview,pinBudgetChars:this.getPinnedCharCount()}}setPin(e,t){if(this.#e.db.prepare(`SELECT * FROM memories WHERE id = ?`).get(e)===void 0)throw Error(`Memory not found: ${e}`);let n=new Date().toISOString();this.#e.db.prepare(`UPDATE memories SET pinned = ?, updated_at = ? WHERE id = ?`).run(+!!t,n,e);let r=N.parse(this.#e.db.prepare(`SELECT * FROM memories WHERE id = ?`).get(e)),i=this.#t.getProjectsForMemories([e]),a=this.#r([e]);return F(r,i.get(e)??[],a.get(e)??[])}incrementAccessCount(e){this.#e.db.prepare(`UPDATE memories SET access_count = access_count + 1 WHERE id = ?`).run(e)}exportAll(){return this.#e.db.prepare(`SELECT m.*, e.embedding FROM memories m LEFT JOIN embeddings e ON e.rowid = m.rowid ORDER BY m.created_at DESC`).all().map(e=>({id:e.id,content:e.content,type:C.parse(e.type),tags:w.parse(JSON.parse(e.tags)),sourceHarness:e.source,accessCount:e.access_count,pinned:e.pinned!==0,createdAt:e.created_at,updatedAt:e.updated_at,embedding:e.embedding===null?null:new Float32Array(e.embedding.buffer,e.embedding.byteOffset,e.embedding.byteLength/4)}))}importAll(e){let t=this.#e.db.prepare(`INSERT OR REPLACE INTO memories (id, content, type, tags, source, access_count, pinned, created_at, updated_at)
317
+ AND ${this.#n(`m`)}`).get(e)??{needsReview:0};return{byType:t,total:r.total,pinned:r.pinned??0,needsReview:i.needsReview,pinBudgetChars:r.pinBudgetChars}}let n=this.#e.db.prepare(`SELECT type, COUNT(*) as count FROM memories GROUP BY type`).all();for(let e of n){let n=E.safeParse(e.type);n.success&&(t[n.data]=e.count)}let r=this.#e.db.prepare(`SELECT COUNT(*) as total, SUM(pinned) as pinned FROM memories`).get()??{total:0,pinned:0},i=this.#e.db.prepare(`SELECT COUNT(DISTINCT memory_id) as needsReview FROM memory_review_events WHERE resolved_at IS NULL`).get()??{needsReview:0};return{byType:t,total:r.total,pinned:r.pinned??0,needsReview:i.needsReview,pinBudgetChars:this.getPinnedCharCount()}}reviewQueueStats(e){let t=e===void 0?`JOIN memories m ON m.id = e.memory_id WHERE e.resolved_at IS NULL`:`JOIN memories m ON m.id = e.memory_id
318
+ WHERE e.resolved_at IS NULL AND ${this.#n(`m`)}`,n=e===void 0?[]:[e],r=this.#e.db.prepare(`SELECT
319
+ CASE
320
+ WHEN e.similarity >= 0.85 THEN 'high'
321
+ WHEN e.similarity >= 0.80 THEN 'mid'
322
+ ELSE 'low'
323
+ END AS band,
324
+ COUNT(DISTINCT e.memory_id) AS count
325
+ FROM memory_review_events e ${t}
326
+ GROUP BY band`).all(...n),i=this.#e.db.prepare(`SELECT m.type, COUNT(DISTINCT e.memory_id) AS count
327
+ FROM memory_review_events e ${t}
328
+ GROUP BY m.type`).all(...n),a=this.#e.db.prepare(`SELECT COUNT(*) AS pairs FROM memory_review_events e ${t}`).get(...n)??{pairs:0},o={high:0,mid:0,low:0};for(let e of r)(e.band===`high`||e.band===`mid`||e.band===`low`)&&(o[e.band]=e.count);let s={};for(let e of i){let t=E.safeParse(e.type);t.success&&(s[t.data]=e.count)}return{pairs:a.pairs,byBand:o,byType:s}}setPin(e,t){if(this.#e.db.prepare(`SELECT * FROM memories WHERE id = ?`).get(e)===void 0)throw Error(`Memory not found: ${e}`);let n=new Date().toISOString();this.#e.db.prepare(`UPDATE memories SET pinned = ?, updated_at = ? WHERE id = ?`).run(+!!t,n,e);let r=L.parse(this.#e.db.prepare(`SELECT * FROM memories WHERE id = ?`).get(e)),i=this.#t.getProjectsForMemories([e]),a=this.#r([e]);return z(r,i.get(e)??[],a.get(e)??[])}incrementAccessCount(e){this.#e.db.prepare(`UPDATE memories SET access_count = access_count + 1 WHERE id = ?`).run(e)}exportAll(){return this.#e.db.prepare(`SELECT m.*, e.embedding FROM memories m LEFT JOIN embeddings e ON e.rowid = m.rowid ORDER BY m.created_at DESC`).all().map(e=>({id:e.id,content:e.content,type:E.parse(e.type),tags:D.parse(JSON.parse(e.tags)),sourceHarness:e.source,accessCount:e.access_count,pinned:e.pinned!==0,createdAt:e.created_at,updatedAt:e.updated_at,embedding:e.embedding===null?null:new Float32Array(e.embedding.buffer,e.embedding.byteOffset,e.embedding.byteLength/4)}))}importAll(e){let t=this.#e.db.prepare(`INSERT OR REPLACE INTO memories (id, content, type, tags, source, access_count, pinned, created_at, updated_at)
288
329
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`),n=this.#e.db.prepare(`INSERT OR REPLACE INTO embeddings (rowid, embedding) SELECT m.rowid, ? FROM memories m WHERE m.id = ?`);this.#e.db.transaction(()=>{for(let r of e)t.run(r.id,r.content,r.type,JSON.stringify(r.tags),r.sourceHarness,r.accessCount,+!!r.pinned,r.createdAt,r.updatedAt),r.embedding!==null&&n.run(Buffer.from(r.embedding.buffer,r.embedding.byteOffset,r.embedding.byteLength),r.id)})()}#n(e=`memories`){return`EXISTS (
289
330
  SELECT 1 FROM memory_projects mp JOIN projects p ON p.id = mp.project_id
290
- WHERE mp.memory_id = ${e}.id AND (p.scope_hash = ? OR p.scope_hash = '${W}')
331
+ WHERE mp.memory_id = ${e}.id AND (p.scope_hash = ? OR p.scope_hash = '${t}')
291
332
  )`}#r(e,t){if(e.length===0)return new Map;let n=e.map(()=>`?`).join(`, `),r=t?.unresolvedOnly===!0?`AND resolved_at IS NULL`:``,i=this.#e.db.prepare(`SELECT * FROM memory_review_events
292
333
  WHERE memory_id IN (${n}) ${r}
293
- ORDER BY created_at DESC`).all(...e),a=new Map;for(let e of i){let t=I(O.parse(e)),n=a.get(t.memoryId)??[];n.push(t),a.set(t.memoryId,n)}return a}};function Fe(e,t){return new q(e,t)}const J=ne(te);function Y(t){return e(`sha256`).update(t).digest(`hex`).slice(0,16)}async function X(){try{let{stdout:e}=await J(`git`,[`remote`,`get-url`,`origin`]),t=e.trim();if(t){let e=Y(t);return{hash:e,name:t.split(`/`).pop()?.replace(/\.git$/,``)??e.slice(0,8)}}}catch{}let e=process.cwd(),t=Y(e);return{hash:t,name:e.split(/[/\\]/).filter(Boolean).pop()??t.slice(0,8)}}async function Ie(){try{let{stdout:e}=await J(`git`,[`remote`,`get-url`,`origin`]),t=e.trim();if(t)return Y(t)}catch{}return Y(process.cwd())}const Le=[{name:`scope-to-projects`,description:`Rename the auto-migrated project for the current directory from its generic hash-derived name to the resolved repo/directory name.`}];async function Re(e){let t=await X(),n=e.getByHash(t.hash);if(n===void 0)return null;let r=n.name,i=e.countMemories(n.id);return e.rename(n.id,t.name),{migration:`scope-to-projects`,oldName:r,newName:t.name,memoryCount:i}}var ze=class{#e;constructor(e){this.#e=e}upsertByHash(e,n){if(!/^[0-9a-f]{16}$/.test(e))throw Error(`Invalid scope hash "${e}": expected 16 lowercase hex characters`);let r=new Date().toISOString(),i=e===`0000000000000000`?U:t(),a=e===`0000000000000000`?G:n;return this.#e.db.prepare(`INSERT OR IGNORE INTO projects (id, name, scope_hash, created_at, updated_at) VALUES (?, ?, ?, ?, ?)`).run(i,a,e,r,r),L(P.parse(this.#e.db.prepare(`SELECT * FROM projects WHERE scope_hash = ?`).get(e)))}rename(e,t){let n=new Date().toISOString();this.#e.db.prepare(`UPDATE projects SET name = ?, updated_at = ? WHERE id = ?`).run(t,n,e);let r=this.#e.db.prepare(`SELECT * FROM projects WHERE id = ?`).get(e);if(r===void 0)throw Error(`Project not found: ${e}`);return L(r)}list(){return this.#e.db.prepare(`SELECT * FROM projects ORDER BY name ASC`).all().map(L)}getByHash(e){let t=this.#e.db.prepare(`SELECT * FROM projects WHERE scope_hash = ?`).get(e);return t===void 0?void 0:L(t)}getByName(e){let t=this.#e.db.prepare(`SELECT * FROM projects WHERE name = ? LIMIT 1`).get(e);return t===void 0?void 0:L(t)}addAssociation(e,t){this.#e.db.prepare(`INSERT OR IGNORE INTO memory_projects (memory_id, project_id) VALUES (?, ?)`).run(e,t)}removeAssociation(e,t){this.#e.db.prepare(`DELETE FROM memory_projects WHERE memory_id = ? AND project_id = ?`).run(e,t)}countMemories(e){return this.#e.db.prepare(`SELECT COUNT(*) AS count FROM memory_projects WHERE project_id = ?`).get(e)?.count??0}getProjectsForMemories(e){if(e.length===0)return new Map;let t=e.map(()=>`?`).join(`,`),n=this.#e.db.prepare(`SELECT p.*, mp.memory_id FROM projects p
334
+ ORDER BY created_at DESC`).all(...e),a=new Map;for(let e of i){let t=B(j.parse(e)),n=a.get(t.memoryId)??[];n.push(t),a.set(t.memoryId,n)}return a}};function Ie(e,t){return new X(e,t)}const Le=ne(te);function Z(e){return r(`sha256`).update(e).digest(`hex`).slice(0,16)}async function Re(){try{let{stdout:e}=await Le(`git`,[`remote`,`get-url`,`origin`]),t=e.trim();if(t){let e=Z(t);return{hash:e,name:t.split(`/`).pop()?.replace(/\.git$/,``)??e.slice(0,8)}}}catch{}let e=process.cwd(),t=Z(e);return{hash:t,name:e.split(/[/\\]/).filter(Boolean).pop()??t.slice(0,8)}}async function ze(){try{let{stdout:e}=await Le(`git`,[`remote`,`get-url`,`origin`]),t=e.trim();if(t)return Z(t)}catch{}return Z(process.cwd())}const Be=[{name:`scope-to-projects`,description:`Rename the auto-migrated project for the current directory from its generic hash-derived name to the resolved repo/directory name.`}];async function Ve(e){let t=await Re(),n=e.getByHash(t.hash);if(n===void 0)return null;let r=n.name,i=e.countMemories(n.id);return e.rename(n.id,t.name),{migration:`scope-to-projects`,oldName:r,newName:t.name,memoryCount:i}}var He=class{#e;constructor(e){this.#e=e}upsertByHash(t,r){if(!/^[0-9a-f]{16}$/.test(t))throw Error(`Invalid scope hash "${t}": expected 16 lowercase hex characters`);let a=new Date().toISOString(),o=t===`0000000000000000`?n:i(),s=t===`0000000000000000`?e:r;return this.#e.db.prepare(`INSERT OR IGNORE INTO projects (id, name, scope_hash, created_at, updated_at) VALUES (?, ?, ?, ?, ?)`).run(o,s,t,a,a),V(R.parse(this.#e.db.prepare(`SELECT * FROM projects WHERE scope_hash = ?`).get(t)))}rename(e,t){let n=new Date().toISOString();this.#e.db.prepare(`UPDATE projects SET name = ?, updated_at = ? WHERE id = ?`).run(t,n,e);let r=this.#e.db.prepare(`SELECT * FROM projects WHERE id = ?`).get(e);if(r===void 0)throw Error(`Project not found: ${e}`);return V(r)}list(){return this.#e.db.prepare(`SELECT * FROM projects ORDER BY name ASC`).all().map(V)}getByHash(e){let t=this.#e.db.prepare(`SELECT * FROM projects WHERE scope_hash = ?`).get(e);return t===void 0?void 0:V(t)}getByName(e){let t=this.#e.db.prepare(`SELECT * FROM projects WHERE name = ? LIMIT 1`).get(e);return t===void 0?void 0:V(t)}addAssociation(e,t){this.#e.db.prepare(`INSERT OR IGNORE INTO memory_projects (memory_id, project_id) VALUES (?, ?)`).run(e,t)}removeAssociation(e,t){this.#e.db.prepare(`DELETE FROM memory_projects WHERE memory_id = ? AND project_id = ?`).run(e,t)}countMemories(e){return this.#e.db.prepare(`SELECT COUNT(*) AS count FROM memory_projects WHERE project_id = ?`).get(e)?.count??0}getProjectsForMemories(e){if(e.length===0)return new Map;let t=e.map(()=>`?`).join(`,`),n=this.#e.db.prepare(`SELECT p.*, mp.memory_id FROM projects p
294
335
  JOIN memory_projects mp ON mp.project_id = p.id
295
- WHERE mp.memory_id IN (${t})`).all(...e),r=new Map;for(let e of n){let t=r.get(e.memory_id)??[];t.push(L(e)),r.set(e.memory_id,t)}return r}};function Be(e){return new ze(e)}const Ve={correction:1,preference:.8,decision:.6,learning:.4,fact:.2};function He(e,t,n){let r=Ve[e.type],i=e.accessCount/(e.accessCount+10),a=1/(1+(n-new Date(e.updatedAt).getTime())/864e5),o=+!!e.pinned;return t*.4+r*.25+i*.2+a*.1+o*.05}async function Z(e,t){let{query:n,type:r,projectHash:i,limit:a=10,includePinned:o}=A.parse(e),{activityLogger:s=x}=t,c=await t.embedder.embed(n),l=Buffer.from(c.buffer),u=t.adapter.findByEmbedding(l,{type:r,projectHash:i,includePinned:o}),d=Date.now(),f=u.filter(e=>e.cosineSim>0).map(e=>{let{cosineSim:t,...n}=e;return{...n,score:He(n,t,d)}});f.sort((e,t)=>t.score-e.score);let p=f.slice(0,a);for(let e of p)t.repo.incrementAccessCount(e.id);return s.logEvent({projectHash:i??`0000000000000000`,eventType:`memory.queried`,payload:{resultCount:p.length,topScores:p.slice(0,3).map(e=>e.score)}}),p}var Ue=class{#e;constructor(e){this.#e=e}findByEmbedding(e,t){let{type:n,projectHash:r,includePinned:i}=t,a=[],o=[e],s=``;i||a.push(`m.pinned = 0`),n!==void 0&&(a.push(`m.type = ?`),o.push(n)),r!==void 0&&(s=`JOIN memory_projects mp ON mp.memory_id = m.id JOIN projects p ON p.id = mp.project_id`,a.push(`(p.scope_hash = ? OR p.scope_hash = ?)`),o.push(r,W));let c=a.length>0?`WHERE ${a.join(` AND `)}`:``,l=`
336
+ WHERE mp.memory_id IN (${t})`).all(...e),r=new Map;for(let e of n){let t=r.get(e.memory_id)??[];t.push(V(e)),r.set(e.memory_id,t)}return r}};function Ue(e){return new He(e)}const We={correction:1,preference:.8,decision:.6,learning:.4,fact:.2};function Ge(e,t,n){let r=We[e.type],i=e.accessCount/(e.accessCount+10),a=1/(1+(n-new Date(e.updatedAt).getTime())/864e5),o=+!!e.pinned;return t*.4+r*.25+i*.2+a*.1+o*.05}async function Ke(e,t){let{query:n,type:r,projectHash:i,limit:a=10,includePinned:o}=N.parse(e),{activityLogger:s=w}=t,c=await t.embedder.embed(n),l=Buffer.from(c.buffer),u=t.adapter.findByEmbedding(l,{type:r,projectHash:i,includePinned:o}),d=Date.now(),f=u.filter(e=>e.cosineSim>0).map(e=>{let{cosineSim:t,...n}=e;return{...n,score:Ge(n,t,d)}});f.sort((e,t)=>t.score-e.score);let p=f.slice(0,a);for(let e of p)t.repo.incrementAccessCount(e.id);return s.logEvent({projectHash:i??`0000000000000000`,eventType:`memory.queried`,payload:{resultCount:p.length,topScores:p.slice(0,3).map(e=>e.score)}}),p}var qe=class{#e;constructor(e){this.#e=e}findByEmbedding(e,n){let{type:r,projectHash:i,includePinned:a}=n,o=[],s=[e],c=``;a||o.push(`m.pinned = 0`),r!==void 0&&(o.push(`m.type = ?`),s.push(r)),i!==void 0&&(c=`JOIN memory_projects mp ON mp.memory_id = m.id JOIN projects p ON p.id = mp.project_id`,o.push(`(p.scope_hash = ? OR p.scope_hash = ?)`),s.push(i,t));let l=o.length>0?`WHERE ${o.join(` AND `)}`:``,u=`
296
337
  SELECT m.*, (1 - vec_distance_cosine(e.embedding, ?)) AS cosine_sim
297
338
  FROM memories m JOIN embeddings e ON e.rowid = m.rowid
298
- ${s}
299
339
  ${c}
300
- `;return this.#e.db.prepare(l).all(...o).map(e=>({...F(e,[]),cosineSim:e.cosine_sim}))}},We=class{#e;#t;#n;#r;constructor(e,t,n,r=x){this.#e=e,this.#t=t,this.#n=n,this.#r=r}async query(e){return Z(e,{adapter:new Ue(this.#e),repo:this.#n,embedder:this.#t,activityLogger:this.#r})}};function Q(e,t){let n=t.repo.stats(e.projectHash);return e.synthesis!==void 0&&e.synthesis.length>0?{stats:n.byType,pinnedGlobal:[],pinnedProject:[],synthesis:e.synthesis}:{stats:n.byType,pinnedGlobal:t.repo.listPinnedGlobal(),pinnedProject:t.repo.listPinnedForProject(e.projectHash)}}function Ge(){return[...S]}var Ke=class{#e;constructor(e){this.#e=e}getSessionContext(e,t){return Q({projectHash:e,synthesis:t},{repo:this.#e})}},qe=class{#e;#t;#n;#r=new Set;#i=new Map;#a=!1;#o;#s=new Map;constructor(e,t,n){this.#e=e,this.#t=t,this.#n=n}async init(){this.#e.clearStaleInFlight(this.#t.inFlightTimeoutMs??12e4),this.#e.expireStale();let e=this.#e.getExpiredOrDirtyScopes();for(let{scope:t}of e)this.#r.add(t);this.#a=!0,await this.#l()}shutdown(){this.#a=!1,this.#o!==void 0&&(clearTimeout(this.#o),this.#o=void 0);let e=[...this.#s.values()];return e.length===0?Promise.resolve():Promise.race([Promise.allSettled(e).then(()=>void 0),new Promise(e=>setTimeout(e,5e3))])}markDirty(e){this.#r.add(e)}#c(){if(!this.#a)return;let e=this.#t.debounceMs??45e3;this.#o=setTimeout(()=>{this.#l()},e)}async#l(){let e=[...this.#r];for(let t of e){let e=this.#t.inFlightTimeoutMs??12e4,n=this.#e.getSynthesis(t);if(n?.inFlightSince!==null&&n?.inFlightSince!==void 0){if(Date.now()-new Date(n.inFlightSince).getTime()<e)continue;this.#e.clearInFlight(t)}this.#r.delete(t);let r=this.#u(t).finally(()=>{this.#s.delete(t)});this.#s.set(t,r)}this.#c()}async#u(e){this.#e.markInFlight(e);try{let t=e===`0000000000000000`?void 0:e,n=await this.#n.run(e,t),r=this.#e.computeSourceMemoryHash(e);this.#e.saveSynthesis(e,n,r),this.#i.delete(e)}catch(t){let n=(this.#i.get(e)??0)+1;this.#i.set(e,n);let r=Math.min(n,5),i=(this.#t.debounceMs??45e3)*r;process.stderr.write(`membank synthesis: error for scope=${e} failures=${n} backoff=${i}ms: ${t instanceof Error?t.message:String(t)}\n`),setTimeout(()=>{this.#r.add(e)},i),this.#e.clearInFlight(e)}}};async function Je(e,t){let n=e===`0000000000000000`?void 0:e;t.synthRepo.markInFlight(e);try{let[r,i]=await Promise.all([t.agentRunner.run(e,n),Promise.resolve(t.synthRepo.computeSourceMemoryHash(e))]);return t.synthRepo.saveSynthesis(e,r,i),r}catch(n){throw t.synthRepo.clearInFlight(e),n}}var Ye=class{#e;constructor(e,t){this.#e=e}async run(e,t){let r=m({name:`membank-synthesis-tools`,version:`1.0.0`,tools:[g(`query_memory`,`Search memories by semantic similarity`,{query:n.string().describe(`Search text`),limit:n.number().optional().describe(`Maximum results to return`),global:n.boolean().optional().describe(`Query global memories only when true, otherwise current project scope`)},async({query:e,limit:n,global:r})=>({content:[{type:`text`,text:await this.#e.queryMemory({query:e,limit:n,global:r,projectHash:t})}]}),{annotations:{readOnlyHint:!0}}),g(`get_memory_summary`,`Returns aggregate stats: total memories, counts by type, pinned count, review queue size`,{},async()=>({content:[{type:`text`,text:await this.#e.getMemorySummary()}]}),{annotations:{readOnlyHint:!0}})]}),i=`Synthesize the memories for ${e===`0000000000000000`?`global (across all projects)`:`project scope: ${e}`}. Use get_memory_summary first to understand the overall state, then use query_memory to retrieve relevant memories (query with broad terms like "preferences", "corrections", "decisions", "key facts"). After gathering information, produce a concise synthesis of the most important things to remember about this user. Output only the synthesis text — no preamble, no metadata.`,a=Date.now(),o=Object.fromEntries(Object.entries(process.env).filter(e=>e[1]!==void 0)),s=h({prompt:i,options:{model:`claude-haiku-4-5-20251001`,systemPrompt:`You are a memory synthesizer. Your job is to read the user's stored memories and produce a concise, well-structured summary of what's most important to remember about this user — their preferences, corrections, decisions, and key facts. Pinned memories are higher fidelity and should be weighted more heavily. Exclude transient or ephemeral details. Output plain text suitable for injection into an LLM context window. Be concise — target 200-400 words.`,mcpServers:{"membank-synthesis-tools":r},allowedTools:[`mcp__membank-synthesis-tools__query_memory`,`mcp__membank-synthesis-tools__get_memory_summary`],disallowedTools:[`mcp__membank__*`],settingSources:[],permissionMode:`bypassPermissions`,env:o}}),c=``;for await(let e of s)if(e.type===`result`)if(e.subtype===`success`)c=e.result;else{let t=`errors`in e&&Array.isArray(e.errors)?`: ${e.errors.join(`; `)}`:``;throw Error(`Synthesis agent failed: ${e.subtype}${t}`)}let l=Date.now()-a;if(process.stderr.write(`membank synthesis: scope=${e} duration=${l}ms\n`),c===``)throw Error(`Synthesis agent returned empty result`);return c}};function Xe(e,t){return new Ye(e,t)}function $(e){return M.parse({id:e.id,scope:e.scope,content:e.content,sourceMemoryHash:e.source_memory_hash,synthesizedAt:e.synthesized_at,expiresAt:e.expires_at,inFlightSince:e.in_flight_since,createdAt:e.created_at,updatedAt:e.updated_at})}var Ze=class{#e;constructor(e){this.#e=e}saveSynthesis(e,n,r){let i=new Date().toISOString(),a=new Date(Date.now()+720*60*60*1e3).toISOString();if(this.#e.db.prepare(`SELECT id FROM syntheses WHERE scope = ?`).get(e)!==void 0)this.#e.db.prepare(`UPDATE syntheses
340
+ ${l}
341
+ `;return this.#e.db.prepare(u).all(...s).map(e=>({...z(e,[]),cosineSim:e.cosine_sim}))}},Je=class{#e;#t;#n;#r;constructor(e,t,n,r=w){this.#e=e,this.#t=t,this.#n=n,this.#r=r}async query(e){return Ke(e,{adapter:new qe(this.#e),repo:this.#n,embedder:this.#t,activityLogger:this.#r})}};function Q(e,t){let n=t.repo.stats(e.projectHash);return e.synthesis!==void 0&&e.synthesis.length>0?{stats:n.byType,pinnedGlobal:[],pinnedProject:[],synthesis:e.synthesis}:{stats:n.byType,pinnedGlobal:t.repo.listPinnedGlobal(),pinnedProject:t.repo.listPinnedForProject(e.projectHash)}}function Ye(){return[...T]}var Xe=class{#e;constructor(e){this.#e=e}getSessionContext(e,t){return Q({projectHash:e,synthesis:t},{repo:this.#e})}},Ze=class{#e;#t;#n;#r=new Set;#i=new Map;#a=!1;#o;#s=new Map;constructor(e,t,n){this.#e=e,this.#t=t,this.#n=n}async init(){this.#e.clearStaleInFlight(this.#t.inFlightTimeoutMs??12e4),this.#e.expireStale();let e=this.#e.getExpiredOrDirtyScopes();for(let{scope:t}of e)this.#r.add(t);this.#a=!0,await this.#l()}shutdown(){this.#a=!1,this.#o!==void 0&&(clearTimeout(this.#o),this.#o=void 0);let e=[...this.#s.values()];return e.length===0?Promise.resolve():Promise.race([Promise.allSettled(e).then(()=>void 0),new Promise(e=>setTimeout(e,5e3))])}markDirty(e){this.#r.add(e)}#c(){if(!this.#a)return;let e=this.#t.debounceMs??45e3;this.#o=setTimeout(()=>{this.#l()},e)}async#l(){let e=[...this.#r];for(let t of e){let e=this.#t.inFlightTimeoutMs??12e4,n=this.#e.getSynthesis(t);if(n?.inFlightSince!==null&&n?.inFlightSince!==void 0){if(Date.now()-new Date(n.inFlightSince).getTime()<e)continue;this.#e.clearInFlight(t)}this.#r.delete(t);let r=this.#u(t).finally(()=>{this.#s.delete(t)});this.#s.set(t,r)}this.#c()}async#u(e){this.#e.markInFlight(e);try{let t=e===`0000000000000000`?void 0:e,n=await this.#n.run(e,t),r=this.#e.computeSourceMemoryHash(e);this.#e.saveSynthesis(e,n,r),this.#i.delete(e)}catch(t){let n=(this.#i.get(e)??0)+1;this.#i.set(e,n);let r=Math.min(n,5),i=(this.#t.debounceMs??45e3)*r;process.stderr.write(`membank synthesis: error for scope=${e} failures=${n} backoff=${i}ms: ${t instanceof Error?t.message:String(t)}\n`),setTimeout(()=>{this.#r.add(e)},i),this.#e.clearInFlight(e)}}};async function Qe(e,t){let n=e===`0000000000000000`?void 0:e;t.synthRepo.markInFlight(e);try{let[r,i]=await Promise.all([t.agentRunner.run(e,n),Promise.resolve(t.synthRepo.computeSourceMemoryHash(e))]);return t.synthRepo.saveSynthesis(e,r,i),r}catch(n){throw t.synthRepo.clearInFlight(e),n}}var $e=class{#e;constructor(e,t){this.#e=e}async run(e,t){let n=_({name:`membank-synthesis-tools`,version:`1.0.0`,tools:[y(`query_memory`,`Search memories by semantic similarity`,{query:a.string().describe(`Search text`),limit:a.number().optional().describe(`Maximum results to return`),global:a.boolean().optional().describe(`Query global memories only when true, otherwise current project scope`)},async({query:e,limit:n,global:r})=>({content:[{type:`text`,text:await this.#e.queryMemory({query:e,limit:n,global:r,projectHash:t})}]}),{annotations:{readOnlyHint:!0}}),y(`get_memory_summary`,`Returns aggregate stats: total memories, counts by type, pinned count, review queue size`,{},async()=>({content:[{type:`text`,text:await this.#e.getMemorySummary()}]}),{annotations:{readOnlyHint:!0}})]}),r=`Synthesize the memories for ${e===`0000000000000000`?`global (across all projects)`:`project scope: ${e}`}. Use get_memory_summary first to understand the overall state, then use query_memory to retrieve relevant memories (query with broad terms like "preferences", "corrections", "decisions", "key facts"). After gathering information, produce a concise synthesis of the most important things to remember about this user. Output only the synthesis text — no preamble, no metadata.`,i=Date.now(),o=Object.fromEntries(Object.entries(process.env).filter(e=>e[1]!==void 0)),s=v({prompt:r,options:{model:`claude-haiku-4-5-20251001`,systemPrompt:`You are a memory synthesizer. Your job is to read the user's stored memories and produce a concise, well-structured summary of what's most important to remember about this user — their preferences, corrections, decisions, and key facts. Pinned memories are higher fidelity and should be weighted more heavily. Exclude transient or ephemeral details. Output plain text suitable for injection into an LLM context window. Be concise — target 200-400 words.`,mcpServers:{"membank-synthesis-tools":n},allowedTools:[`mcp__membank-synthesis-tools__query_memory`,`mcp__membank-synthesis-tools__get_memory_summary`],disallowedTools:[`mcp__membank__*`],settingSources:[],permissionMode:`bypassPermissions`,env:o}}),c=``;for await(let e of s)if(e.type===`result`)if(e.subtype===`success`)c=e.result;else{let t=`errors`in e&&Array.isArray(e.errors)?`: ${e.errors.join(`; `)}`:``;throw Error(`Synthesis agent failed: ${e.subtype}${t}`)}let l=Date.now()-i;if(process.stderr.write(`membank synthesis: scope=${e} duration=${l}ms\n`),c===``)throw Error(`Synthesis agent returned empty result`);return c}};function et(e,t){return new $e(e,t)}function $(e){return I.parse({id:e.id,scope:e.scope,content:e.content,sourceMemoryHash:e.source_memory_hash,synthesizedAt:e.synthesized_at,expiresAt:e.expires_at,inFlightSince:e.in_flight_since,createdAt:e.created_at,updatedAt:e.updated_at})}var tt=class{#e;constructor(e){this.#e=e}saveSynthesis(e,t,n){let r=new Date().toISOString(),a=new Date(Date.now()+720*60*60*1e3).toISOString();if(this.#e.db.prepare(`SELECT id FROM syntheses WHERE scope = ?`).get(e)!==void 0)this.#e.db.prepare(`UPDATE syntheses
301
342
  SET content = ?, source_memory_hash = ?, synthesized_at = ?, expires_at = ?,
302
343
  in_flight_since = NULL, updated_at = ?
303
- WHERE scope = ?`).run(n,r,i,a,i,e);else{let o=t();this.#e.db.prepare(`INSERT INTO syntheses
344
+ WHERE scope = ?`).run(t,n,r,a,r,e);else{let o=i();this.#e.db.prepare(`INSERT INTO syntheses
304
345
  (id, scope, content, source_memory_hash, synthesized_at, expires_at,
305
346
  in_flight_since, created_at, updated_at)
306
- VALUES (?, ?, ?, ?, ?, ?, NULL, ?, ?)`).run(o,e,n,r,i,a,i,i)}let o=this.#e.db.prepare(`SELECT * FROM syntheses WHERE scope = ?`).get(e);if(o===void 0)throw Error(`Failed to save synthesis for scope: ${e}`);return $(o)}getSynthesis(e){let t=this.#e.db.prepare(`SELECT * FROM syntheses WHERE scope = ?`).get(e);return t===void 0?void 0:$(t)}listAll(){return this.#e.db.prepare(`SELECT * FROM syntheses ORDER BY scope`).all().map($)}markInFlight(e){let n=new Date().toISOString();if(this.#e.db.prepare(`SELECT id FROM syntheses WHERE scope = ?`).get(e)!==void 0)this.#e.db.prepare(`UPDATE syntheses SET in_flight_since = ?, updated_at = ? WHERE scope = ?`).run(n,n,e);else{let r=t(),i=new Date(Date.now()+720*60*60*1e3).toISOString();this.#e.db.prepare(`INSERT INTO syntheses
347
+ VALUES (?, ?, ?, ?, ?, ?, NULL, ?, ?)`).run(o,e,t,n,r,a,r,r)}let o=this.#e.db.prepare(`SELECT * FROM syntheses WHERE scope = ?`).get(e);if(o===void 0)throw Error(`Failed to save synthesis for scope: ${e}`);return $(o)}getSynthesis(e){let t=this.#e.db.prepare(`SELECT * FROM syntheses WHERE scope = ?`).get(e);return t===void 0?void 0:$(t)}listAll(){return this.#e.db.prepare(`SELECT * FROM syntheses ORDER BY scope`).all().map($)}markInFlight(e){let t=new Date().toISOString();if(this.#e.db.prepare(`SELECT id FROM syntheses WHERE scope = ?`).get(e)!==void 0)this.#e.db.prepare(`UPDATE syntheses SET in_flight_since = ?, updated_at = ? WHERE scope = ?`).run(t,t,e);else{let n=i(),r=new Date(Date.now()+720*60*60*1e3).toISOString();this.#e.db.prepare(`INSERT INTO syntheses
307
348
  (id, scope, content, source_memory_hash, synthesized_at, expires_at,
308
349
  in_flight_since, created_at, updated_at)
309
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(r,e,`pending`,``,n,i,n,n,n)}}clearInFlight(e){let t=new Date().toISOString();this.#e.db.prepare(`UPDATE syntheses SET in_flight_since = NULL, updated_at = ? WHERE scope = ?`).run(t,e)}clearStaleInFlight(e){let t=new Date(Date.now()-e).toISOString(),n=new Date().toISOString();this.#e.db.prepare(`UPDATE syntheses SET in_flight_since = NULL, updated_at = ? WHERE in_flight_since IS NOT NULL AND in_flight_since < ?`).run(n,t)}computeSourceMemoryHash(t){let n=this.#e.db.prepare(`SELECT m.content FROM memories m
350
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(n,e,`pending`,``,t,r,t,t,t)}}clearInFlight(e){let t=new Date().toISOString();this.#e.db.prepare(`UPDATE syntheses SET in_flight_since = NULL, updated_at = ? WHERE scope = ?`).run(t,e)}clearStaleInFlight(e){let t=new Date(Date.now()-e).toISOString(),n=new Date().toISOString();this.#e.db.prepare(`UPDATE syntheses SET in_flight_since = NULL, updated_at = ? WHERE in_flight_since IS NOT NULL AND in_flight_since < ?`).run(n,t)}computeSourceMemoryHash(e){let t=this.#e.db.prepare(`SELECT m.content FROM memories m
310
351
  JOIN memory_projects mp ON mp.memory_id = m.id
311
352
  JOIN projects p ON p.id = mp.project_id
312
353
  WHERE p.scope_hash = ?
313
- ORDER BY m.id`).all(t);return e(`sha256`).update(JSON.stringify(n.map(e=>e.content))).digest(`hex`)}getExpiredOrDirtyScopes(){let e=this.getAllActiveScopes(),t=new Date().toISOString(),n=[];for(let r of e){let e=this.#e.db.prepare(`SELECT * FROM syntheses WHERE scope = ?`).get(r);if(e===void 0||e.content===`pending`&&e.source_memory_hash===``){n.push({scope:r,reason:`missing`});continue}if(e.expires_at<=t){n.push({scope:r,reason:`expired`});continue}this.computeSourceMemoryHash(r)!==e.source_memory_hash&&n.push({scope:r,reason:`dirty`})}return n}getAllActiveScopes(){return this.#e.db.prepare(`SELECT DISTINCT scope_hash FROM projects`).all().map(e=>e.scope_hash)}expireStale(){let e=new Date().toISOString();this.#e.db.prepare(`DELETE FROM syntheses WHERE expires_at < ?`).run(e)}};function Qe(e){return new Ze(e)}export{_ as ACTIVITY_EVENT_TYPE_VALUES,v as ActivityEventTypeSchema,z as DatabaseError,me as DatabaseManager,_e as EmbeddingService,U as GLOBAL_PROJECT_ID,G as GLOBAL_PROJECT_NAME,W as GLOBAL_SCOPE_HASH,S as MEMORY_TYPE_VALUES,Le as MIGRATIONS,B as MODEL_NAME,R as MembankError,j as MemoryPatchSchema,N as MemoryRowSchema,k as MemorySchema,C as MemoryTypeSchema,V as ModelDownloadError,ge as ModelDownloader,K as PIN_BUDGET_THRESHOLD,P as ProjectRowSchema,T as ProjectSchema,We as QueryEngine,A as QueryOptionsSchema,ie as RETENTION_DAYS,O as ReviewEventRowSchema,D as ReviewEventSchema,E as ReviewReasonSchema,ue as SaveOptionsSchema,Ke as SessionContextBuilder,de as SessionContextSchema,q as SqliteMemoryRepository,qe as SynthesisEngine,M as SynthesisSchema,w as TagsJsonSchema,se as createActivityLogger,oe as createActivityRepository,Oe as createClaudeCodeTranscriptReader,xe as createExtractionAgentRunner,Te as createExtractionRunRepository,Fe as createMemoryRepository,Be as createProjectRepository,Xe as createSynthesisAgentRunner,Qe as createSynthesisRepository,ke as deleteMemory,Q as getSessionContext,Pe as isOverBudget,le as isSynthesisEnabled,re as listEvents,Ge as listMemoryTypes,y as logEvent,x as noopActivityLogger,Z as queryMemories,X as resolveProject,Ae as resolveReview,Ie as resolveScope,F as rowToMemory,L as rowToProject,ve as runExtraction,Re as runScopeToProjectsMigration,Je as runSynthesis,Me as saveMemory,Ne as updateMemory};
354
+ ORDER BY m.id`).all(e);return r(`sha256`).update(JSON.stringify(t.map(e=>e.content))).digest(`hex`)}getExpiredOrDirtyScopes(){let e=this.getAllActiveScopes(),t=new Date().toISOString(),n=[];for(let r of e){let e=this.#e.db.prepare(`SELECT * FROM syntheses WHERE scope = ?`).get(r);if(e===void 0||e.content===`pending`&&e.source_memory_hash===``){n.push({scope:r,reason:`missing`});continue}if(e.expires_at<=t){n.push({scope:r,reason:`expired`});continue}this.computeSourceMemoryHash(r)!==e.source_memory_hash&&n.push({scope:r,reason:`dirty`})}return n}getAllActiveScopes(){return this.#e.db.prepare(`SELECT DISTINCT scope_hash FROM projects`).all().map(e=>e.scope_hash)}expireStale(){let e=new Date().toISOString();this.#e.db.prepare(`DELETE FROM syntheses WHERE expires_at < ?`).run(e)}};function nt(e){return new tt(e)}export{b as ACTIVITY_EVENT_TYPE_VALUES,x as ActivityEventTypeSchema,U as DatabaseError,pe as DatabaseManager,ge as EmbeddingService,n as GLOBAL_PROJECT_ID,e as GLOBAL_PROJECT_NAME,t as GLOBAL_SCOPE_HASH,T as MEMORY_TYPE_VALUES,Be as MIGRATIONS,W as MODEL_NAME,H as MembankError,F as MemoryPatchSchema,L as MemoryRowSchema,M as MemorySchema,E as MemoryTypeSchema,G as ModelDownloadError,he as ModelDownloader,Y as PIN_BUDGET_THRESHOLD,R as ProjectRowSchema,O as ProjectSchema,Je as QueryEngine,N as QueryOptionsSchema,ie as RETENTION_DAYS,j as ReviewEventRowSchema,A as ReviewEventSchema,k as ReviewReasonSchema,P as SaveOptionsSchema,Xe as SessionContextBuilder,ue as SessionContextSchema,X as SqliteMemoryRepository,Ze as SynthesisEngine,I as SynthesisSchema,D as TagsJsonSchema,Oe as clusterFlagged,se as createActivityLogger,oe as createActivityRepository,De as createClaudeCodeTranscriptReader,be as createExtractionAgentRunner,we as createExtractionRunRepository,Ie as createMemoryRepository,Ue as createProjectRepository,et as createSynthesisAgentRunner,nt as createSynthesisRepository,ke as deleteManyMemories,q as deleteMemory,Q as getSessionContext,Fe as isOverBudget,le as isSynthesisEnabled,re as listEvents,Ye as listMemoryTypes,S as logEvent,Ae as mergeMemories,w as noopActivityLogger,Ke as queryMemories,Re as resolveProject,je as resolveReview,Me as resolveReviewMany,ze as resolveScope,z as rowToMemory,V as rowToProject,_e as runExtraction,Ve as runScopeToProjectsMigration,Qe as runSynthesis,Ne as saveMemory,Pe as updateMemory};
314
355
  //# sourceMappingURL=index.mjs.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@membank/core",
3
- "version": "0.12.0",
3
+ "version": "0.13.0",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -9,9 +9,14 @@
9
9
  },
10
10
  "exports": {
11
11
  ".": {
12
+ "types": "./dist/index.d.mts",
12
13
  "import": "./dist/index.mjs",
13
- "require": "./dist/index.cjs",
14
- "types": "./dist/index.d.mts"
14
+ "require": "./dist/index.cjs"
15
+ },
16
+ "./client": {
17
+ "types": "./dist/client.d.mts",
18
+ "import": "./dist/client.mjs",
19
+ "require": "./dist/client.cjs"
15
20
  }
16
21
  },
17
22
  "files": [