@membank/core 0.11.1 → 0.12.1
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.
- package/dist/client.cjs +1 -0
- package/dist/client.d.cts +2 -0
- package/dist/client.d.mts +2 -0
- package/dist/client.mjs +1 -0
- package/dist/global-scope-B463kRq-.mjs +2 -0
- package/dist/global-scope-Bv4l3n3S.d.cts +7 -0
- package/dist/global-scope-CgOQm1jp.cjs +1 -0
- package/dist/global-scope-lgsTOiAt.d.mts +7 -0
- package/dist/index.cjs +109 -40
- package/dist/index.d.cts +104 -16
- package/dist/index.d.mts +104 -16
- package/dist/index.mjs +109 -40
- package/package.json +8 -3
package/dist/client.cjs
ADDED
|
@@ -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;
|
package/dist/client.mjs
ADDED
|
@@ -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,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,4 +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));
|
|
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 ee=require(`node:events`),g=require(`@huggingface/transformers`),_=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 v=[`memory.created`,`memory.updated`,`memory.deleted`,`memory.flagged`,`memory.queried`],y=u.z.enum(v);function b(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 ae(e){return{id:e.id,projectHash:e.project_hash,eventType:y.parse(e.event_type),memoryId:e.memory_id,payload:JSON.parse(e.payload),createdAt:e.created_at}}var x=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 x(e)}function se(e){let t=new x(e);return{logEvent:e=>b(e,t)}}const S={logEvent(){}};function ce(){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 le(){return ce()?.synthesis?.enabled===!0}const C=[`correction`,`preference`,`decision`,`learning`,`fact`],w=u.z.enum(C),T=u.z.array(u.z.string()),E=u.z.object({id:u.z.string(),name:u.z.string(),scopeHash:u.z.string(),createdAt:u.z.string(),updatedAt:u.z.string()}),D=u.z.enum([`similarity_dedup`]),O=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:D,createdAt:u.z.string(),resolvedAt:u.z.string().nullable()}),k=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:D,created_at:u.z.string(),resolved_at:u.z.string().nullable()}),A=u.z.object({id:u.z.string(),content:u.z.string(),type:w,tags:u.z.array(u.z.string()),projects:u.z.array(E),sourceHarness:u.z.string().nullable(),accessCount:u.z.number().int().nonnegative(),pinned:u.z.boolean(),reviewEvents:u.z.array(O),createdAt:u.z.string(),updatedAt:u.z.string()}),j=u.z.object({query:u.z.string().min(1),type:w.optional(),projectHash:u.z.string().optional(),limit:u.z.number().int().positive().optional(),includePinned:u.z.boolean().optional()}),M=u.z.object({content:u.z.string().min(1),type:w,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()}),N=u.z.object({content:u.z.string().min(1).optional(),tags:u.z.array(u.z.string()).optional(),type:w.optional()}),P=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()}),ue=u.z.object({stats:u.z.record(w,u.z.number()),pinnedGlobal:u.z.array(A),pinnedProject:u.z.array(A),synthesis:u.z.string().optional()}),F=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()}),I=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 L(e,t,n=[]){return{id:e.id,content:e.content,type:w.parse(e.type),tags:T.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 R(e){let t=k.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 z(e){return{id:e.id,name:e.name,scopeHash:e.scope_hash,createdAt:e.created_at,updatedAt:e.updated_at}}var B=class extends Error{constructor(e,t){super(e,t),this.name=`MembankError`}},V=class extends B{constructor(e,t){super(e,t),this.name=`DatabaseError`}};const de=(0,p.join)((0,f.homedir)(),`.membank`,`memory.db`),fe=[[1,`
|
|
2
3
|
CREATE TABLE IF NOT EXISTS memories (
|
|
3
4
|
id TEXT PRIMARY KEY,
|
|
4
5
|
content TEXT NOT NULL,
|
|
@@ -154,14 +155,86 @@ CREATE TABLE IF NOT EXISTS extraction_runs (
|
|
|
154
155
|
|
|
155
156
|
CREATE INDEX IF NOT EXISTS idx_extraction_runs_status
|
|
156
157
|
ON extraction_runs(status) WHERE status = 'in_flight';
|
|
157
|
-
`]
|
|
158
|
+
`],[7,`
|
|
159
|
+
INSERT OR IGNORE INTO projects (id, name, scope_hash, created_at, updated_at)
|
|
160
|
+
VALUES ('00000000-0000-0000-0000-000000000000', 'global', '0000000000000000', datetime('now'), datetime('now'));
|
|
161
|
+
|
|
162
|
+
INSERT OR IGNORE INTO memory_projects (memory_id, project_id)
|
|
163
|
+
SELECT id, '00000000-0000-0000-0000-000000000000'
|
|
164
|
+
FROM memories
|
|
165
|
+
WHERE id NOT IN (SELECT memory_id FROM memory_projects);
|
|
166
|
+
`],[8,`
|
|
167
|
+
PRAGMA foreign_keys = OFF;
|
|
168
|
+
|
|
169
|
+
BEGIN;
|
|
170
|
+
|
|
171
|
+
UPDATE syntheses SET scope = '0000000000000000' WHERE scope = 'global';
|
|
172
|
+
|
|
173
|
+
DROP TABLE IF EXISTS syntheses_new;
|
|
174
|
+
|
|
175
|
+
CREATE TABLE syntheses_new (
|
|
176
|
+
id TEXT PRIMARY KEY,
|
|
177
|
+
scope TEXT NOT NULL REFERENCES projects(scope_hash) ON DELETE CASCADE,
|
|
178
|
+
content TEXT NOT NULL,
|
|
179
|
+
source_memory_hash TEXT NOT NULL,
|
|
180
|
+
synthesized_at TEXT NOT NULL,
|
|
181
|
+
expires_at TEXT NOT NULL,
|
|
182
|
+
in_flight_since TEXT,
|
|
183
|
+
created_at TEXT NOT NULL,
|
|
184
|
+
updated_at TEXT NOT NULL,
|
|
185
|
+
UNIQUE(scope),
|
|
186
|
+
CHECK(expires_at > synthesized_at)
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
INSERT INTO syntheses_new SELECT * FROM syntheses;
|
|
190
|
+
|
|
191
|
+
DROP TABLE syntheses;
|
|
192
|
+
ALTER TABLE syntheses_new RENAME TO syntheses;
|
|
193
|
+
|
|
194
|
+
CREATE INDEX IF NOT EXISTS idx_syntheses_expires_at ON syntheses(expires_at);
|
|
195
|
+
CREATE INDEX IF NOT EXISTS idx_syntheses_scope_inflight
|
|
196
|
+
ON syntheses(scope) WHERE in_flight_since IS NOT NULL;
|
|
197
|
+
|
|
198
|
+
COMMIT;
|
|
199
|
+
|
|
200
|
+
PRAGMA foreign_keys = ON;
|
|
201
|
+
`],[9,`
|
|
202
|
+
CREATE TABLE activity_events (
|
|
203
|
+
id TEXT PRIMARY KEY,
|
|
204
|
+
project_hash TEXT NOT NULL REFERENCES projects(scope_hash) ON DELETE CASCADE,
|
|
205
|
+
event_type TEXT NOT NULL,
|
|
206
|
+
memory_id TEXT,
|
|
207
|
+
payload TEXT NOT NULL,
|
|
208
|
+
created_at TEXT NOT NULL
|
|
209
|
+
);
|
|
210
|
+
|
|
211
|
+
CREATE INDEX idx_activity_project_created ON activity_events(project_hash, created_at DESC);
|
|
212
|
+
CREATE INDEX idx_activity_type_created ON activity_events(event_type, created_at DESC);
|
|
213
|
+
`],[10,`
|
|
214
|
+
ALTER TABLE activity_events RENAME TO activity_events_old;
|
|
215
|
+
|
|
216
|
+
CREATE TABLE activity_events (
|
|
217
|
+
id TEXT PRIMARY KEY,
|
|
218
|
+
project_hash TEXT NOT NULL,
|
|
219
|
+
event_type TEXT NOT NULL,
|
|
220
|
+
memory_id TEXT,
|
|
221
|
+
payload TEXT NOT NULL,
|
|
222
|
+
created_at TEXT NOT NULL
|
|
223
|
+
);
|
|
224
|
+
|
|
225
|
+
INSERT INTO activity_events SELECT * FROM activity_events_old;
|
|
226
|
+
DROP TABLE activity_events_old;
|
|
227
|
+
|
|
228
|
+
CREATE INDEX idx_activity_project_created ON activity_events(project_hash, created_at DESC);
|
|
229
|
+
CREATE INDEX idx_activity_type_created ON activity_events(event_type, created_at DESC);
|
|
230
|
+
`]];var pe=class e{#e;constructor(e){this.#e=e}static open(t){let n=t??de;(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 V(`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(`
|
|
158
231
|
CREATE TABLE IF NOT EXISTS meta (
|
|
159
232
|
key TEXT PRIMARY KEY,
|
|
160
233
|
value TEXT NOT NULL
|
|
161
234
|
);
|
|
162
|
-
`);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
|
|
163
|
-
`);var
|
|
164
|
-
`),r=Object.fromEntries(Object.entries(process.env).filter(e=>e[1]!==void 0)),i=Date.now(),a=(0,
|
|
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 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 H=`Xenova/bge-small-en-v1.5`;var U=class extends Error{constructor(e,t){super(e,t),this.name=`ModelDownloadError`}};function me(){return(0,p.join)((0,f.homedir)(),`.membank`,`models`)}function W(e){if(!(0,d.existsSync)(e))return!1;try{return(0,d.readdirSync)(e).length>0}catch{return!1}}var he=class extends ee.EventEmitter{modelPath;constructor(e){super(),this.modelPath=e??me()}isAlreadyCached(){return W(this.modelPath)}get cachePath(){return this.modelPath}async download(){if(W(this.modelPath))return{skipped:!0};let e=Date.now(),t=0,n=e;try{await(0,g.pipeline)(`feature-extraction`,H,{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 U(`Failed to download model`,{cause:e})}return{skipped:!1}}},ge=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,g.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 _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(`
|
|
236
|
+
`);var ye=class{#e;constructor(e){this.#e=e}async run(e){let t=(0,_.createSdkMcpServer)({name:`membank-extraction-tools`,version:`1.0.0`,tools:[(0,_.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,_.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,_.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(`
|
|
237
|
+
`),r=Object.fromEntries(Object.entries(process.env).filter(e=>e[1]!==void 0)),i=Date.now(),a=(0,_.query)({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}}),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 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)
|
|
165
238
|
VALUES (?, ?, NULL, 'in_flight', NULL)
|
|
166
239
|
ON CONFLICT(session_id) DO UPDATE SET
|
|
167
240
|
started_at = excluded.started_at,
|
|
@@ -171,26 +244,25 @@ CREATE INDEX IF NOT EXISTS idx_extraction_runs_status
|
|
|
171
244
|
SET status = 'completed', completed_at = ?, error = NULL
|
|
172
245
|
WHERE session_id = ?`).run(t.toISOString(),e)}markFailed(e,t,n){this.#e.db.prepare(`UPDATE extraction_runs
|
|
173
246
|
SET status = 'failed', completed_at = ?, error = ?
|
|
174
|
-
WHERE session_id = ?`).run(t.toISOString(),n,e)}get(e){let t=this.#t(e);return t===void 0?void 0:
|
|
175
|
-
`)}var
|
|
176
|
-
`).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=
|
|
247
|
+
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(`
|
|
248
|
+
`)}var G=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=Te(t.message?.content).trim();i.length!==0&&n.push(`${r}: ${i}`)}let r=n.slice(-this.#e).join(`
|
|
177
250
|
|
|
178
|
-
`);return r.length<=this.#t?r:r.slice(r.length-this.#t)}};function
|
|
251
|
+
`);return r.length<=this.#t?r:r.slice(r.length-this.#t)}};function Ee(e={}){return new G(e)}function De(e,t,n=S){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 Oe(e,t){t.resolveReviewEvents(e)}function ke(e){return e>.92?`overwrite`:e>=.75?`flag`:`none`}async function Ae(e,t){let{content:n,type:r,tags:i=[],projectScope:a,sourceHarness:o}=M.parse(e),{repo:s,embedder:c,activityLogger:u=S}=t,d=a?.hash??`0000000000000000`,f=await c.embed(n),[p]=s.findSimilar(f,r,a?.hash);if(p!==void 0){let e=ke(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 je(e,t,n){let{repo:r,embedder:i,activityLogger:a=S}=n,o=N.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 Me(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
|
|
179
252
|
FROM memories m JOIN embeddings e ON e.rowid = m.rowid
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
253
|
+
JOIN memory_projects mp ON mp.memory_id = m.id
|
|
254
|
+
JOIN projects p ON p.id = mp.project_id
|
|
255
|
+
WHERE m.type = ? AND p.scope_hash = ?
|
|
256
|
+
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
|
|
183
257
|
FROM memories m JOIN embeddings e ON e.rowid = m.rowid
|
|
184
258
|
JOIN memory_projects mp ON mp.memory_id = m.id
|
|
185
259
|
JOIN projects p ON p.id = mp.project_id
|
|
186
260
|
WHERE m.type = ? AND p.scope_hash = ?
|
|
187
|
-
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);
|
|
188
|
-
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)
|
|
189
|
-
WHERE id NOT IN (SELECT memory_id FROM memory_projects)
|
|
190
|
-
AND pinned = 1`).all().map(e=>M(e,[]))}listPinnedForProject(e){return this.#e.db.prepare(`SELECT m.* FROM memories m
|
|
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),L(F.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=F.parse(this.#e.db.prepare(`SELECT * FROM memories WHERE id = ?`).get(e)),s=this.#t.getProjectsForMemories([e]),c=this.#r([e]);return L(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 L(t,n.get(e)??[],r.get(e)??[])}update(e,t,n){let{content:r,tags:i,type:a}=N.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=F.parse(this.#e.db.prepare(`SELECT * FROM memories WHERE id = ?`).get(e)),d=this.#t.getProjectsForMemories([e]),f=this.#r([e]);return L(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=>L(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
|
|
191
263
|
JOIN memory_projects mp ON mp.memory_id = m.id
|
|
192
264
|
JOIN projects p ON p.id = mp.project_id
|
|
193
|
-
WHERE p.scope_hash = ? AND m.pinned = 1`).all(e).map(e=>
|
|
265
|
+
WHERE p.scope_hash = ? AND m.pinned = 1`).all(e).map(e=>L(e,[]))}listFlagged(e){let t;if(t=e===void 0?this.#e.db.prepare(`SELECT * FROM memories
|
|
194
266
|
WHERE EXISTS (
|
|
195
267
|
SELECT 1 FROM memory_review_events e
|
|
196
268
|
WHERE e.memory_id = memories.id AND e.resolved_at IS NULL
|
|
@@ -201,44 +273,41 @@ CREATE INDEX IF NOT EXISTS idx_extraction_runs_status
|
|
|
201
273
|
WHERE e.memory_id = memories.id AND e.resolved_at IS NULL
|
|
202
274
|
)
|
|
203
275
|
AND ${this.#n()}
|
|
204
|
-
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=>
|
|
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=>L(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=>R(k.parse(e)))}createReviewEvent(e){let t=new Date().toISOString();this.#e.db.prepare(`INSERT INTO memory_review_events
|
|
205
277
|
(id, memory_id, conflicting_memory_id, similarity, conflict_content_snapshot, reason, created_at)
|
|
206
|
-
VALUES (?, ?, ?, ?, ?, 'similarity_dedup', ?)`).run((0,
|
|
207
|
-
WHERE pinned = 1 AND ${this.#n()}`).get(e)??{total:0}).total}stats(e){let t=Object.fromEntries(
|
|
278
|
+
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
|
|
279
|
+
WHERE pinned = 1 AND ${this.#n()}`).get(e)??{total:0}).total}stats(e){let t=Object.fromEntries(C.map(e=>[e,0]));if(e!==void 0){let n=this.#e.db.prepare(`SELECT type, COUNT(*) as count FROM memories
|
|
208
280
|
WHERE ${this.#n()}
|
|
209
|
-
GROUP BY type`).all(e);for(let e of n){let n=
|
|
281
|
+
GROUP BY type`).all(e);for(let e of n){let n=w.safeParse(e.type);n.success&&(t[n.data]=e.count)}let r=this.#e.db.prepare(`SELECT COUNT(*) as total, SUM(pinned) as pinned,
|
|
210
282
|
COALESCE(SUM(CASE WHEN pinned = 1 THEN LENGTH(content) ELSE 0 END), 0) as pinBudgetChars
|
|
211
283
|
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
|
|
212
284
|
FROM memory_review_events e
|
|
213
285
|
JOIN memories m ON m.id = e.memory_id
|
|
214
286
|
WHERE e.resolved_at IS NULL
|
|
215
|
-
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=
|
|
216
|
-
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`
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
))`}#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
|
|
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=w.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=F.parse(this.#e.db.prepare(`SELECT * FROM memories WHERE id = ?`).get(e)),i=this.#t.getProjectsForMemories([e]),a=this.#r([e]);return L(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:w.parse(e.type),tags:T.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
|
+
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
|
+
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 = '${c.r}')
|
|
291
|
+
)`}#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
|
|
221
292
|
WHERE memory_id IN (${n}) ${r}
|
|
222
|
-
ORDER BY created_at DESC`).all(...e),a=new Map;for(let e of i){let t=
|
|
293
|
+
ORDER BY created_at DESC`).all(...e),a=new Map;for(let e of i){let t=R(k.parse(e)),n=a.get(t.memoryId)??[];n.push(t),a.set(t.memoryId,n)}return a}};function Ne(e,t){return new q(e,t)}const J=(0,re.promisify)(ne.execFile);function Y(e){return(0,l.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 Pe(){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 Fe=[{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 Ie(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 Le=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),z(I.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 z(r)}list(){return this.#e.db.prepare(`SELECT * FROM projects ORDER BY name ASC`).all().map(z)}getByHash(e){let t=this.#e.db.prepare(`SELECT * FROM projects WHERE scope_hash = ?`).get(e);return t===void 0?void 0:z(t)}getByName(e){let t=this.#e.db.prepare(`SELECT * FROM projects WHERE name = ? LIMIT 1`).get(e);return t===void 0?void 0:z(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
|
|
223
294
|
JOIN memory_projects mp ON mp.project_id = p.id
|
|
224
|
-
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(
|
|
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(z(e)),r.set(e.memory_id,t)}return r}};function Re(e){return new Le(e)}const ze={correction:1,preference:.8,decision:.6,learning:.4,fact:.2};function Be(e,t,n){let r=ze[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}=j.parse(e),{activityLogger:s=S}=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:Be(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 Ve=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=`
|
|
225
296
|
SELECT m.*, (1 - vec_distance_cosine(e.embedding, ?)) AS cosine_sim
|
|
226
297
|
FROM memories m JOIN embeddings e ON e.rowid = m.rowid
|
|
227
298
|
${s}
|
|
228
|
-
${
|
|
229
|
-
`;return this.#e.db.prepare(
|
|
299
|
+
${l}
|
|
300
|
+
`;return this.#e.db.prepare(u).all(...o).map(e=>({...L(e,[]),cosineSim:e.cosine_sim}))}},He=class{#e;#t;#n;#r;constructor(e,t,n,r=S){this.#e=e,this.#t=t,this.#n=n,this.#r=r}async query(e){return Z(e,{adapter:new Ve(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 Ue(){return[...C]}var We=class{#e;constructor(e){this.#e=e}getSessionContext(e,t){return Q({projectHash:e,synthesis:t},{repo:this.#e})}},Ge=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 Ke(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 qe=class{#e;constructor(e,t){this.#e=e}async run(e,t){let n=(0,_.createSdkMcpServer)({name:`membank-synthesis-tools`,version:`1.0.0`,tools:[(0,_.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,_.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,_.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 Je(e,t){return new qe(e,t)}function $(e){return P.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 Ye=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
|
|
230
301
|
SET content = ?, source_memory_hash = ?, synthesized_at = ?, expires_at = ?,
|
|
231
302
|
in_flight_since = NULL, updated_at = ?
|
|
232
|
-
WHERE scope = ?`).run(t,n,r,i,r,e);else{let a=(0,
|
|
303
|
+
WHERE scope = ?`).run(t,n,r,i,r,e);else{let a=(0,l.randomUUID)();this.#e.db.prepare(`INSERT INTO syntheses
|
|
233
304
|
(id, scope, content, source_memory_hash, synthesized_at, expires_at,
|
|
234
305
|
in_flight_since, created_at, updated_at)
|
|
235
|
-
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,
|
|
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,l.randomUUID)(),r=new Date(Date.now()+720*60*60*1e3).toISOString();this.#e.db.prepare(`INSERT INTO syntheses
|
|
236
307
|
(id, scope, content, source_memory_hash, synthesized_at, expires_at,
|
|
237
308
|
in_flight_since, created_at, updated_at)
|
|
238
|
-
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
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
WHERE p.scope_hash = ?
|
|
244
|
-
ORDER BY m.id`).all(e),(0,g.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[`global`,...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 Be(e){return new ze(e)}exports.DatabaseError=I,exports.DatabaseManager=ce,exports.EmbeddingService=V,exports.MEMORY_TYPE_VALUES=v,exports.MIGRATIONS=Ee,exports.MODEL_NAME=L,exports.MembankError=F,exports.MemoryPatchSchema=O,exports.MemoryRowSchema=A,exports.MemorySchema=T,exports.MemoryTypeSchema=y,exports.ModelDownloadError=R,exports.ModelDownloader=B,exports.PIN_BUDGET_THRESHOLD=G,exports.ProjectRowSchema=j,exports.ProjectSchema=x,exports.QueryEngine=Me,exports.QueryOptionsSchema=E,exports.ReviewEventRowSchema=w,exports.ReviewEventSchema=C,exports.ReviewReasonSchema=S,exports.SaveOptionsSchema=D,exports.SessionContextBuilder=Pe,exports.SessionContextSchema=ae,exports.SqliteMemoryRepository=K,exports.SynthesisEngine=Fe,exports.SynthesisSchema=k,exports.TagsJsonSchema=b,exports.createClaudeCodeTranscriptReader=_e,exports.createExtractionAgentRunner=ue,exports.createExtractionRunRepository=me,exports.createMemoryRepository=we,exports.createProjectRepository=ke,exports.createSynthesisAgentRunner=Re,exports.createSynthesisRepository=Be,exports.deleteMemory=ve,exports.getSessionContext=Q,exports.isOverBudget=Ce,exports.isSynthesisEnabled=ie,exports.listMemoryTypes=Ne,exports.queryMemories=Z,exports.resolveProject=Y,exports.resolveReview=ye,exports.resolveScope=Te,exports.rowToMemory=M,exports.rowToProject=P,exports.runExtraction=H,exports.runScopeToProjectsMigration=De,exports.runSynthesis=Ie,exports.saveMemory=xe,exports.updateMemory=Se;
|
|
309
|
+
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
|
+
JOIN memory_projects mp ON mp.memory_id = m.id
|
|
311
|
+
JOIN projects p ON p.id = mp.project_id
|
|
312
|
+
WHERE p.scope_hash = ?
|
|
313
|
+
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 Xe(e){return new Ye(e)}exports.ACTIVITY_EVENT_TYPE_VALUES=v,exports.ActivityEventTypeSchema=y,exports.DatabaseError=V,exports.DatabaseManager=pe,exports.EmbeddingService=ge,exports.GLOBAL_PROJECT_ID=c.t,exports.GLOBAL_PROJECT_NAME=c.n,exports.GLOBAL_SCOPE_HASH=c.r,exports.MEMORY_TYPE_VALUES=C,exports.MIGRATIONS=Fe,exports.MODEL_NAME=H,exports.MembankError=B,exports.MemoryPatchSchema=N,exports.MemoryRowSchema=F,exports.MemorySchema=A,exports.MemoryTypeSchema=w,exports.ModelDownloadError=U,exports.ModelDownloader=he,exports.PIN_BUDGET_THRESHOLD=K,exports.ProjectRowSchema=I,exports.ProjectSchema=E,exports.QueryEngine=He,exports.QueryOptionsSchema=j,exports.RETENTION_DAYS=30,exports.ReviewEventRowSchema=k,exports.ReviewEventSchema=O,exports.ReviewReasonSchema=D,exports.SaveOptionsSchema=M,exports.SessionContextBuilder=We,exports.SessionContextSchema=ue,exports.SqliteMemoryRepository=q,exports.SynthesisEngine=Ge,exports.SynthesisSchema=P,exports.TagsJsonSchema=T,exports.createActivityLogger=se,exports.createActivityRepository=oe,exports.createClaudeCodeTranscriptReader=Ee,exports.createExtractionAgentRunner=be,exports.createExtractionRunRepository=we,exports.createMemoryRepository=Ne,exports.createProjectRepository=Re,exports.createSynthesisAgentRunner=Je,exports.createSynthesisRepository=Xe,exports.deleteMemory=De,exports.getSessionContext=Q,exports.isOverBudget=Me,exports.isSynthesisEnabled=le,exports.listEvents=ie,exports.listMemoryTypes=Ue,exports.logEvent=b,exports.noopActivityLogger=S,exports.queryMemories=Z,exports.resolveProject=X,exports.resolveReview=Oe,exports.resolveScope=Pe,exports.rowToMemory=L,exports.rowToProject=z,exports.runExtraction=_e,exports.runScopeToProjectsMigration=Ie,exports.runSynthesis=Ke,exports.saveMemory=Ae,exports.updateMemory=je;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,7 +1,105 @@
|
|
|
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";
|
|
4
5
|
|
|
6
|
+
//#region src/activity/domain/activity-event.d.ts
|
|
7
|
+
declare const ACTIVITY_EVENT_TYPE_VALUES: readonly ["memory.created", "memory.updated", "memory.deleted", "memory.flagged", "memory.queried"];
|
|
8
|
+
declare const ActivityEventTypeSchema: z.ZodEnum<{
|
|
9
|
+
"memory.created": "memory.created";
|
|
10
|
+
"memory.updated": "memory.updated";
|
|
11
|
+
"memory.deleted": "memory.deleted";
|
|
12
|
+
"memory.flagged": "memory.flagged";
|
|
13
|
+
"memory.queried": "memory.queried";
|
|
14
|
+
}>;
|
|
15
|
+
type ActivityEventType = z.infer<typeof ActivityEventTypeSchema>;
|
|
16
|
+
declare const RETENTION_DAYS = 30;
|
|
17
|
+
interface ActivityEvent {
|
|
18
|
+
id: string;
|
|
19
|
+
projectHash: string;
|
|
20
|
+
eventType: ActivityEventType;
|
|
21
|
+
memoryId: string | null;
|
|
22
|
+
payload: Record<string, unknown>;
|
|
23
|
+
createdAt: string;
|
|
24
|
+
}
|
|
25
|
+
interface ActivityEventInput {
|
|
26
|
+
projectHash: string;
|
|
27
|
+
eventType: ActivityEventType;
|
|
28
|
+
memoryId?: string;
|
|
29
|
+
payload?: Record<string, unknown>;
|
|
30
|
+
}
|
|
31
|
+
//#endregion
|
|
32
|
+
//#region src/activity/ports.d.ts
|
|
33
|
+
interface ActivityRepository {
|
|
34
|
+
insert(event: {
|
|
35
|
+
id: string;
|
|
36
|
+
projectHash: string;
|
|
37
|
+
eventType: ActivityEventType;
|
|
38
|
+
memoryId: string | null;
|
|
39
|
+
payload: Record<string, unknown>;
|
|
40
|
+
createdAt: string;
|
|
41
|
+
}): void;
|
|
42
|
+
list(filter: {
|
|
43
|
+
scope?: string;
|
|
44
|
+
type?: ActivityEventType;
|
|
45
|
+
since?: string;
|
|
46
|
+
limit?: number;
|
|
47
|
+
}): ActivityEvent[];
|
|
48
|
+
prune(olderThan: string): void;
|
|
49
|
+
}
|
|
50
|
+
interface ActivityLogger {
|
|
51
|
+
logEvent(input: ActivityEventInput): void;
|
|
52
|
+
}
|
|
53
|
+
declare const noopActivityLogger: ActivityLogger;
|
|
54
|
+
//#endregion
|
|
55
|
+
//#region src/activity/application/list-events.d.ts
|
|
56
|
+
interface ListEventsFilter {
|
|
57
|
+
scope?: string;
|
|
58
|
+
type?: ActivityEventType;
|
|
59
|
+
since?: string;
|
|
60
|
+
limit?: number;
|
|
61
|
+
}
|
|
62
|
+
declare function listEvents(filter: ListEventsFilter, repo: ActivityRepository): ActivityEvent[];
|
|
63
|
+
//#endregion
|
|
64
|
+
//#region src/activity/application/log-event.d.ts
|
|
65
|
+
declare function logEvent(input: ActivityEventInput, repo: ActivityRepository): void;
|
|
66
|
+
//#endregion
|
|
67
|
+
//#region src/db/manager.d.ts
|
|
68
|
+
type VecLoader = (db: BetterSqlite3.Database) => void;
|
|
69
|
+
declare class DatabaseManager {
|
|
70
|
+
#private;
|
|
71
|
+
private constructor();
|
|
72
|
+
static open(dbPath?: string): DatabaseManager;
|
|
73
|
+
static openInMemory(): DatabaseManager;
|
|
74
|
+
/** For testing: inject a custom vec loader (e.g. a throwing stub). */
|
|
75
|
+
static _openInMemoryWithLoader(loader: VecLoader): DatabaseManager;
|
|
76
|
+
get db(): BetterSqlite3.Database;
|
|
77
|
+
close(): void;
|
|
78
|
+
}
|
|
79
|
+
//#endregion
|
|
80
|
+
//#region src/activity/infrastructure/sqlite-activity-repository.d.ts
|
|
81
|
+
declare class SqliteActivityRepository implements ActivityRepository {
|
|
82
|
+
#private;
|
|
83
|
+
constructor(db: DatabaseManager);
|
|
84
|
+
insert(event: {
|
|
85
|
+
id: string;
|
|
86
|
+
projectHash: string;
|
|
87
|
+
eventType: string;
|
|
88
|
+
memoryId: string | null;
|
|
89
|
+
payload: Record<string, unknown>;
|
|
90
|
+
createdAt: string;
|
|
91
|
+
}): void;
|
|
92
|
+
list(filter: {
|
|
93
|
+
scope?: string;
|
|
94
|
+
type?: string;
|
|
95
|
+
since?: string;
|
|
96
|
+
limit?: number;
|
|
97
|
+
}): ActivityEvent[];
|
|
98
|
+
prune(olderThan: string): void;
|
|
99
|
+
}
|
|
100
|
+
declare function createActivityRepository(db: DatabaseManager): SqliteActivityRepository;
|
|
101
|
+
declare function createActivityLogger(db: DatabaseManager): ActivityLogger;
|
|
102
|
+
//#endregion
|
|
5
103
|
//#region src/config/loader.d.ts
|
|
6
104
|
declare function isSynthesisEnabled(): boolean;
|
|
7
105
|
//#endregion
|
|
@@ -262,19 +360,6 @@ declare class DatabaseError extends MembankError {
|
|
|
262
360
|
constructor(message: string, options?: ErrorOptions);
|
|
263
361
|
}
|
|
264
362
|
//#endregion
|
|
265
|
-
//#region src/db/manager.d.ts
|
|
266
|
-
type VecLoader = (db: BetterSqlite3.Database) => void;
|
|
267
|
-
declare class DatabaseManager {
|
|
268
|
-
#private;
|
|
269
|
-
private constructor();
|
|
270
|
-
static open(dbPath?: string): DatabaseManager;
|
|
271
|
-
static openInMemory(): DatabaseManager;
|
|
272
|
-
/** For testing: inject a custom vec loader (e.g. a throwing stub). */
|
|
273
|
-
static _openInMemoryWithLoader(loader: VecLoader): DatabaseManager;
|
|
274
|
-
get db(): BetterSqlite3.Database;
|
|
275
|
-
close(): void;
|
|
276
|
-
}
|
|
277
|
-
//#endregion
|
|
278
363
|
//#region src/embedding/infrastructure/model-downloader.d.ts
|
|
279
364
|
declare const MODEL_NAME = "Xenova/bge-small-en-v1.5";
|
|
280
365
|
interface DownloadProgress {
|
|
@@ -476,7 +561,7 @@ interface TranscriptReaderOptions {
|
|
|
476
561
|
declare function createClaudeCodeTranscriptReader(opts?: TranscriptReaderOptions): TranscriptReader;
|
|
477
562
|
//#endregion
|
|
478
563
|
//#region src/memory/application/delete-memory.d.ts
|
|
479
|
-
declare function deleteMemory(id: string, repo: MemoryRepository): Promise<void>;
|
|
564
|
+
declare function deleteMemory(id: string, repo: MemoryRepository, activityLogger?: ActivityLogger): Promise<void>;
|
|
480
565
|
//#endregion
|
|
481
566
|
//#region src/memory/application/resolve-review.d.ts
|
|
482
567
|
declare function resolveReview(memoryId: string, repo: MemoryRepository): void;
|
|
@@ -485,12 +570,14 @@ declare function resolveReview(memoryId: string, repo: MemoryRepository): void;
|
|
|
485
570
|
declare function saveMemory(opts: SaveOptions, deps: {
|
|
486
571
|
repo: MemoryRepository;
|
|
487
572
|
embedder: Embedder;
|
|
573
|
+
activityLogger?: ActivityLogger;
|
|
488
574
|
}): Promise<Memory>;
|
|
489
575
|
//#endregion
|
|
490
576
|
//#region src/memory/application/update-memory.d.ts
|
|
491
577
|
declare function updateMemory(id: string, patch: MemoryPatch, deps: {
|
|
492
578
|
repo: MemoryRepository;
|
|
493
579
|
embedder: Embedder;
|
|
580
|
+
activityLogger?: ActivityLogger;
|
|
494
581
|
}): Promise<Memory>;
|
|
495
582
|
//#endregion
|
|
496
583
|
//#region src/memory/domain/pin-budget.d.ts
|
|
@@ -582,12 +669,13 @@ declare function queryMemories(options: QueryOptions, deps: {
|
|
|
582
669
|
adapter: QueryAdapter;
|
|
583
670
|
repo: Pick<MemoryRepository, "incrementAccessCount">;
|
|
584
671
|
embedder: Embedder;
|
|
672
|
+
activityLogger?: ActivityLogger;
|
|
585
673
|
}): Promise<ScoredMemory[]>;
|
|
586
674
|
//#endregion
|
|
587
675
|
//#region src/query/engine.d.ts
|
|
588
676
|
declare class QueryEngine implements Querier {
|
|
589
677
|
#private;
|
|
590
|
-
constructor(db: DatabaseManager, embeddingService: Embedder, repo: MemoryRepository);
|
|
678
|
+
constructor(db: DatabaseManager, embeddingService: Embedder, repo: MemoryRepository, activityLogger?: ActivityLogger);
|
|
591
679
|
query(options: QueryOptions): Promise<ScoredMemory[]>;
|
|
592
680
|
}
|
|
593
681
|
//#endregion
|
|
@@ -675,5 +763,5 @@ declare function createSynthesisAgentRunner(tools: SynthesisTools, config: Synth
|
|
|
675
763
|
//#region src/synthesis/infrastructure/sqlite-synthesis-repository.d.ts
|
|
676
764
|
declare function createSynthesisRepository(db: DatabaseManager): SynthesisRepository;
|
|
677
765
|
//#endregion
|
|
678
|
-
export { 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, 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, 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, createClaudeCodeTranscriptReader, createExtractionAgentRunner, createExtractionRunRepository, createMemoryRepository, createProjectRepository, createSynthesisAgentRunner, createSynthesisRepository, deleteMemory, getSessionContext, isOverBudget, isSynthesisEnabled, listMemoryTypes, queryMemories, resolveProject, resolveReview, resolveScope, rowToMemory, rowToProject, runExtraction, runScopeToProjectsMigration, runSynthesis, saveMemory, updateMemory };
|
|
766
|
+
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 };
|
|
679
767
|
//# sourceMappingURL=index.d.cts.map
|
package/dist/index.d.mts
CHANGED
|
@@ -1,7 +1,105 @@
|
|
|
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";
|
|
4
5
|
|
|
6
|
+
//#region src/activity/domain/activity-event.d.ts
|
|
7
|
+
declare const ACTIVITY_EVENT_TYPE_VALUES: readonly ["memory.created", "memory.updated", "memory.deleted", "memory.flagged", "memory.queried"];
|
|
8
|
+
declare const ActivityEventTypeSchema: z.ZodEnum<{
|
|
9
|
+
"memory.created": "memory.created";
|
|
10
|
+
"memory.updated": "memory.updated";
|
|
11
|
+
"memory.deleted": "memory.deleted";
|
|
12
|
+
"memory.flagged": "memory.flagged";
|
|
13
|
+
"memory.queried": "memory.queried";
|
|
14
|
+
}>;
|
|
15
|
+
type ActivityEventType = z.infer<typeof ActivityEventTypeSchema>;
|
|
16
|
+
declare const RETENTION_DAYS = 30;
|
|
17
|
+
interface ActivityEvent {
|
|
18
|
+
id: string;
|
|
19
|
+
projectHash: string;
|
|
20
|
+
eventType: ActivityEventType;
|
|
21
|
+
memoryId: string | null;
|
|
22
|
+
payload: Record<string, unknown>;
|
|
23
|
+
createdAt: string;
|
|
24
|
+
}
|
|
25
|
+
interface ActivityEventInput {
|
|
26
|
+
projectHash: string;
|
|
27
|
+
eventType: ActivityEventType;
|
|
28
|
+
memoryId?: string;
|
|
29
|
+
payload?: Record<string, unknown>;
|
|
30
|
+
}
|
|
31
|
+
//#endregion
|
|
32
|
+
//#region src/activity/ports.d.ts
|
|
33
|
+
interface ActivityRepository {
|
|
34
|
+
insert(event: {
|
|
35
|
+
id: string;
|
|
36
|
+
projectHash: string;
|
|
37
|
+
eventType: ActivityEventType;
|
|
38
|
+
memoryId: string | null;
|
|
39
|
+
payload: Record<string, unknown>;
|
|
40
|
+
createdAt: string;
|
|
41
|
+
}): void;
|
|
42
|
+
list(filter: {
|
|
43
|
+
scope?: string;
|
|
44
|
+
type?: ActivityEventType;
|
|
45
|
+
since?: string;
|
|
46
|
+
limit?: number;
|
|
47
|
+
}): ActivityEvent[];
|
|
48
|
+
prune(olderThan: string): void;
|
|
49
|
+
}
|
|
50
|
+
interface ActivityLogger {
|
|
51
|
+
logEvent(input: ActivityEventInput): void;
|
|
52
|
+
}
|
|
53
|
+
declare const noopActivityLogger: ActivityLogger;
|
|
54
|
+
//#endregion
|
|
55
|
+
//#region src/activity/application/list-events.d.ts
|
|
56
|
+
interface ListEventsFilter {
|
|
57
|
+
scope?: string;
|
|
58
|
+
type?: ActivityEventType;
|
|
59
|
+
since?: string;
|
|
60
|
+
limit?: number;
|
|
61
|
+
}
|
|
62
|
+
declare function listEvents(filter: ListEventsFilter, repo: ActivityRepository): ActivityEvent[];
|
|
63
|
+
//#endregion
|
|
64
|
+
//#region src/activity/application/log-event.d.ts
|
|
65
|
+
declare function logEvent(input: ActivityEventInput, repo: ActivityRepository): void;
|
|
66
|
+
//#endregion
|
|
67
|
+
//#region src/db/manager.d.ts
|
|
68
|
+
type VecLoader = (db: BetterSqlite3.Database) => void;
|
|
69
|
+
declare class DatabaseManager {
|
|
70
|
+
#private;
|
|
71
|
+
private constructor();
|
|
72
|
+
static open(dbPath?: string): DatabaseManager;
|
|
73
|
+
static openInMemory(): DatabaseManager;
|
|
74
|
+
/** For testing: inject a custom vec loader (e.g. a throwing stub). */
|
|
75
|
+
static _openInMemoryWithLoader(loader: VecLoader): DatabaseManager;
|
|
76
|
+
get db(): BetterSqlite3.Database;
|
|
77
|
+
close(): void;
|
|
78
|
+
}
|
|
79
|
+
//#endregion
|
|
80
|
+
//#region src/activity/infrastructure/sqlite-activity-repository.d.ts
|
|
81
|
+
declare class SqliteActivityRepository implements ActivityRepository {
|
|
82
|
+
#private;
|
|
83
|
+
constructor(db: DatabaseManager);
|
|
84
|
+
insert(event: {
|
|
85
|
+
id: string;
|
|
86
|
+
projectHash: string;
|
|
87
|
+
eventType: string;
|
|
88
|
+
memoryId: string | null;
|
|
89
|
+
payload: Record<string, unknown>;
|
|
90
|
+
createdAt: string;
|
|
91
|
+
}): void;
|
|
92
|
+
list(filter: {
|
|
93
|
+
scope?: string;
|
|
94
|
+
type?: string;
|
|
95
|
+
since?: string;
|
|
96
|
+
limit?: number;
|
|
97
|
+
}): ActivityEvent[];
|
|
98
|
+
prune(olderThan: string): void;
|
|
99
|
+
}
|
|
100
|
+
declare function createActivityRepository(db: DatabaseManager): SqliteActivityRepository;
|
|
101
|
+
declare function createActivityLogger(db: DatabaseManager): ActivityLogger;
|
|
102
|
+
//#endregion
|
|
5
103
|
//#region src/config/loader.d.ts
|
|
6
104
|
declare function isSynthesisEnabled(): boolean;
|
|
7
105
|
//#endregion
|
|
@@ -262,19 +360,6 @@ declare class DatabaseError extends MembankError {
|
|
|
262
360
|
constructor(message: string, options?: ErrorOptions);
|
|
263
361
|
}
|
|
264
362
|
//#endregion
|
|
265
|
-
//#region src/db/manager.d.ts
|
|
266
|
-
type VecLoader = (db: BetterSqlite3.Database) => void;
|
|
267
|
-
declare class DatabaseManager {
|
|
268
|
-
#private;
|
|
269
|
-
private constructor();
|
|
270
|
-
static open(dbPath?: string): DatabaseManager;
|
|
271
|
-
static openInMemory(): DatabaseManager;
|
|
272
|
-
/** For testing: inject a custom vec loader (e.g. a throwing stub). */
|
|
273
|
-
static _openInMemoryWithLoader(loader: VecLoader): DatabaseManager;
|
|
274
|
-
get db(): BetterSqlite3.Database;
|
|
275
|
-
close(): void;
|
|
276
|
-
}
|
|
277
|
-
//#endregion
|
|
278
363
|
//#region src/embedding/infrastructure/model-downloader.d.ts
|
|
279
364
|
declare const MODEL_NAME = "Xenova/bge-small-en-v1.5";
|
|
280
365
|
interface DownloadProgress {
|
|
@@ -476,7 +561,7 @@ interface TranscriptReaderOptions {
|
|
|
476
561
|
declare function createClaudeCodeTranscriptReader(opts?: TranscriptReaderOptions): TranscriptReader;
|
|
477
562
|
//#endregion
|
|
478
563
|
//#region src/memory/application/delete-memory.d.ts
|
|
479
|
-
declare function deleteMemory(id: string, repo: MemoryRepository): Promise<void>;
|
|
564
|
+
declare function deleteMemory(id: string, repo: MemoryRepository, activityLogger?: ActivityLogger): Promise<void>;
|
|
480
565
|
//#endregion
|
|
481
566
|
//#region src/memory/application/resolve-review.d.ts
|
|
482
567
|
declare function resolveReview(memoryId: string, repo: MemoryRepository): void;
|
|
@@ -485,12 +570,14 @@ declare function resolveReview(memoryId: string, repo: MemoryRepository): void;
|
|
|
485
570
|
declare function saveMemory(opts: SaveOptions, deps: {
|
|
486
571
|
repo: MemoryRepository;
|
|
487
572
|
embedder: Embedder;
|
|
573
|
+
activityLogger?: ActivityLogger;
|
|
488
574
|
}): Promise<Memory>;
|
|
489
575
|
//#endregion
|
|
490
576
|
//#region src/memory/application/update-memory.d.ts
|
|
491
577
|
declare function updateMemory(id: string, patch: MemoryPatch, deps: {
|
|
492
578
|
repo: MemoryRepository;
|
|
493
579
|
embedder: Embedder;
|
|
580
|
+
activityLogger?: ActivityLogger;
|
|
494
581
|
}): Promise<Memory>;
|
|
495
582
|
//#endregion
|
|
496
583
|
//#region src/memory/domain/pin-budget.d.ts
|
|
@@ -582,12 +669,13 @@ declare function queryMemories(options: QueryOptions, deps: {
|
|
|
582
669
|
adapter: QueryAdapter;
|
|
583
670
|
repo: Pick<MemoryRepository, "incrementAccessCount">;
|
|
584
671
|
embedder: Embedder;
|
|
672
|
+
activityLogger?: ActivityLogger;
|
|
585
673
|
}): Promise<ScoredMemory[]>;
|
|
586
674
|
//#endregion
|
|
587
675
|
//#region src/query/engine.d.ts
|
|
588
676
|
declare class QueryEngine implements Querier {
|
|
589
677
|
#private;
|
|
590
|
-
constructor(db: DatabaseManager, embeddingService: Embedder, repo: MemoryRepository);
|
|
678
|
+
constructor(db: DatabaseManager, embeddingService: Embedder, repo: MemoryRepository, activityLogger?: ActivityLogger);
|
|
591
679
|
query(options: QueryOptions): Promise<ScoredMemory[]>;
|
|
592
680
|
}
|
|
593
681
|
//#endregion
|
|
@@ -675,5 +763,5 @@ declare function createSynthesisAgentRunner(tools: SynthesisTools, config: Synth
|
|
|
675
763
|
//#region src/synthesis/infrastructure/sqlite-synthesis-repository.d.ts
|
|
676
764
|
declare function createSynthesisRepository(db: DatabaseManager): SynthesisRepository;
|
|
677
765
|
//#endregion
|
|
678
|
-
export { 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, 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, 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, createClaudeCodeTranscriptReader, createExtractionAgentRunner, createExtractionRunRepository, createMemoryRepository, createProjectRepository, createSynthesisAgentRunner, createSynthesisRepository, deleteMemory, getSessionContext, isOverBudget, isSynthesisEnabled, listMemoryTypes, queryMemories, resolveProject, resolveReview, resolveScope, rowToMemory, rowToProject, runExtraction, runScopeToProjectsMigration, runSynthesis, saveMemory, updateMemory };
|
|
766
|
+
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 };
|
|
679
767
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import{
|
|
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 ee}from"node:events";import{pipeline as h}from"@huggingface/transformers";import{createSdkMcpServer as g,query as _,tool as v}from"@anthropic-ai/claude-agent-sdk";import{readFile as te}from"node:fs/promises";import{execFile as ne}from"node:child_process";import{promisify as re}from"node:util";function ie(e,t){return t.list(e)}const y=[`memory.created`,`memory.updated`,`memory.deleted`,`memory.flagged`,`memory.queried`],b=a.enum(y),ae=30;function x(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 oe(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(oe)}prune(e){let t=Date.now();t-this.#t<6e4||(this.#r.run(e),this.#t=t)}};function se(e){return new S(e)}function ce(e){let t=new S(e);return{logEvent:e=>x(e,t)}}const C={logEvent(){}};function le(){let e=f(u(),`.membank`,`config.json`);try{let t=c(e,`utf8`);return JSON.parse(t)}catch{return null}}function ue(){return le()?.synthesis?.enabled===!0}const w=[`correction`,`preference`,`decision`,`learning`,`fact`],T=a.enum(w),E=a.array(a.string()),D=a.object({id:a.string(),name:a.string(),scopeHash:a.string(),createdAt:a.string(),updatedAt:a.string()}),O=a.enum([`similarity_dedup`]),k=a.object({id:a.string(),memoryId:a.string(),conflictingMemoryId:a.string().nullable(),similarity:a.number(),conflictContentSnapshot:a.string(),reason:O,createdAt:a.string(),resolvedAt:a.string().nullable()}),A=a.object({id:a.string(),memory_id:a.string(),conflicting_memory_id:a.string().nullable(),similarity:a.number(),conflict_content_snapshot:a.string(),reason:O,created_at:a.string(),resolved_at:a.string().nullable()}),j=a.object({id:a.string(),content:a.string(),type:T,tags:a.array(a.string()),projects:a.array(D),sourceHarness:a.string().nullable(),accessCount:a.number().int().nonnegative(),pinned:a.boolean(),reviewEvents:a.array(k),createdAt:a.string(),updatedAt:a.string()}),M=a.object({query:a.string().min(1),type:T.optional(),projectHash:a.string().optional(),limit:a.number().int().positive().optional(),includePinned:a.boolean().optional()}),N=a.object({content:a.string().min(1),type:T,tags:a.array(a.string()).optional(),projectScope:a.object({hash:a.string(),name:a.string()}).optional(),sourceHarness:a.string().optional()}),P=a.object({content:a.string().min(1).optional(),tags:a.array(a.string()).optional(),type:T.optional()}),F=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()}),de=a.object({stats:a.record(T,a.number()),pinnedGlobal:a.array(j),pinnedProject:a.array(j),synthesis:a.string().optional()}),I=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()}),L=a.object({id:a.string(),name:a.string(),scope_hash:a.string(),created_at:a.string(),updated_at:a.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 fe=f(u(),`.membank`,`memory.db`),pe=[[1,`
|
|
2
3
|
CREATE TABLE IF NOT EXISTS memories (
|
|
3
4
|
id TEXT PRIMARY KEY,
|
|
4
5
|
content TEXT NOT NULL,
|
|
@@ -154,14 +155,86 @@ CREATE TABLE IF NOT EXISTS extraction_runs (
|
|
|
154
155
|
|
|
155
156
|
CREATE INDEX IF NOT EXISTS idx_extraction_runs_status
|
|
156
157
|
ON extraction_runs(status) WHERE status = 'in_flight';
|
|
157
|
-
`]
|
|
158
|
+
`],[7,`
|
|
159
|
+
INSERT OR IGNORE INTO projects (id, name, scope_hash, created_at, updated_at)
|
|
160
|
+
VALUES ('00000000-0000-0000-0000-000000000000', 'global', '0000000000000000', datetime('now'), datetime('now'));
|
|
161
|
+
|
|
162
|
+
INSERT OR IGNORE INTO memory_projects (memory_id, project_id)
|
|
163
|
+
SELECT id, '00000000-0000-0000-0000-000000000000'
|
|
164
|
+
FROM memories
|
|
165
|
+
WHERE id NOT IN (SELECT memory_id FROM memory_projects);
|
|
166
|
+
`],[8,`
|
|
167
|
+
PRAGMA foreign_keys = OFF;
|
|
168
|
+
|
|
169
|
+
BEGIN;
|
|
170
|
+
|
|
171
|
+
UPDATE syntheses SET scope = '0000000000000000' WHERE scope = 'global';
|
|
172
|
+
|
|
173
|
+
DROP TABLE IF EXISTS syntheses_new;
|
|
174
|
+
|
|
175
|
+
CREATE TABLE syntheses_new (
|
|
176
|
+
id TEXT PRIMARY KEY,
|
|
177
|
+
scope TEXT NOT NULL REFERENCES projects(scope_hash) ON DELETE CASCADE,
|
|
178
|
+
content TEXT NOT NULL,
|
|
179
|
+
source_memory_hash TEXT NOT NULL,
|
|
180
|
+
synthesized_at TEXT NOT NULL,
|
|
181
|
+
expires_at TEXT NOT NULL,
|
|
182
|
+
in_flight_since TEXT,
|
|
183
|
+
created_at TEXT NOT NULL,
|
|
184
|
+
updated_at TEXT NOT NULL,
|
|
185
|
+
UNIQUE(scope),
|
|
186
|
+
CHECK(expires_at > synthesized_at)
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
INSERT INTO syntheses_new SELECT * FROM syntheses;
|
|
190
|
+
|
|
191
|
+
DROP TABLE syntheses;
|
|
192
|
+
ALTER TABLE syntheses_new RENAME TO syntheses;
|
|
193
|
+
|
|
194
|
+
CREATE INDEX IF NOT EXISTS idx_syntheses_expires_at ON syntheses(expires_at);
|
|
195
|
+
CREATE INDEX IF NOT EXISTS idx_syntheses_scope_inflight
|
|
196
|
+
ON syntheses(scope) WHERE in_flight_since IS NOT NULL;
|
|
197
|
+
|
|
198
|
+
COMMIT;
|
|
199
|
+
|
|
200
|
+
PRAGMA foreign_keys = ON;
|
|
201
|
+
`],[9,`
|
|
202
|
+
CREATE TABLE activity_events (
|
|
203
|
+
id TEXT PRIMARY KEY,
|
|
204
|
+
project_hash TEXT NOT NULL REFERENCES projects(scope_hash) ON DELETE CASCADE,
|
|
205
|
+
event_type TEXT NOT NULL,
|
|
206
|
+
memory_id TEXT,
|
|
207
|
+
payload TEXT NOT NULL,
|
|
208
|
+
created_at TEXT NOT NULL
|
|
209
|
+
);
|
|
210
|
+
|
|
211
|
+
CREATE INDEX idx_activity_project_created ON activity_events(project_hash, created_at DESC);
|
|
212
|
+
CREATE INDEX idx_activity_type_created ON activity_events(event_type, created_at DESC);
|
|
213
|
+
`],[10,`
|
|
214
|
+
ALTER TABLE activity_events RENAME TO activity_events_old;
|
|
215
|
+
|
|
216
|
+
CREATE TABLE activity_events (
|
|
217
|
+
id TEXT PRIMARY KEY,
|
|
218
|
+
project_hash TEXT NOT NULL,
|
|
219
|
+
event_type TEXT NOT NULL,
|
|
220
|
+
memory_id TEXT,
|
|
221
|
+
payload TEXT NOT NULL,
|
|
222
|
+
created_at TEXT NOT NULL
|
|
223
|
+
);
|
|
224
|
+
|
|
225
|
+
INSERT INTO activity_events SELECT * FROM activity_events_old;
|
|
226
|
+
DROP TABLE activity_events_old;
|
|
227
|
+
|
|
228
|
+
CREATE INDEX idx_activity_project_created ON activity_events(project_hash, created_at DESC);
|
|
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;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 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(`
|
|
158
231
|
CREATE TABLE IF NOT EXISTS meta (
|
|
159
232
|
key TEXT PRIMARY KEY,
|
|
160
233
|
value TEXT NOT NULL
|
|
161
234
|
);
|
|
162
|
-
`);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
|
|
163
|
-
`);var
|
|
164
|
-
`),r=Object.fromEntries(Object.entries(process.env).filter(e=>e[1]!==void 0)),i=Date.now(),
|
|
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 U=`Xenova/bge-small-en-v1.5`;var W=class extends Error{constructor(e,t){super(e,t),this.name=`ModelDownloadError`}};function he(){return f(u(),`.membank`,`models`)}function G(e){if(!o(e))return!1;try{return l(e).length>0}catch{return!1}}var ge=class extends ee{modelPath;constructor(e){super(),this.modelPath=e??he()}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 h(`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}}},_e=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 h(`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=g({name:`membank-extraction-tools`,version:`1.0.0`,tools:[v(`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}}),v(`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})}]})),v(`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(`
|
|
237
|
+
`),r=Object.fromEntries(Object.entries(process.env).filter(e=>e[1]!==void 0)),i=Date.now(),o=_({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}}),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 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)
|
|
165
238
|
VALUES (?, ?, NULL, 'in_flight', NULL)
|
|
166
239
|
ON CONFLICT(session_id) DO UPDATE SET
|
|
167
240
|
started_at = excluded.started_at,
|
|
@@ -171,26 +244,25 @@ CREATE INDEX IF NOT EXISTS idx_extraction_runs_status
|
|
|
171
244
|
SET status = 'completed', completed_at = ?, error = NULL
|
|
172
245
|
WHERE session_id = ?`).run(t.toISOString(),e)}markFailed(e,t,n){this.#e.db.prepare(`UPDATE extraction_runs
|
|
173
246
|
SET status = 'failed', completed_at = ?, error = ?
|
|
174
|
-
WHERE session_id = ?`).run(t.toISOString(),n,e)}get(e){let t=this.#t(e);return t===void 0?void 0:
|
|
175
|
-
`)}var
|
|
176
|
-
`).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=
|
|
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 te(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(`
|
|
177
250
|
|
|
178
|
-
`);return r.length<=this.#t?r:r.slice(r.length-this.#t)}};function
|
|
251
|
+
`);return r.length<=this.#t?r:r.slice(r.length-this.#t)}};function Oe(e={}){return new De(e)}function ke(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()}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:a=[],projectScope:o,sourceHarness:s}=N.parse(e),{repo:c,embedder:l,activityLogger:u=C}=t,d=o?.hash??`0000000000000000`,f=await l.embed(n),[p]=c.findSimilar(f,r,o?.hash);if(p!==void 0){let e=je(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 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 K=8e3;function Pe(e){return e>=K}var q=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
|
|
179
252
|
FROM memories m JOIN embeddings e ON e.rowid = m.rowid
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
253
|
+
JOIN memory_projects mp ON mp.memory_id = m.id
|
|
254
|
+
JOIN projects p ON p.id = mp.project_id
|
|
255
|
+
WHERE m.type = ? AND p.scope_hash = ?
|
|
256
|
+
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
|
|
183
257
|
FROM memories m JOIN embeddings e ON e.rowid = m.rowid
|
|
184
258
|
JOIN memory_projects mp ON mp.memory_id = m.id
|
|
185
259
|
JOIN projects p ON p.id = mp.project_id
|
|
186
260
|
WHERE m.type = ? AND p.scope_hash = ?
|
|
187
|
-
ORDER BY similarity DESC LIMIT 1`).get(
|
|
188
|
-
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)
|
|
189
|
-
WHERE id NOT IN (SELECT memory_id FROM memory_projects)
|
|
190
|
-
AND pinned = 1`).all().map(e=>j(e,[]))}listPinnedForProject(e){return this.#e.db.prepare(`SELECT m.* FROM memories m
|
|
261
|
+
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)
|
|
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),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)??[])}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 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=>R(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
|
|
191
263
|
JOIN memory_projects mp ON mp.memory_id = m.id
|
|
192
264
|
JOIN projects p ON p.id = mp.project_id
|
|
193
|
-
WHERE p.scope_hash = ? AND m.pinned = 1`).all(e).map(e=>
|
|
265
|
+
WHERE p.scope_hash = ? AND m.pinned = 1`).all(e).map(e=>R(e,[]))}listFlagged(e){let t;if(t=e===void 0?this.#e.db.prepare(`SELECT * FROM memories
|
|
194
266
|
WHERE EXISTS (
|
|
195
267
|
SELECT 1 FROM memory_review_events e
|
|
196
268
|
WHERE e.memory_id = memories.id AND e.resolved_at IS NULL
|
|
@@ -201,45 +273,42 @@ CREATE INDEX IF NOT EXISTS idx_extraction_runs_status
|
|
|
201
273
|
WHERE e.memory_id = memories.id AND e.resolved_at IS NULL
|
|
202
274
|
)
|
|
203
275
|
AND ${this.#n()}
|
|
204
|
-
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=>
|
|
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=>R(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=>z(A.parse(e)))}createReviewEvent(e){let t=new Date().toISOString();this.#e.db.prepare(`INSERT INTO memory_review_events
|
|
205
277
|
(id, memory_id, conflicting_memory_id, similarity, conflict_content_snapshot, reason, created_at)
|
|
206
|
-
VALUES (?, ?, ?, ?, ?, 'similarity_dedup', ?)`).run(
|
|
207
|
-
WHERE pinned = 1 AND ${this.#n()}`).get(e)??{total:0}).total}stats(e){let t=Object.fromEntries(
|
|
278
|
+
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
|
|
279
|
+
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
|
|
208
280
|
WHERE ${this.#n()}
|
|
209
|
-
GROUP BY type`).all(e);for(let e of n){let n=
|
|
281
|
+
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,
|
|
210
282
|
COALESCE(SUM(CASE WHEN pinned = 1 THEN LENGTH(content) ELSE 0 END), 0) as pinBudgetChars
|
|
211
283
|
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
|
|
212
284
|
FROM memory_review_events e
|
|
213
285
|
JOIN memories m ON m.id = e.memory_id
|
|
214
286
|
WHERE e.resolved_at IS NULL
|
|
215
|
-
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=
|
|
216
|
-
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`
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
))`}#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
|
|
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=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()}}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
|
+
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
|
+
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 = '${t}')
|
|
291
|
+
)`}#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
|
|
221
292
|
WHERE memory_id IN (${n}) ${r}
|
|
222
|
-
ORDER BY created_at DESC`).all(...e),a=new Map;for(let e of i){let t=
|
|
293
|
+
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 q(e,t)}const J=re(ne);function Y(e){return r(`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(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),B(L.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 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
|
|
223
294
|
JOIN memory_projects mp ON mp.project_id = p.id
|
|
224
|
-
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(
|
|
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(B(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}=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: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,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=`
|
|
225
296
|
SELECT m.*, (1 - vec_distance_cosine(e.embedding, ?)) AS cosine_sim
|
|
226
297
|
FROM memories m JOIN embeddings e ON e.rowid = m.rowid
|
|
227
|
-
${s}
|
|
228
298
|
${c}
|
|
229
|
-
|
|
299
|
+
${l}
|
|
300
|
+
`;return this.#e.db.prepare(u).all(...s).map(e=>({...R(e,[]),cosineSim:e.cosine_sim}))}},We=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 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[...w]}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=g({name:`membank-synthesis-tools`,version:`1.0.0`,tools:[v(`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}}),v(`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=_({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 Xe(e,t){return new Ye(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 Ze=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
|
|
230
301
|
SET content = ?, source_memory_hash = ?, synthesized_at = ?, expires_at = ?,
|
|
231
302
|
in_flight_since = NULL, updated_at = ?
|
|
232
|
-
WHERE scope = ?`).run(t,n,r,
|
|
303
|
+
WHERE scope = ?`).run(t,n,r,a,r,e);else{let o=i();this.#e.db.prepare(`INSERT INTO syntheses
|
|
233
304
|
(id, scope, content, source_memory_hash, synthesized_at, expires_at,
|
|
234
305
|
in_flight_since, created_at, updated_at)
|
|
235
|
-
VALUES (?, ?, ?, ?, ?, ?, NULL, ?, ?)`).run(
|
|
306
|
+
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
|
|
236
307
|
(id, scope, content, source_memory_hash, synthesized_at, expires_at,
|
|
237
308
|
in_flight_since, created_at, updated_at)
|
|
238
|
-
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
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
WHERE p.scope_hash = ?
|
|
244
|
-
ORDER BY m.id`).all(e),h(`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[`global`,...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 ze(e){return new Re(e)}export{F as DatabaseError,ce as DatabaseManager,B as EmbeddingService,_ as MEMORY_TYPE_VALUES,we as MIGRATIONS,I as MODEL_NAME,P as MembankError,D as MemoryPatchSchema,k as MemoryRowSchema,w as MemorySchema,v as MemoryTypeSchema,L as ModelDownloadError,z as ModelDownloader,K as PIN_BUDGET_THRESHOLD,A as ProjectRowSchema,b as ProjectSchema,je as QueryEngine,T as QueryOptionsSchema,C as ReviewEventRowSchema,S as ReviewEventSchema,x as ReviewReasonSchema,E as SaveOptionsSchema,Ne as SessionContextBuilder,ae as SessionContextSchema,q as SqliteMemoryRepository,Pe as SynthesisEngine,O as SynthesisSchema,y as TagsJsonSchema,ge as createClaudeCodeTranscriptReader,W as createExtractionAgentRunner,pe as createExtractionRunRepository,Se as createMemoryRepository,De as createProjectRepository,Le as createSynthesisAgentRunner,ze as createSynthesisRepository,_e as deleteMemory,Q as getSessionContext,xe as isOverBudget,ie as isSynthesisEnabled,Me as listMemoryTypes,Z as queryMemories,X as resolveProject,ve as resolveReview,Ce as resolveScope,j as rowToMemory,N as rowToProject,V as runExtraction,Te as runScopeToProjectsMigration,Fe as runSynthesis,ye as saveMemory,be as updateMemory};
|
|
309
|
+
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
|
+
JOIN memory_projects mp ON mp.memory_id = m.id
|
|
311
|
+
JOIN projects p ON p.id = mp.project_id
|
|
312
|
+
WHERE p.scope_hash = ?
|
|
313
|
+
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 Qe(e){return new Ze(e)}export{y as ACTIVITY_EVENT_TYPE_VALUES,b as ActivityEventTypeSchema,H as DatabaseError,me as DatabaseManager,_e as EmbeddingService,n as GLOBAL_PROJECT_ID,e as GLOBAL_PROJECT_NAME,t as GLOBAL_SCOPE_HASH,w as MEMORY_TYPE_VALUES,Le as MIGRATIONS,U as MODEL_NAME,V as MembankError,P as MemoryPatchSchema,I as MemoryRowSchema,j as MemorySchema,T as MemoryTypeSchema,W as ModelDownloadError,ge as ModelDownloader,K as PIN_BUDGET_THRESHOLD,L as ProjectRowSchema,D as ProjectSchema,We as QueryEngine,M as QueryOptionsSchema,ae as RETENTION_DAYS,A as ReviewEventRowSchema,k as ReviewEventSchema,O as ReviewReasonSchema,N as SaveOptionsSchema,Ke as SessionContextBuilder,de as SessionContextSchema,q as SqliteMemoryRepository,qe as SynthesisEngine,F as SynthesisSchema,E as TagsJsonSchema,ce as createActivityLogger,se 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,ue as isSynthesisEnabled,ie as listEvents,Ge as listMemoryTypes,x as logEvent,C as noopActivityLogger,Z as queryMemories,X as resolveProject,Ae as resolveReview,Ie as resolveScope,R as rowToMemory,B as rowToProject,ve as runExtraction,Re as runScopeToProjectsMigration,Je as runSynthesis,Me as saveMemory,Ne as updateMemory};
|
|
245
314
|
//# sourceMappingURL=index.mjs.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@membank/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.1",
|
|
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
|
-
|
|
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": [
|