@membank/core 0.5.1 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -66,6 +66,39 @@ CREATE TABLE IF NOT EXISTS memories (
66
66
  CREATE VIRTUAL TABLE IF NOT EXISTS embeddings USING vec0(
67
67
  embedding FLOAT[384]
68
68
  );
69
+ `], [2, `
70
+ CREATE TABLE IF NOT EXISTS projects (
71
+ id TEXT PRIMARY KEY,
72
+ name TEXT NOT NULL,
73
+ scope_hash TEXT NOT NULL UNIQUE,
74
+ created_at TEXT NOT NULL,
75
+ updated_at TEXT NOT NULL
76
+ );
77
+
78
+ CREATE TABLE IF NOT EXISTS memory_projects (
79
+ memory_id TEXT NOT NULL REFERENCES memories(id) ON DELETE CASCADE,
80
+ project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
81
+ PRIMARY KEY (memory_id, project_id)
82
+ );
83
+
84
+ INSERT OR IGNORE INTO projects (id, name, scope_hash, created_at, updated_at)
85
+ SELECT
86
+ lower(hex(randomblob(16))),
87
+ 'project-' || substr(scope, 1, 8),
88
+ scope,
89
+ datetime('now'),
90
+ datetime('now')
91
+ FROM memories
92
+ WHERE scope != 'global'
93
+ GROUP BY scope;
94
+
95
+ INSERT OR IGNORE INTO memory_projects (memory_id, project_id)
96
+ SELECT m.id, p.id
97
+ FROM memories m
98
+ JOIN projects p ON p.scope_hash = m.scope
99
+ WHERE m.scope != 'global';
100
+
101
+ ALTER TABLE memories DROP COLUMN scope;
69
102
  `]];
70
103
  var DatabaseManager = class DatabaseManager {
71
104
  #db;
@@ -96,6 +129,7 @@ var DatabaseManager = class DatabaseManager {
96
129
  throw new DatabaseError("Failed to load sqlite-vec extension", { cause: err });
97
130
  }
98
131
  db.pragma("journal_mode = WAL");
132
+ db.pragma("foreign_keys = ON");
99
133
  const manager = new DatabaseManager(db);
100
134
  manager.#runMigrations();
101
135
  return manager;
@@ -123,13 +157,13 @@ var DatabaseManager = class DatabaseManager {
123
157
  };
124
158
  //#endregion
125
159
  //#region src/db/row-types.ts
126
- function rowToMemory(row) {
160
+ function rowToMemory(row, projects) {
127
161
  return {
128
162
  id: row.id,
129
163
  content: row.content,
130
164
  type: row.type,
131
165
  tags: JSON.parse(row.tags),
132
- scope: row.scope,
166
+ projects,
133
167
  sourceHarness: row.source,
134
168
  accessCount: row.access_count,
135
169
  pinned: row.pinned !== 0,
@@ -138,6 +172,15 @@ function rowToMemory(row) {
138
172
  updatedAt: row.updated_at
139
173
  };
140
174
  }
175
+ function rowToProject(row) {
176
+ return {
177
+ id: row.id,
178
+ name: row.name,
179
+ scopeHash: row.scope_hash,
180
+ createdAt: row.created_at,
181
+ updatedAt: row.updated_at
182
+ };
183
+ }
141
184
  //#endregion
142
185
  //#region src/embedding/service.ts
143
186
  var EmbeddingService = class {
@@ -177,30 +220,44 @@ const MEMORY_TYPE_VALUES = [
177
220
  var MemoryRepository = class {
178
221
  #db;
179
222
  #embedding;
180
- constructor(db, embeddingService) {
223
+ #projects;
224
+ constructor(db, embeddingService, projects) {
181
225
  this.#db = db;
182
226
  this.#embedding = embeddingService;
227
+ this.#projects = projects;
183
228
  }
184
229
  async save(options) {
185
- const { content, type, tags = [], scope = "global", sourceHarness } = options;
230
+ const { content, type, tags = [], projectHash, sourceHarness } = options;
186
231
  const embedding = await this.#embedding.embed(content);
187
232
  const embeddingBlob = Buffer.from(embedding.buffer);
188
- const top = this.#db.db.prepare(`SELECT m.rowid, m.*, (1 - vec_distance_cosine(e.embedding, ?)) AS similarity
189
- FROM memories m JOIN embeddings e ON e.rowid = m.rowid
190
- WHERE m.type = ? AND m.scope = ?
191
- ORDER BY similarity DESC LIMIT 1`).get(embeddingBlob, type, scope);
233
+ let top;
234
+ if (projectHash !== void 0) top = this.#db.db.prepare(`SELECT m.rowid, m.*, (1 - vec_distance_cosine(e.embedding, ?)) AS similarity
235
+ FROM memories m JOIN embeddings e ON e.rowid = m.rowid
236
+ JOIN memory_projects mp ON mp.memory_id = m.id
237
+ JOIN projects p ON p.id = mp.project_id
238
+ WHERE m.type = ? AND p.scope_hash = ?
239
+ ORDER BY similarity DESC LIMIT 1`).get(embeddingBlob, type, projectHash);
240
+ else top = this.#db.db.prepare(`SELECT m.rowid, m.*, (1 - vec_distance_cosine(e.embedding, ?)) AS similarity
241
+ FROM memories m JOIN embeddings e ON e.rowid = m.rowid
242
+ WHERE m.type = ?
243
+ AND m.id NOT IN (SELECT memory_id FROM memory_projects)
244
+ ORDER BY similarity DESC LIMIT 1`).get(embeddingBlob, type);
192
245
  const now = (/* @__PURE__ */ new Date()).toISOString();
193
246
  if (top !== void 0 && top.similarity > .92) {
194
247
  this.#db.db.prepare(`UPDATE memories SET content = ?, updated_at = ? WHERE id = ?`).run(content, now, top.id);
195
248
  this.#db.db.prepare(`UPDATE embeddings SET embedding = ? WHERE rowid = ?`).run(embeddingBlob, top.rowid);
196
- return rowToMemory(this.#db.db.prepare(`SELECT * FROM memories WHERE id = ?`).get(top.id));
249
+ return rowToMemory(this.#db.db.prepare(`SELECT * FROM memories WHERE id = ?`).get(top.id), this.#projects.getProjectsForMemories([top.id]).get(top.id) ?? []);
197
250
  }
198
251
  if (top !== void 0 && top.similarity >= .75) this.#db.db.prepare(`UPDATE memories SET needs_review = 1 WHERE id = ?`).run(top.id);
199
252
  const id = (0, node_crypto.randomUUID)();
200
- this.#db.db.prepare(`INSERT INTO memories (id, content, type, tags, scope, source, access_count, pinned, needs_review, created_at, updated_at)
201
- VALUES (?, ?, ?, ?, ?, ?, 0, 0, 0, ?, ?)`).run(id, content, type, JSON.stringify(tags), scope, sourceHarness ?? null, now, now);
253
+ this.#db.db.prepare(`INSERT INTO memories (id, content, type, tags, source, access_count, pinned, needs_review, created_at, updated_at)
254
+ VALUES (?, ?, ?, ?, ?, 0, 0, 0, ?, ?)`).run(id, content, type, JSON.stringify(tags), sourceHarness ?? null, now, now);
202
255
  this.#db.db.prepare(`INSERT INTO embeddings (rowid, embedding) SELECT m.rowid, ? FROM memories m WHERE m.id = ?`).run(embeddingBlob, id);
203
- return rowToMemory(this.#db.db.prepare(`SELECT * FROM memories WHERE id = ?`).get(id));
256
+ if (projectHash !== void 0) {
257
+ const project = this.#projects.upsertByHash(projectHash, `project-${projectHash.slice(0, 8)}`);
258
+ this.#projects.addAssociation(id, project.id);
259
+ }
260
+ return rowToMemory(this.#db.db.prepare(`SELECT * FROM memories WHERE id = ?`).get(id), this.#projects.getProjectsForMemories([id]).get(id) ?? []);
204
261
  }
205
262
  async update(id, patch) {
206
263
  const existing = this.#db.db.prepare(`SELECT m.rowid, m.* FROM memories m WHERE m.id = ?`).get(id);
@@ -223,11 +280,12 @@ var MemoryRepository = class {
223
280
  const embeddingBlob = Buffer.from(embedding.buffer);
224
281
  this.#db.db.prepare(`UPDATE embeddings SET embedding = ? WHERE rowid = ?`).run(embeddingBlob, existing.rowid);
225
282
  }
226
- return rowToMemory(this.#db.db.prepare(`SELECT * FROM memories WHERE id = ?`).get(id));
283
+ return rowToMemory(this.#db.db.prepare(`SELECT * FROM memories WHERE id = ?`).get(id), this.#projects.getProjectsForMemories([id]).get(id) ?? []);
227
284
  }
228
285
  delete(id) {
229
286
  const row = this.#db.db.prepare(`SELECT rowid FROM memories WHERE id = ?`).get(id);
230
287
  if (row !== void 0) this.#db.db.prepare(`DELETE FROM embeddings WHERE rowid = ?`).run(row.rowid);
288
+ this.#db.db.prepare(`DELETE FROM memory_projects WHERE memory_id = ?`).run(id);
231
289
  this.#db.db.prepare(`DELETE FROM memories WHERE id = ?`).run(id);
232
290
  return Promise.resolve();
233
291
  }
@@ -240,7 +298,11 @@ var MemoryRepository = class {
240
298
  }
241
299
  if (opts?.pinned === true) conditions.push("pinned = 1");
242
300
  const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
243
- return this.#db.db.prepare(`SELECT * FROM memories ${where} ORDER BY created_at DESC`).all(...params).map(rowToMemory);
301
+ const rows = this.#db.db.prepare(`SELECT * FROM memories ${where} ORDER BY created_at DESC`).all(...params);
302
+ if (rows.length === 0) return [];
303
+ const ids = rows.map((r) => r.id);
304
+ const projectMap = this.#projects.getProjectsForMemories(ids);
305
+ return rows.map((row) => rowToMemory(row, projectMap.get(row.id) ?? []));
244
306
  }
245
307
  stats() {
246
308
  const byType = Object.fromEntries(MEMORY_TYPE_VALUES.map((t) => [t, 0]));
@@ -260,13 +322,61 @@ var MemoryRepository = class {
260
322
  if (this.#db.db.prepare(`SELECT * FROM memories WHERE id = ?`).get(id) === void 0) throw new Error(`Memory not found: ${id}`);
261
323
  const now = (/* @__PURE__ */ new Date()).toISOString();
262
324
  this.#db.db.prepare(`UPDATE memories SET pinned = ?, updated_at = ? WHERE id = ?`).run(pinned ? 1 : 0, now, id);
263
- return rowToMemory(this.#db.db.prepare(`SELECT * FROM memories WHERE id = ?`).get(id));
325
+ return rowToMemory(this.#db.db.prepare(`SELECT * FROM memories WHERE id = ?`).get(id), this.#projects.getProjectsForMemories([id]).get(id) ?? []);
264
326
  }
265
327
  incrementAccessCount(id) {
266
328
  this.#db.db.prepare(`UPDATE memories SET access_count = access_count + 1 WHERE id = ?`).run(id);
267
329
  }
268
330
  };
269
331
  //#endregion
332
+ //#region src/project/repository.ts
333
+ var ProjectRepository = class {
334
+ #db;
335
+ constructor(db) {
336
+ this.#db = db;
337
+ }
338
+ upsertByHash(hash, name) {
339
+ const now = (/* @__PURE__ */ new Date()).toISOString();
340
+ const id = (0, node_crypto.randomUUID)();
341
+ this.#db.db.prepare(`INSERT OR IGNORE INTO projects (id, name, scope_hash, created_at, updated_at) VALUES (?, ?, ?, ?, ?)`).run(id, name, hash, now, now);
342
+ return rowToProject(this.#db.db.prepare(`SELECT * FROM projects WHERE scope_hash = ?`).get(hash));
343
+ }
344
+ rename(id, name) {
345
+ const now = (/* @__PURE__ */ new Date()).toISOString();
346
+ this.#db.db.prepare(`UPDATE projects SET name = ?, updated_at = ? WHERE id = ?`).run(name, now, id);
347
+ const row = this.#db.db.prepare(`SELECT * FROM projects WHERE id = ?`).get(id);
348
+ if (row === void 0) throw new Error(`Project not found: ${id}`);
349
+ return rowToProject(row);
350
+ }
351
+ list() {
352
+ return this.#db.db.prepare(`SELECT * FROM projects ORDER BY name ASC`).all().map(rowToProject);
353
+ }
354
+ getByHash(hash) {
355
+ const row = this.#db.db.prepare(`SELECT * FROM projects WHERE scope_hash = ?`).get(hash);
356
+ return row !== void 0 ? rowToProject(row) : void 0;
357
+ }
358
+ addAssociation(memoryId, projectId) {
359
+ this.#db.db.prepare(`INSERT OR IGNORE INTO memory_projects (memory_id, project_id) VALUES (?, ?)`).run(memoryId, projectId);
360
+ }
361
+ removeAssociation(memoryId, projectId) {
362
+ this.#db.db.prepare(`DELETE FROM memory_projects WHERE memory_id = ? AND project_id = ?`).run(memoryId, projectId);
363
+ }
364
+ getProjectsForMemories(memoryIds) {
365
+ if (memoryIds.length === 0) return /* @__PURE__ */ new Map();
366
+ const placeholders = memoryIds.map(() => "?").join(",");
367
+ const rows = this.#db.db.prepare(`SELECT p.*, mp.memory_id FROM projects p
368
+ JOIN memory_projects mp ON mp.project_id = p.id
369
+ WHERE mp.memory_id IN (${placeholders})`).all(...memoryIds);
370
+ const result = /* @__PURE__ */ new Map();
371
+ for (const row of rows) {
372
+ const list = result.get(row.memory_id) ?? [];
373
+ list.push(rowToProject(row));
374
+ result.set(row.memory_id, list);
375
+ }
376
+ return result;
377
+ }
378
+ };
379
+ //#endregion
270
380
  //#region src/query/engine.ts
271
381
  const TYPE_WEIGHTS = {
272
382
  correction: 1,
@@ -285,28 +395,32 @@ var QueryEngine = class {
285
395
  this.#repo = repo;
286
396
  }
287
397
  async query(options) {
288
- const { query, type, scope, limit = 10 } = options;
398
+ const { query, type, projectHash, limit = 10 } = options;
289
399
  const queryEmbedding = await this.#embedding.embed(query);
290
400
  const queryBlob = Buffer.from(queryEmbedding.buffer);
291
401
  const whereClauses = [];
292
402
  const params = [queryBlob];
403
+ let joinClause = "";
293
404
  if (type !== void 0) {
294
405
  whereClauses.push("m.type = ?");
295
406
  params.push(type);
296
407
  }
297
- if (scope !== void 0) {
298
- whereClauses.push("m.scope = ?");
299
- params.push(scope);
408
+ if (projectHash !== void 0) {
409
+ joinClause = "LEFT JOIN memory_projects mp ON mp.memory_id = m.id LEFT JOIN projects p ON p.id = mp.project_id";
410
+ whereClauses.push("p.scope_hash = ?");
411
+ params.push(projectHash);
300
412
  }
413
+ const whereSQL = whereClauses.length > 0 ? `WHERE ${whereClauses.join(" AND ")}` : "";
301
414
  const sql = `
302
415
  SELECT m.*, (1 - vec_distance_cosine(e.embedding, ?)) AS cosine_sim
303
416
  FROM memories m JOIN embeddings e ON e.rowid = m.rowid
304
- ${whereClauses.length > 0 ? `WHERE ${whereClauses.join(" AND ")}` : ""}
417
+ ${joinClause}
418
+ ${whereSQL}
305
419
  `;
306
420
  const rows = this.#db.db.prepare(sql).all(...params);
307
421
  const now = Date.now();
308
422
  const scored = rows.filter((row) => row.cosine_sim > 0).map((row) => {
309
- const memory = rowToMemory(row);
423
+ const memory = rowToMemory(row, []);
310
424
  const score = this.#computeScore(memory, now);
311
425
  return {
312
426
  ...memory,
@@ -332,6 +446,29 @@ const execFileAsync = (0, node_util.promisify)(node_child_process.execFile);
332
446
  function sha256Truncated(input) {
333
447
  return (0, node_crypto.createHash)("sha256").update(input).digest("hex").slice(0, 16);
334
448
  }
449
+ async function resolveProject() {
450
+ try {
451
+ const { stdout } = await execFileAsync("git", [
452
+ "remote",
453
+ "get-url",
454
+ "origin"
455
+ ]);
456
+ const url = stdout.trim();
457
+ if (url) {
458
+ const hash = sha256Truncated(url);
459
+ return {
460
+ hash,
461
+ name: url.split("/").pop()?.replace(/\.git$/, "") ?? hash.slice(0, 8)
462
+ };
463
+ }
464
+ } catch {}
465
+ const cwd = process.cwd();
466
+ const hash = sha256Truncated(cwd);
467
+ return {
468
+ hash,
469
+ name: cwd.split(/[/\\]/).filter(Boolean).pop() ?? hash.slice(0, 8)
470
+ };
471
+ }
335
472
  async function resolveScope() {
336
473
  try {
337
474
  const { stdout } = await execFileAsync("git", [
@@ -354,9 +491,14 @@ var SessionContextBuilder = class {
354
491
  constructor(db) {
355
492
  this.#db = db;
356
493
  }
357
- getSessionContext(projectScope) {
358
- const pinnedGlobal = this.#db.db.prepare("SELECT * FROM memories WHERE scope = 'global' AND pinned = 1").all().map(rowToMemory);
359
- const pinnedProject = this.#db.db.prepare("SELECT * FROM memories WHERE scope = ? AND pinned = 1").all(projectScope).map(rowToMemory);
494
+ getSessionContext(projectHash) {
495
+ const pinnedGlobal = this.#db.db.prepare(`SELECT * FROM memories
496
+ WHERE id NOT IN (SELECT memory_id FROM memory_projects)
497
+ AND pinned = 1`).all().map((row) => rowToMemory(row, []));
498
+ const pinnedProject = this.#db.db.prepare(`SELECT m.* FROM memories m
499
+ JOIN memory_projects mp ON mp.memory_id = m.id
500
+ JOIN projects p ON p.id = mp.project_id
501
+ WHERE p.scope_hash = ? AND m.pinned = 1`).all(projectHash).map((row) => rowToMemory(row, []));
360
502
  const typeCounts = this.#db.db.prepare("SELECT type, COUNT(*) as count FROM memories GROUP BY type").all();
361
503
  const stats = Object.fromEntries(MEMORY_TYPE_VALUES.map((t) => [t, 0]));
362
504
  for (const row of typeCounts) if (stats[row.type] !== void 0) stats[row.type] = row.count;
@@ -374,8 +516,10 @@ exports.EmbeddingService = EmbeddingService;
374
516
  exports.MEMORY_TYPE_VALUES = MEMORY_TYPE_VALUES;
375
517
  exports.MembankError = MembankError;
376
518
  exports.MemoryRepository = MemoryRepository;
519
+ exports.ProjectRepository = ProjectRepository;
377
520
  exports.QueryEngine = QueryEngine;
378
521
  exports.SessionContextBuilder = SessionContextBuilder;
379
522
  exports.listMemoryTypes = listMemoryTypes;
523
+ exports.resolveProject = resolveProject;
380
524
  exports.resolveScope = resolveScope;
381
525
  exports.rowToMemory = rowToMemory;
package/dist/index.d.cts CHANGED
@@ -24,12 +24,19 @@ declare class DatabaseManager {
24
24
  //#region src/types.d.ts
25
25
  type MemoryType = "correction" | "preference" | "decision" | "learning" | "fact";
26
26
  declare const MEMORY_TYPE_VALUES: readonly ["correction", "preference", "decision", "learning", "fact"];
27
+ interface Project {
28
+ id: string;
29
+ name: string;
30
+ scopeHash: string;
31
+ createdAt: string;
32
+ updatedAt: string;
33
+ }
27
34
  interface Memory {
28
35
  id: string;
29
36
  content: string;
30
37
  type: MemoryType;
31
38
  tags: string[];
32
- scope: string;
39
+ projects: Project[];
33
40
  sourceHarness: string | null;
34
41
  accessCount: number;
35
42
  pinned: boolean;
@@ -40,14 +47,14 @@ interface Memory {
40
47
  interface QueryOptions {
41
48
  query: string;
42
49
  type?: MemoryType;
43
- scope?: string;
50
+ projectHash?: string;
44
51
  limit?: number;
45
52
  }
46
53
  interface SaveOptions {
47
54
  content: string;
48
55
  type: MemoryType;
49
56
  tags?: string[];
50
- scope?: string;
57
+ projectHash?: string;
51
58
  sourceHarness?: string;
52
59
  }
53
60
  interface SessionContext {
@@ -62,7 +69,6 @@ interface MemoryRow {
62
69
  content: string;
63
70
  type: string;
64
71
  tags: string;
65
- scope: string;
66
72
  source: string | null;
67
73
  access_count: number;
68
74
  pinned: number;
@@ -70,7 +76,7 @@ interface MemoryRow {
70
76
  created_at: string;
71
77
  updated_at: string;
72
78
  }
73
- declare function rowToMemory(row: MemoryRow): Memory;
79
+ declare function rowToMemory(row: MemoryRow, projects: Project[]): Memory;
74
80
  //#endregion
75
81
  //#region src/embedding/service.d.ts
76
82
  type ProgressCallback = (progress: {
@@ -86,10 +92,23 @@ declare class EmbeddingService {
86
92
  embed(text: string): Promise<Float32Array>;
87
93
  }
88
94
  //#endregion
95
+ //#region src/project/repository.d.ts
96
+ declare class ProjectRepository {
97
+ #private;
98
+ constructor(db: DatabaseManager);
99
+ upsertByHash(hash: string, name: string): Project;
100
+ rename(id: string, name: string): Project;
101
+ list(): Project[];
102
+ getByHash(hash: string): Project | undefined;
103
+ addAssociation(memoryId: string, projectId: string): void;
104
+ removeAssociation(memoryId: string, projectId: string): void;
105
+ getProjectsForMemories(memoryIds: string[]): Map<string, Project[]>;
106
+ }
107
+ //#endregion
89
108
  //#region src/memory/repository.d.ts
90
109
  declare class MemoryRepository {
91
110
  #private;
92
- constructor(db: DatabaseManager, embeddingService: EmbeddingService);
111
+ constructor(db: DatabaseManager, embeddingService: EmbeddingService, projects: ProjectRepository);
93
112
  save(options: SaveOptions): Promise<Memory>;
94
113
  update(id: string, patch: {
95
114
  content?: string;
@@ -119,6 +138,10 @@ declare class QueryEngine {
119
138
  }
120
139
  //#endregion
121
140
  //#region src/scope/resolver.d.ts
141
+ declare function resolveProject(): Promise<{
142
+ hash: string;
143
+ name: string;
144
+ }>;
122
145
  declare function resolveScope(): Promise<string>;
123
146
  //#endregion
124
147
  //#region src/session/builder.d.ts
@@ -126,8 +149,8 @@ declare function listMemoryTypes(): MemoryType[];
126
149
  declare class SessionContextBuilder {
127
150
  #private;
128
151
  constructor(db: DatabaseManager);
129
- getSessionContext(projectScope: string): SessionContext;
152
+ getSessionContext(projectHash: string): SessionContext;
130
153
  }
131
154
  //#endregion
132
- export { DatabaseError, DatabaseManager, EmbeddingService, MEMORY_TYPE_VALUES, MembankError, Memory, MemoryRepository, type MemoryRow, MemoryType, ProgressCallback, QueryEngine, QueryOptions, SaveOptions, SessionContext, SessionContextBuilder, listMemoryTypes, resolveScope, rowToMemory };
155
+ export { DatabaseError, DatabaseManager, EmbeddingService, MEMORY_TYPE_VALUES, MembankError, Memory, MemoryRepository, type MemoryRow, MemoryType, ProgressCallback, Project, ProjectRepository, QueryEngine, QueryOptions, SaveOptions, SessionContext, SessionContextBuilder, listMemoryTypes, resolveProject, resolveScope, rowToMemory };
133
156
  //# sourceMappingURL=index.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../src/db/errors.ts","../src/db/manager.ts","../src/types.ts","../src/db/row-types.ts","../src/embedding/service.ts","../src/memory/repository.ts","../src/query/engine.ts","../src/scope/resolver.ts","../src/session/builder.ts"],"mappings":";;;cAAa,YAAA,SAAqB,KAAA;cACpB,OAAA,UAAiB,OAAA,GAAU,YAAA;AAAA;AAAA,cAM5B,aAAA,SAAsB,YAAA;cACrB,OAAA,UAAiB,OAAA,GAAU,YAAA;AAAA;;;KCCpC,SAAA,IAAa,EAAA,EAAI,aAAA,CAAc,QAAA;AAAA,cA2BvB,eAAA;EAAA;UAGJ,WAAA,CAAA;EAAA,OAIA,IAAA,CAAK,MAAA,YAAkB,eAAA;EAAA,OAOvB,YAAA,CAAA,GAAgB,eAAA;EDlDS;EAAA,OCuDzB,uBAAA,CAAwB,MAAA,EAAQ,SAAA,GAAY,eAAA;EAAA,IAkD/C,EAAA,CAAA,GAAM,aAAA,CAAc,QAAA;EAIxB,KAAA,CAAA;AAAA;;;KC7GU,UAAA;AAAA,cAEC,kBAAA;AAAA,UAQI,MAAA;EACf,EAAA;EACA,OAAA;EACA,IAAA,EAAM,UAAA;EACN,IAAA;EACA,KAAA;EACA,aAAA;EACA,WAAA;EACA,MAAA;EACA,WAAA;EACA,SAAA;EACA,SAAA;AAAA;AAAA,UAGe,YAAA;EACf,KAAA;EACA,IAAA,GAAO,UAAA;EACP,KAAA;EACA,KAAA;AAAA;AAAA,UAGe,WAAA;EACf,OAAA;EACA,IAAA,EAAM,UAAA;EACN,IAAA;EACA,KAAA;EACA,aAAA;AAAA;AAAA,UAGe,cAAA;EACf,KAAA,EAAO,MAAA,CAAO,UAAA;EACd,YAAA,EAAc,MAAA;EACd,aAAA,EAAe,MAAA;AAAA;;;UCxCA,SAAA;EACf,EAAA;EACA,OAAA;EACA,IAAA;EACA,IAAA;EACA,KAAA;EACA,MAAA;EACA,YAAA;EACA,MAAA;EACA,YAAA;EACA,UAAA;EACA,UAAA;AAAA;AAAA,iBAGc,WAAA,CAAY,GAAA,EAAK,SAAA,GAAY,MAAA;;;KCZjC,gBAAA,IAAoB,QAAA;EAAY,MAAA;EAAgB,QAAA;AAAA;AAAA,cAE/C,gBAAA;EAAA,iBACM,cAAA;EAAA,iBACA,UAAA;EAAA,QACT,gBAAA;cAEI,cAAA,WAAyB,UAAA,GAAa,gBAAA;EAAA,QAKpC,WAAA;EAUR,KAAA,CAAM,IAAA,WAAe,OAAA,CAAQ,YAAA;AAAA;;;cCbxB,gBAAA;EAAA;cAIC,EAAA,EAAI,eAAA,EAAiB,gBAAA,EAAkB,gBAAA;EAK7C,IAAA,CAAK,OAAA,EAAS,WAAA,GAAc,OAAA,CAAQ,MAAA;EA6DpC,MAAA,CAAO,EAAA,UAAY,KAAA;IAAS,OAAA;IAAkB,IAAA;EAAA,IAAoB,OAAA,CAAQ,MAAA;EA2ChF,MAAA,CAAO,EAAA,WAAa,OAAA;EAcpB,IAAA,CAAK,IAAA;IAAS,IAAA,GAAO,UAAA;IAAY,MAAA;EAAA,IAAqB,MAAA;EAuBtD,KAAA,CAAA;IAAW,MAAA,EAAQ,MAAA,CAAO,UAAA;IAAqB,KAAA;IAAe,WAAA;EAAA;EA+B9D,MAAA,CAAO,EAAA,UAAY,MAAA,YAAkB,MAAA;EAqBrC,oBAAA,CAAqB,EAAA;AAAA;;;cCpMV,WAAA;EAAA;cAKC,EAAA,EAAI,eAAA,EAAiB,gBAAA,EAAkB,gBAAA,EAAkB,IAAA,EAAM,gBAAA;EAMrE,KAAA,CAAM,OAAA,EAAS,YAAA,GAAe,OAAA,CAAQ,KAAA,CAAM,MAAA;IAAW,KAAA;EAAA;AAAA;;;iBCpBzC,YAAA,CAAA,GAAgB,OAAA;;;iBCCtB,eAAA,CAAA,GAAmB,UAAA;AAAA,cAItB,qBAAA;EAAA;cAGC,EAAA,EAAI,eAAA;EAIhB,iBAAA,CAAkB,YAAA,WAAuB,cAAA;AAAA"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/db/errors.ts","../src/db/manager.ts","../src/types.ts","../src/db/row-types.ts","../src/embedding/service.ts","../src/project/repository.ts","../src/memory/repository.ts","../src/query/engine.ts","../src/scope/resolver.ts","../src/session/builder.ts"],"mappings":";;;cAAa,YAAA,SAAqB,KAAA;cACpB,OAAA,UAAiB,OAAA,GAAU,YAAA;AAAA;AAAA,cAM5B,aAAA,SAAsB,YAAA;cACrB,OAAA,UAAiB,OAAA,GAAU,YAAA;AAAA;;;KCCpC,SAAA,IAAa,EAAA,EAAI,aAAA,CAAc,QAAA;AAAA,cAgEvB,eAAA;EAAA;UAGJ,WAAA,CAAA;EAAA,OAIA,IAAA,CAAK,MAAA,YAAkB,eAAA;EAAA,OAOvB,YAAA,CAAA,GAAgB,eAAA;EDvFS;EAAA,OC4FzB,uBAAA,CAAwB,MAAA,EAAQ,SAAA,GAAY,eAAA;EAAA,IAmD/C,EAAA,CAAA,GAAM,aAAA,CAAc,QAAA;EAIxB,KAAA,CAAA;AAAA;;;KCnJU,UAAA;AAAA,cAEC,kBAAA;AAAA,UAQI,OAAA;EACf,EAAA;EACA,IAAA;EACA,SAAA;EACA,SAAA;EACA,SAAA;AAAA;AAAA,UAGe,MAAA;EACf,EAAA;EACA,OAAA;EACA,IAAA,EAAM,UAAA;EACN,IAAA;EACA,QAAA,EAAU,OAAA;EACV,aAAA;EACA,WAAA;EACA,MAAA;EACA,WAAA;EACA,SAAA;EACA,SAAA;AAAA;AAAA,UAGe,YAAA;EACf,KAAA;EACA,IAAA,GAAO,UAAA;EACP,WAAA;EACA,KAAA;AAAA;AAAA,UAGe,WAAA;EACf,OAAA;EACA,IAAA,EAAM,UAAA;EACN,IAAA;EACA,WAAA;EACA,aAAA;AAAA;AAAA,UAGe,cAAA;EACf,KAAA,EAAO,MAAA,CAAO,UAAA;EACd,YAAA,EAAc,MAAA;EACd,aAAA,EAAe,MAAA;AAAA;;;UChDA,SAAA;EACf,EAAA;EACA,OAAA;EACA,IAAA;EACA,IAAA;EACA,MAAA;EACA,YAAA;EACA,MAAA;EACA,YAAA;EACA,UAAA;EACA,UAAA;AAAA;AAAA,iBAWc,WAAA,CAAY,GAAA,EAAK,SAAA,EAAW,QAAA,EAAU,OAAA,KAAY,MAAA;;;KCnBtD,gBAAA,IAAoB,QAAA;EAAY,MAAA;EAAgB,QAAA;AAAA;AAAA,cAE/C,gBAAA;EAAA,iBACM,cAAA;EAAA,iBACA,UAAA;EAAA,QACT,gBAAA;cAEI,cAAA,WAAyB,UAAA,GAAa,gBAAA;EAAA,QAKpC,WAAA;EAUR,KAAA,CAAM,IAAA,WAAe,OAAA,CAAQ,YAAA;AAAA;;;cChBxB,iBAAA;EAAA;cAGC,EAAA,EAAI,eAAA;EAIhB,YAAA,CAAa,IAAA,UAAc,IAAA,WAAe,OAAA;EAgB1C,MAAA,CAAO,EAAA,UAAY,IAAA,WAAe,OAAA;EAclC,IAAA,CAAA,GAAQ,OAAA;EAOR,SAAA,CAAU,IAAA,WAAe,OAAA;EAOzB,cAAA,CAAe,QAAA,UAAkB,SAAA;EAMjC,iBAAA,CAAkB,QAAA,UAAkB,SAAA;EAMpC,sBAAA,CAAuB,SAAA,aAAsB,GAAA,SAAY,OAAA;AAAA;;;cC3D9C,gBAAA;EAAA;cAMT,EAAA,EAAI,eAAA,EACJ,gBAAA,EAAkB,gBAAA,EAClB,QAAA,EAAU,iBAAA;EAON,IAAA,CAAK,OAAA,EAAS,WAAA,GAAc,OAAA,CAAQ,MAAA;EAqFpC,MAAA,CAAO,EAAA,UAAY,KAAA;IAAS,OAAA;IAAkB,IAAA;EAAA,IAAoB,OAAA,CAAQ,MAAA;EA4ChF,MAAA,CAAO,EAAA,WAAa,OAAA;EAepB,IAAA,CAAK,IAAA;IAAS,IAAA,GAAO,UAAA;IAAY,MAAA;EAAA,IAAqB,MAAA;EA2BtD,KAAA,CAAA;IAAW,MAAA,EAAQ,MAAA,CAAO,UAAA;IAAqB,KAAA;IAAe,WAAA;EAAA;EA+B9D,MAAA,CAAO,EAAA,UAAY,MAAA,YAAkB,MAAA;EAsBrC,oBAAA,CAAqB,EAAA;AAAA;;;cC1OV,WAAA;EAAA;cAKC,EAAA,EAAI,eAAA,EAAiB,gBAAA,EAAkB,gBAAA,EAAkB,IAAA,EAAM,gBAAA;EAMrE,KAAA,CAAM,OAAA,EAAS,YAAA,GAAe,OAAA,CAAQ,KAAA,CAAM,MAAA;IAAW,KAAA;EAAA;AAAA;;;iBCpBzC,cAAA,CAAA,GAAkB,OAAA;EAAU,IAAA;EAAc,IAAA;AAAA;AAAA,iBAwB1C,YAAA,CAAA,GAAgB,OAAA;;;iBCvBtB,eAAA,CAAA,GAAmB,UAAA;AAAA,cAItB,qBAAA;EAAA;cAGC,EAAA,EAAI,eAAA;EAIhB,iBAAA,CAAkB,WAAA,WAAsB,cAAA;AAAA"}
package/dist/index.d.mts CHANGED
@@ -24,12 +24,19 @@ declare class DatabaseManager {
24
24
  //#region src/types.d.ts
25
25
  type MemoryType = "correction" | "preference" | "decision" | "learning" | "fact";
26
26
  declare const MEMORY_TYPE_VALUES: readonly ["correction", "preference", "decision", "learning", "fact"];
27
+ interface Project {
28
+ id: string;
29
+ name: string;
30
+ scopeHash: string;
31
+ createdAt: string;
32
+ updatedAt: string;
33
+ }
27
34
  interface Memory {
28
35
  id: string;
29
36
  content: string;
30
37
  type: MemoryType;
31
38
  tags: string[];
32
- scope: string;
39
+ projects: Project[];
33
40
  sourceHarness: string | null;
34
41
  accessCount: number;
35
42
  pinned: boolean;
@@ -40,14 +47,14 @@ interface Memory {
40
47
  interface QueryOptions {
41
48
  query: string;
42
49
  type?: MemoryType;
43
- scope?: string;
50
+ projectHash?: string;
44
51
  limit?: number;
45
52
  }
46
53
  interface SaveOptions {
47
54
  content: string;
48
55
  type: MemoryType;
49
56
  tags?: string[];
50
- scope?: string;
57
+ projectHash?: string;
51
58
  sourceHarness?: string;
52
59
  }
53
60
  interface SessionContext {
@@ -62,7 +69,6 @@ interface MemoryRow {
62
69
  content: string;
63
70
  type: string;
64
71
  tags: string;
65
- scope: string;
66
72
  source: string | null;
67
73
  access_count: number;
68
74
  pinned: number;
@@ -70,7 +76,7 @@ interface MemoryRow {
70
76
  created_at: string;
71
77
  updated_at: string;
72
78
  }
73
- declare function rowToMemory(row: MemoryRow): Memory;
79
+ declare function rowToMemory(row: MemoryRow, projects: Project[]): Memory;
74
80
  //#endregion
75
81
  //#region src/embedding/service.d.ts
76
82
  type ProgressCallback = (progress: {
@@ -86,10 +92,23 @@ declare class EmbeddingService {
86
92
  embed(text: string): Promise<Float32Array>;
87
93
  }
88
94
  //#endregion
95
+ //#region src/project/repository.d.ts
96
+ declare class ProjectRepository {
97
+ #private;
98
+ constructor(db: DatabaseManager);
99
+ upsertByHash(hash: string, name: string): Project;
100
+ rename(id: string, name: string): Project;
101
+ list(): Project[];
102
+ getByHash(hash: string): Project | undefined;
103
+ addAssociation(memoryId: string, projectId: string): void;
104
+ removeAssociation(memoryId: string, projectId: string): void;
105
+ getProjectsForMemories(memoryIds: string[]): Map<string, Project[]>;
106
+ }
107
+ //#endregion
89
108
  //#region src/memory/repository.d.ts
90
109
  declare class MemoryRepository {
91
110
  #private;
92
- constructor(db: DatabaseManager, embeddingService: EmbeddingService);
111
+ constructor(db: DatabaseManager, embeddingService: EmbeddingService, projects: ProjectRepository);
93
112
  save(options: SaveOptions): Promise<Memory>;
94
113
  update(id: string, patch: {
95
114
  content?: string;
@@ -119,6 +138,10 @@ declare class QueryEngine {
119
138
  }
120
139
  //#endregion
121
140
  //#region src/scope/resolver.d.ts
141
+ declare function resolveProject(): Promise<{
142
+ hash: string;
143
+ name: string;
144
+ }>;
122
145
  declare function resolveScope(): Promise<string>;
123
146
  //#endregion
124
147
  //#region src/session/builder.d.ts
@@ -126,8 +149,8 @@ declare function listMemoryTypes(): MemoryType[];
126
149
  declare class SessionContextBuilder {
127
150
  #private;
128
151
  constructor(db: DatabaseManager);
129
- getSessionContext(projectScope: string): SessionContext;
152
+ getSessionContext(projectHash: string): SessionContext;
130
153
  }
131
154
  //#endregion
132
- export { DatabaseError, DatabaseManager, EmbeddingService, MEMORY_TYPE_VALUES, MembankError, Memory, MemoryRepository, type MemoryRow, MemoryType, ProgressCallback, QueryEngine, QueryOptions, SaveOptions, SessionContext, SessionContextBuilder, listMemoryTypes, resolveScope, rowToMemory };
155
+ export { DatabaseError, DatabaseManager, EmbeddingService, MEMORY_TYPE_VALUES, MembankError, Memory, MemoryRepository, type MemoryRow, MemoryType, ProgressCallback, Project, ProjectRepository, QueryEngine, QueryOptions, SaveOptions, SessionContext, SessionContextBuilder, listMemoryTypes, resolveProject, resolveScope, rowToMemory };
133
156
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/db/errors.ts","../src/db/manager.ts","../src/types.ts","../src/db/row-types.ts","../src/embedding/service.ts","../src/memory/repository.ts","../src/query/engine.ts","../src/scope/resolver.ts","../src/session/builder.ts"],"mappings":";;;cAAa,YAAA,SAAqB,KAAA;cACpB,OAAA,UAAiB,OAAA,GAAU,YAAA;AAAA;AAAA,cAM5B,aAAA,SAAsB,YAAA;cACrB,OAAA,UAAiB,OAAA,GAAU,YAAA;AAAA;;;KCCpC,SAAA,IAAa,EAAA,EAAI,aAAA,CAAc,QAAA;AAAA,cA2BvB,eAAA;EAAA;UAGJ,WAAA,CAAA;EAAA,OAIA,IAAA,CAAK,MAAA,YAAkB,eAAA;EAAA,OAOvB,YAAA,CAAA,GAAgB,eAAA;EDlDS;EAAA,OCuDzB,uBAAA,CAAwB,MAAA,EAAQ,SAAA,GAAY,eAAA;EAAA,IAkD/C,EAAA,CAAA,GAAM,aAAA,CAAc,QAAA;EAIxB,KAAA,CAAA;AAAA;;;KC7GU,UAAA;AAAA,cAEC,kBAAA;AAAA,UAQI,MAAA;EACf,EAAA;EACA,OAAA;EACA,IAAA,EAAM,UAAA;EACN,IAAA;EACA,KAAA;EACA,aAAA;EACA,WAAA;EACA,MAAA;EACA,WAAA;EACA,SAAA;EACA,SAAA;AAAA;AAAA,UAGe,YAAA;EACf,KAAA;EACA,IAAA,GAAO,UAAA;EACP,KAAA;EACA,KAAA;AAAA;AAAA,UAGe,WAAA;EACf,OAAA;EACA,IAAA,EAAM,UAAA;EACN,IAAA;EACA,KAAA;EACA,aAAA;AAAA;AAAA,UAGe,cAAA;EACf,KAAA,EAAO,MAAA,CAAO,UAAA;EACd,YAAA,EAAc,MAAA;EACd,aAAA,EAAe,MAAA;AAAA;;;UCxCA,SAAA;EACf,EAAA;EACA,OAAA;EACA,IAAA;EACA,IAAA;EACA,KAAA;EACA,MAAA;EACA,YAAA;EACA,MAAA;EACA,YAAA;EACA,UAAA;EACA,UAAA;AAAA;AAAA,iBAGc,WAAA,CAAY,GAAA,EAAK,SAAA,GAAY,MAAA;;;KCZjC,gBAAA,IAAoB,QAAA;EAAY,MAAA;EAAgB,QAAA;AAAA;AAAA,cAE/C,gBAAA;EAAA,iBACM,cAAA;EAAA,iBACA,UAAA;EAAA,QACT,gBAAA;cAEI,cAAA,WAAyB,UAAA,GAAa,gBAAA;EAAA,QAKpC,WAAA;EAUR,KAAA,CAAM,IAAA,WAAe,OAAA,CAAQ,YAAA;AAAA;;;cCbxB,gBAAA;EAAA;cAIC,EAAA,EAAI,eAAA,EAAiB,gBAAA,EAAkB,gBAAA;EAK7C,IAAA,CAAK,OAAA,EAAS,WAAA,GAAc,OAAA,CAAQ,MAAA;EA6DpC,MAAA,CAAO,EAAA,UAAY,KAAA;IAAS,OAAA;IAAkB,IAAA;EAAA,IAAoB,OAAA,CAAQ,MAAA;EA2ChF,MAAA,CAAO,EAAA,WAAa,OAAA;EAcpB,IAAA,CAAK,IAAA;IAAS,IAAA,GAAO,UAAA;IAAY,MAAA;EAAA,IAAqB,MAAA;EAuBtD,KAAA,CAAA;IAAW,MAAA,EAAQ,MAAA,CAAO,UAAA;IAAqB,KAAA;IAAe,WAAA;EAAA;EA+B9D,MAAA,CAAO,EAAA,UAAY,MAAA,YAAkB,MAAA;EAqBrC,oBAAA,CAAqB,EAAA;AAAA;;;cCpMV,WAAA;EAAA;cAKC,EAAA,EAAI,eAAA,EAAiB,gBAAA,EAAkB,gBAAA,EAAkB,IAAA,EAAM,gBAAA;EAMrE,KAAA,CAAM,OAAA,EAAS,YAAA,GAAe,OAAA,CAAQ,KAAA,CAAM,MAAA;IAAW,KAAA;EAAA;AAAA;;;iBCpBzC,YAAA,CAAA,GAAgB,OAAA;;;iBCCtB,eAAA,CAAA,GAAmB,UAAA;AAAA,cAItB,qBAAA;EAAA;cAGC,EAAA,EAAI,eAAA;EAIhB,iBAAA,CAAkB,YAAA,WAAuB,cAAA;AAAA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/db/errors.ts","../src/db/manager.ts","../src/types.ts","../src/db/row-types.ts","../src/embedding/service.ts","../src/project/repository.ts","../src/memory/repository.ts","../src/query/engine.ts","../src/scope/resolver.ts","../src/session/builder.ts"],"mappings":"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"}
package/dist/index.mjs CHANGED
@@ -41,6 +41,39 @@ CREATE TABLE IF NOT EXISTS memories (
41
41
  CREATE VIRTUAL TABLE IF NOT EXISTS embeddings USING vec0(
42
42
  embedding FLOAT[384]
43
43
  );
44
+ `], [2, `
45
+ CREATE TABLE IF NOT EXISTS projects (
46
+ id TEXT PRIMARY KEY,
47
+ name TEXT NOT NULL,
48
+ scope_hash TEXT NOT NULL UNIQUE,
49
+ created_at TEXT NOT NULL,
50
+ updated_at TEXT NOT NULL
51
+ );
52
+
53
+ CREATE TABLE IF NOT EXISTS memory_projects (
54
+ memory_id TEXT NOT NULL REFERENCES memories(id) ON DELETE CASCADE,
55
+ project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
56
+ PRIMARY KEY (memory_id, project_id)
57
+ );
58
+
59
+ INSERT OR IGNORE INTO projects (id, name, scope_hash, created_at, updated_at)
60
+ SELECT
61
+ lower(hex(randomblob(16))),
62
+ 'project-' || substr(scope, 1, 8),
63
+ scope,
64
+ datetime('now'),
65
+ datetime('now')
66
+ FROM memories
67
+ WHERE scope != 'global'
68
+ GROUP BY scope;
69
+
70
+ INSERT OR IGNORE INTO memory_projects (memory_id, project_id)
71
+ SELECT m.id, p.id
72
+ FROM memories m
73
+ JOIN projects p ON p.scope_hash = m.scope
74
+ WHERE m.scope != 'global';
75
+
76
+ ALTER TABLE memories DROP COLUMN scope;
44
77
  `]];
45
78
  var DatabaseManager = class DatabaseManager {
46
79
  #db;
@@ -71,6 +104,7 @@ var DatabaseManager = class DatabaseManager {
71
104
  throw new DatabaseError("Failed to load sqlite-vec extension", { cause: err });
72
105
  }
73
106
  db.pragma("journal_mode = WAL");
107
+ db.pragma("foreign_keys = ON");
74
108
  const manager = new DatabaseManager(db);
75
109
  manager.#runMigrations();
76
110
  return manager;
@@ -98,13 +132,13 @@ var DatabaseManager = class DatabaseManager {
98
132
  };
99
133
  //#endregion
100
134
  //#region src/db/row-types.ts
101
- function rowToMemory(row) {
135
+ function rowToMemory(row, projects) {
102
136
  return {
103
137
  id: row.id,
104
138
  content: row.content,
105
139
  type: row.type,
106
140
  tags: JSON.parse(row.tags),
107
- scope: row.scope,
141
+ projects,
108
142
  sourceHarness: row.source,
109
143
  accessCount: row.access_count,
110
144
  pinned: row.pinned !== 0,
@@ -113,6 +147,15 @@ function rowToMemory(row) {
113
147
  updatedAt: row.updated_at
114
148
  };
115
149
  }
150
+ function rowToProject(row) {
151
+ return {
152
+ id: row.id,
153
+ name: row.name,
154
+ scopeHash: row.scope_hash,
155
+ createdAt: row.created_at,
156
+ updatedAt: row.updated_at
157
+ };
158
+ }
116
159
  //#endregion
117
160
  //#region src/embedding/service.ts
118
161
  var EmbeddingService = class {
@@ -152,30 +195,44 @@ const MEMORY_TYPE_VALUES = [
152
195
  var MemoryRepository = class {
153
196
  #db;
154
197
  #embedding;
155
- constructor(db, embeddingService) {
198
+ #projects;
199
+ constructor(db, embeddingService, projects) {
156
200
  this.#db = db;
157
201
  this.#embedding = embeddingService;
202
+ this.#projects = projects;
158
203
  }
159
204
  async save(options) {
160
- const { content, type, tags = [], scope = "global", sourceHarness } = options;
205
+ const { content, type, tags = [], projectHash, sourceHarness } = options;
161
206
  const embedding = await this.#embedding.embed(content);
162
207
  const embeddingBlob = Buffer.from(embedding.buffer);
163
- const top = this.#db.db.prepare(`SELECT m.rowid, m.*, (1 - vec_distance_cosine(e.embedding, ?)) AS similarity
164
- FROM memories m JOIN embeddings e ON e.rowid = m.rowid
165
- WHERE m.type = ? AND m.scope = ?
166
- ORDER BY similarity DESC LIMIT 1`).get(embeddingBlob, type, scope);
208
+ let top;
209
+ if (projectHash !== void 0) top = this.#db.db.prepare(`SELECT m.rowid, m.*, (1 - vec_distance_cosine(e.embedding, ?)) AS similarity
210
+ FROM memories m JOIN embeddings e ON e.rowid = m.rowid
211
+ JOIN memory_projects mp ON mp.memory_id = m.id
212
+ JOIN projects p ON p.id = mp.project_id
213
+ WHERE m.type = ? AND p.scope_hash = ?
214
+ ORDER BY similarity DESC LIMIT 1`).get(embeddingBlob, type, projectHash);
215
+ else top = this.#db.db.prepare(`SELECT m.rowid, m.*, (1 - vec_distance_cosine(e.embedding, ?)) AS similarity
216
+ FROM memories m JOIN embeddings e ON e.rowid = m.rowid
217
+ WHERE m.type = ?
218
+ AND m.id NOT IN (SELECT memory_id FROM memory_projects)
219
+ ORDER BY similarity DESC LIMIT 1`).get(embeddingBlob, type);
167
220
  const now = (/* @__PURE__ */ new Date()).toISOString();
168
221
  if (top !== void 0 && top.similarity > .92) {
169
222
  this.#db.db.prepare(`UPDATE memories SET content = ?, updated_at = ? WHERE id = ?`).run(content, now, top.id);
170
223
  this.#db.db.prepare(`UPDATE embeddings SET embedding = ? WHERE rowid = ?`).run(embeddingBlob, top.rowid);
171
- return rowToMemory(this.#db.db.prepare(`SELECT * FROM memories WHERE id = ?`).get(top.id));
224
+ return rowToMemory(this.#db.db.prepare(`SELECT * FROM memories WHERE id = ?`).get(top.id), this.#projects.getProjectsForMemories([top.id]).get(top.id) ?? []);
172
225
  }
173
226
  if (top !== void 0 && top.similarity >= .75) this.#db.db.prepare(`UPDATE memories SET needs_review = 1 WHERE id = ?`).run(top.id);
174
227
  const id = randomUUID();
175
- this.#db.db.prepare(`INSERT INTO memories (id, content, type, tags, scope, source, access_count, pinned, needs_review, created_at, updated_at)
176
- VALUES (?, ?, ?, ?, ?, ?, 0, 0, 0, ?, ?)`).run(id, content, type, JSON.stringify(tags), scope, sourceHarness ?? null, now, now);
228
+ this.#db.db.prepare(`INSERT INTO memories (id, content, type, tags, source, access_count, pinned, needs_review, created_at, updated_at)
229
+ VALUES (?, ?, ?, ?, ?, 0, 0, 0, ?, ?)`).run(id, content, type, JSON.stringify(tags), sourceHarness ?? null, now, now);
177
230
  this.#db.db.prepare(`INSERT INTO embeddings (rowid, embedding) SELECT m.rowid, ? FROM memories m WHERE m.id = ?`).run(embeddingBlob, id);
178
- return rowToMemory(this.#db.db.prepare(`SELECT * FROM memories WHERE id = ?`).get(id));
231
+ if (projectHash !== void 0) {
232
+ const project = this.#projects.upsertByHash(projectHash, `project-${projectHash.slice(0, 8)}`);
233
+ this.#projects.addAssociation(id, project.id);
234
+ }
235
+ return rowToMemory(this.#db.db.prepare(`SELECT * FROM memories WHERE id = ?`).get(id), this.#projects.getProjectsForMemories([id]).get(id) ?? []);
179
236
  }
180
237
  async update(id, patch) {
181
238
  const existing = this.#db.db.prepare(`SELECT m.rowid, m.* FROM memories m WHERE m.id = ?`).get(id);
@@ -198,11 +255,12 @@ var MemoryRepository = class {
198
255
  const embeddingBlob = Buffer.from(embedding.buffer);
199
256
  this.#db.db.prepare(`UPDATE embeddings SET embedding = ? WHERE rowid = ?`).run(embeddingBlob, existing.rowid);
200
257
  }
201
- return rowToMemory(this.#db.db.prepare(`SELECT * FROM memories WHERE id = ?`).get(id));
258
+ return rowToMemory(this.#db.db.prepare(`SELECT * FROM memories WHERE id = ?`).get(id), this.#projects.getProjectsForMemories([id]).get(id) ?? []);
202
259
  }
203
260
  delete(id) {
204
261
  const row = this.#db.db.prepare(`SELECT rowid FROM memories WHERE id = ?`).get(id);
205
262
  if (row !== void 0) this.#db.db.prepare(`DELETE FROM embeddings WHERE rowid = ?`).run(row.rowid);
263
+ this.#db.db.prepare(`DELETE FROM memory_projects WHERE memory_id = ?`).run(id);
206
264
  this.#db.db.prepare(`DELETE FROM memories WHERE id = ?`).run(id);
207
265
  return Promise.resolve();
208
266
  }
@@ -215,7 +273,11 @@ var MemoryRepository = class {
215
273
  }
216
274
  if (opts?.pinned === true) conditions.push("pinned = 1");
217
275
  const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
218
- return this.#db.db.prepare(`SELECT * FROM memories ${where} ORDER BY created_at DESC`).all(...params).map(rowToMemory);
276
+ const rows = this.#db.db.prepare(`SELECT * FROM memories ${where} ORDER BY created_at DESC`).all(...params);
277
+ if (rows.length === 0) return [];
278
+ const ids = rows.map((r) => r.id);
279
+ const projectMap = this.#projects.getProjectsForMemories(ids);
280
+ return rows.map((row) => rowToMemory(row, projectMap.get(row.id) ?? []));
219
281
  }
220
282
  stats() {
221
283
  const byType = Object.fromEntries(MEMORY_TYPE_VALUES.map((t) => [t, 0]));
@@ -235,13 +297,61 @@ var MemoryRepository = class {
235
297
  if (this.#db.db.prepare(`SELECT * FROM memories WHERE id = ?`).get(id) === void 0) throw new Error(`Memory not found: ${id}`);
236
298
  const now = (/* @__PURE__ */ new Date()).toISOString();
237
299
  this.#db.db.prepare(`UPDATE memories SET pinned = ?, updated_at = ? WHERE id = ?`).run(pinned ? 1 : 0, now, id);
238
- return rowToMemory(this.#db.db.prepare(`SELECT * FROM memories WHERE id = ?`).get(id));
300
+ return rowToMemory(this.#db.db.prepare(`SELECT * FROM memories WHERE id = ?`).get(id), this.#projects.getProjectsForMemories([id]).get(id) ?? []);
239
301
  }
240
302
  incrementAccessCount(id) {
241
303
  this.#db.db.prepare(`UPDATE memories SET access_count = access_count + 1 WHERE id = ?`).run(id);
242
304
  }
243
305
  };
244
306
  //#endregion
307
+ //#region src/project/repository.ts
308
+ var ProjectRepository = class {
309
+ #db;
310
+ constructor(db) {
311
+ this.#db = db;
312
+ }
313
+ upsertByHash(hash, name) {
314
+ const now = (/* @__PURE__ */ new Date()).toISOString();
315
+ const id = randomUUID();
316
+ this.#db.db.prepare(`INSERT OR IGNORE INTO projects (id, name, scope_hash, created_at, updated_at) VALUES (?, ?, ?, ?, ?)`).run(id, name, hash, now, now);
317
+ return rowToProject(this.#db.db.prepare(`SELECT * FROM projects WHERE scope_hash = ?`).get(hash));
318
+ }
319
+ rename(id, name) {
320
+ const now = (/* @__PURE__ */ new Date()).toISOString();
321
+ this.#db.db.prepare(`UPDATE projects SET name = ?, updated_at = ? WHERE id = ?`).run(name, now, id);
322
+ const row = this.#db.db.prepare(`SELECT * FROM projects WHERE id = ?`).get(id);
323
+ if (row === void 0) throw new Error(`Project not found: ${id}`);
324
+ return rowToProject(row);
325
+ }
326
+ list() {
327
+ return this.#db.db.prepare(`SELECT * FROM projects ORDER BY name ASC`).all().map(rowToProject);
328
+ }
329
+ getByHash(hash) {
330
+ const row = this.#db.db.prepare(`SELECT * FROM projects WHERE scope_hash = ?`).get(hash);
331
+ return row !== void 0 ? rowToProject(row) : void 0;
332
+ }
333
+ addAssociation(memoryId, projectId) {
334
+ this.#db.db.prepare(`INSERT OR IGNORE INTO memory_projects (memory_id, project_id) VALUES (?, ?)`).run(memoryId, projectId);
335
+ }
336
+ removeAssociation(memoryId, projectId) {
337
+ this.#db.db.prepare(`DELETE FROM memory_projects WHERE memory_id = ? AND project_id = ?`).run(memoryId, projectId);
338
+ }
339
+ getProjectsForMemories(memoryIds) {
340
+ if (memoryIds.length === 0) return /* @__PURE__ */ new Map();
341
+ const placeholders = memoryIds.map(() => "?").join(",");
342
+ const rows = this.#db.db.prepare(`SELECT p.*, mp.memory_id FROM projects p
343
+ JOIN memory_projects mp ON mp.project_id = p.id
344
+ WHERE mp.memory_id IN (${placeholders})`).all(...memoryIds);
345
+ const result = /* @__PURE__ */ new Map();
346
+ for (const row of rows) {
347
+ const list = result.get(row.memory_id) ?? [];
348
+ list.push(rowToProject(row));
349
+ result.set(row.memory_id, list);
350
+ }
351
+ return result;
352
+ }
353
+ };
354
+ //#endregion
245
355
  //#region src/query/engine.ts
246
356
  const TYPE_WEIGHTS = {
247
357
  correction: 1,
@@ -260,28 +370,32 @@ var QueryEngine = class {
260
370
  this.#repo = repo;
261
371
  }
262
372
  async query(options) {
263
- const { query, type, scope, limit = 10 } = options;
373
+ const { query, type, projectHash, limit = 10 } = options;
264
374
  const queryEmbedding = await this.#embedding.embed(query);
265
375
  const queryBlob = Buffer.from(queryEmbedding.buffer);
266
376
  const whereClauses = [];
267
377
  const params = [queryBlob];
378
+ let joinClause = "";
268
379
  if (type !== void 0) {
269
380
  whereClauses.push("m.type = ?");
270
381
  params.push(type);
271
382
  }
272
- if (scope !== void 0) {
273
- whereClauses.push("m.scope = ?");
274
- params.push(scope);
383
+ if (projectHash !== void 0) {
384
+ joinClause = "LEFT JOIN memory_projects mp ON mp.memory_id = m.id LEFT JOIN projects p ON p.id = mp.project_id";
385
+ whereClauses.push("p.scope_hash = ?");
386
+ params.push(projectHash);
275
387
  }
388
+ const whereSQL = whereClauses.length > 0 ? `WHERE ${whereClauses.join(" AND ")}` : "";
276
389
  const sql = `
277
390
  SELECT m.*, (1 - vec_distance_cosine(e.embedding, ?)) AS cosine_sim
278
391
  FROM memories m JOIN embeddings e ON e.rowid = m.rowid
279
- ${whereClauses.length > 0 ? `WHERE ${whereClauses.join(" AND ")}` : ""}
392
+ ${joinClause}
393
+ ${whereSQL}
280
394
  `;
281
395
  const rows = this.#db.db.prepare(sql).all(...params);
282
396
  const now = Date.now();
283
397
  const scored = rows.filter((row) => row.cosine_sim > 0).map((row) => {
284
- const memory = rowToMemory(row);
398
+ const memory = rowToMemory(row, []);
285
399
  const score = this.#computeScore(memory, now);
286
400
  return {
287
401
  ...memory,
@@ -307,6 +421,29 @@ const execFileAsync = promisify(execFile);
307
421
  function sha256Truncated(input) {
308
422
  return createHash("sha256").update(input).digest("hex").slice(0, 16);
309
423
  }
424
+ async function resolveProject() {
425
+ try {
426
+ const { stdout } = await execFileAsync("git", [
427
+ "remote",
428
+ "get-url",
429
+ "origin"
430
+ ]);
431
+ const url = stdout.trim();
432
+ if (url) {
433
+ const hash = sha256Truncated(url);
434
+ return {
435
+ hash,
436
+ name: url.split("/").pop()?.replace(/\.git$/, "") ?? hash.slice(0, 8)
437
+ };
438
+ }
439
+ } catch {}
440
+ const cwd = process.cwd();
441
+ const hash = sha256Truncated(cwd);
442
+ return {
443
+ hash,
444
+ name: cwd.split(/[/\\]/).filter(Boolean).pop() ?? hash.slice(0, 8)
445
+ };
446
+ }
310
447
  async function resolveScope() {
311
448
  try {
312
449
  const { stdout } = await execFileAsync("git", [
@@ -329,9 +466,14 @@ var SessionContextBuilder = class {
329
466
  constructor(db) {
330
467
  this.#db = db;
331
468
  }
332
- getSessionContext(projectScope) {
333
- const pinnedGlobal = this.#db.db.prepare("SELECT * FROM memories WHERE scope = 'global' AND pinned = 1").all().map(rowToMemory);
334
- const pinnedProject = this.#db.db.prepare("SELECT * FROM memories WHERE scope = ? AND pinned = 1").all(projectScope).map(rowToMemory);
469
+ getSessionContext(projectHash) {
470
+ const pinnedGlobal = this.#db.db.prepare(`SELECT * FROM memories
471
+ WHERE id NOT IN (SELECT memory_id FROM memory_projects)
472
+ AND pinned = 1`).all().map((row) => rowToMemory(row, []));
473
+ const pinnedProject = this.#db.db.prepare(`SELECT m.* FROM memories m
474
+ JOIN memory_projects mp ON mp.memory_id = m.id
475
+ JOIN projects p ON p.id = mp.project_id
476
+ WHERE p.scope_hash = ? AND m.pinned = 1`).all(projectHash).map((row) => rowToMemory(row, []));
335
477
  const typeCounts = this.#db.db.prepare("SELECT type, COUNT(*) as count FROM memories GROUP BY type").all();
336
478
  const stats = Object.fromEntries(MEMORY_TYPE_VALUES.map((t) => [t, 0]));
337
479
  for (const row of typeCounts) if (stats[row.type] !== void 0) stats[row.type] = row.count;
@@ -343,6 +485,6 @@ var SessionContextBuilder = class {
343
485
  }
344
486
  };
345
487
  //#endregion
346
- export { DatabaseError, DatabaseManager, EmbeddingService, MEMORY_TYPE_VALUES, MembankError, MemoryRepository, QueryEngine, SessionContextBuilder, listMemoryTypes, resolveScope, rowToMemory };
488
+ export { DatabaseError, DatabaseManager, EmbeddingService, MEMORY_TYPE_VALUES, MembankError, MemoryRepository, ProjectRepository, QueryEngine, SessionContextBuilder, listMemoryTypes, resolveProject, resolveScope, rowToMemory };
347
489
 
348
490
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["#db","#init","#initInMemory","#runMigrations","#db","#embedding","#db","#embedding","#repo","#computeScore","#db"],"sources":["../src/db/errors.ts","../src/db/manager.ts","../src/db/row-types.ts","../src/embedding/service.ts","../src/types.ts","../src/memory/repository.ts","../src/query/engine.ts","../src/scope/resolver.ts","../src/session/builder.ts"],"sourcesContent":["export class MembankError extends Error {\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = \"MembankError\";\n }\n}\n\nexport class DatabaseError extends MembankError {\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = \"DatabaseError\";\n }\n}\n","import { mkdirSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport BetterSqlite3 from \"better-sqlite3\";\nimport * as sqliteVec from \"sqlite-vec\";\nimport { DatabaseError } from \"./errors.js\";\n\nconst DEFAULT_DB_PATH = join(homedir(), \".membank\", \"memory.db\");\n\ntype VecLoader = (db: BetterSqlite3.Database) => void;\n\nconst MIGRATIONS: [number, string][] = [\n [\n 1,\n `\nCREATE TABLE IF NOT EXISTS memories (\n id TEXT PRIMARY KEY,\n content TEXT NOT NULL,\n type TEXT NOT NULL,\n tags TEXT NOT NULL DEFAULT '[]',\n scope TEXT NOT NULL,\n source TEXT,\n access_count INTEGER NOT NULL DEFAULT 0,\n pinned INTEGER NOT NULL DEFAULT 0,\n needs_review INTEGER NOT NULL DEFAULT 0,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL\n);\n\nCREATE VIRTUAL TABLE IF NOT EXISTS embeddings USING vec0(\n embedding FLOAT[384]\n);\n`,\n ],\n];\n\nexport class DatabaseManager {\n readonly #db: BetterSqlite3.Database;\n\n private constructor(db: BetterSqlite3.Database) {\n this.#db = db;\n }\n\n static open(dbPath?: string): DatabaseManager {\n const resolvedPath = dbPath ?? DEFAULT_DB_PATH;\n mkdirSync(dirname(resolvedPath), { recursive: true });\n const db = new BetterSqlite3(resolvedPath);\n return DatabaseManager.#init(db, sqliteVec.load);\n }\n\n static openInMemory(): DatabaseManager {\n return DatabaseManager.#initInMemory(sqliteVec.load);\n }\n\n /** For testing: inject a custom vec loader (e.g. a throwing stub). */\n static _openInMemoryWithLoader(loader: VecLoader): DatabaseManager {\n return DatabaseManager.#initInMemory(loader);\n }\n\n static #initInMemory(loader: VecLoader): DatabaseManager {\n const db = new BetterSqlite3(\":memory:\");\n return DatabaseManager.#init(db, loader);\n }\n\n static #init(db: BetterSqlite3.Database, loader: VecLoader): DatabaseManager {\n try {\n loader(db);\n } catch (err) {\n throw new DatabaseError(\"Failed to load sqlite-vec extension\", {\n cause: err,\n });\n }\n\n db.pragma(\"journal_mode = WAL\");\n\n const manager = new DatabaseManager(db);\n manager.#runMigrations();\n return manager;\n }\n\n #runMigrations(): void {\n // Bootstrap the meta table before reading schema_version from it\n this.#db.exec(`\n CREATE TABLE IF NOT EXISTS meta (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL\n );\n `);\n\n const row = this.#db\n .prepare<[], { value: string }>(\"SELECT value FROM meta WHERE key = 'schema_version'\")\n .get();\n\n const currentVersion = row ? Number.parseInt(row.value, 10) : 0;\n\n for (const [targetVersion, sql] of MIGRATIONS) {\n if (currentVersion < targetVersion) {\n this.#db.exec(sql);\n this.#db\n .prepare(\"INSERT OR REPLACE INTO meta (key, value) VALUES ('schema_version', ?)\")\n .run(String(targetVersion));\n }\n }\n }\n\n get db(): BetterSqlite3.Database {\n return this.#db;\n }\n\n close(): void {\n this.#db.close();\n }\n}\n","import type { Memory, MemoryType } from \"../types.js\";\n\nexport interface MemoryRow {\n id: string;\n content: string;\n type: string;\n tags: string;\n scope: string;\n source: string | null;\n access_count: number;\n pinned: number;\n needs_review: number;\n created_at: string;\n updated_at: string;\n}\n\nexport function rowToMemory(row: MemoryRow): Memory {\n return {\n id: row.id,\n content: row.content,\n type: row.type as MemoryType,\n tags: JSON.parse(row.tags) as string[],\n scope: row.scope,\n sourceHarness: row.source,\n accessCount: row.access_count,\n pinned: row.pinned !== 0,\n needsReview: row.needs_review !== 0,\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n };\n}\n","import { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { pipeline } from \"@huggingface/transformers\";\n\nexport type ProgressCallback = (progress: { status: string; progress?: number }) => void;\n\nexport class EmbeddingService {\n private readonly modelCachePath: string;\n private readonly onProgress: ProgressCallback | undefined;\n private pipelineInstance: Awaited<ReturnType<typeof pipeline>> | null = null;\n\n constructor(modelCachePath?: string, onProgress?: ProgressCallback) {\n this.modelCachePath = modelCachePath ?? join(homedir(), \".membank\", \"models\");\n this.onProgress = onProgress;\n }\n\n private async getPipeline(): Promise<Awaited<ReturnType<typeof pipeline>>> {\n if (this.pipelineInstance === null) {\n this.pipelineInstance = await pipeline(\"feature-extraction\", \"Xenova/bge-small-en-v1.5\", {\n cache_dir: this.modelCachePath,\n progress_callback: this.onProgress,\n });\n }\n return this.pipelineInstance;\n }\n\n async embed(text: string): Promise<Float32Array> {\n const pipe = await this.getPipeline();\n // Shape: [1, seq_len, 384]. Cast to any to bypass the non-unified pipeline union signature.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const output = await (\n pipe as (input: string, opts: Record<string, unknown>) => Promise<unknown>\n )(text, { pooling: \"mean\", normalize: true });\n\n // @huggingface/transformers Tensor has a .data property with the flat array\n const tensor = output as { data: Float32Array | number[] };\n const flat = tensor.data;\n\n return flat instanceof Float32Array ? flat : new Float32Array(flat);\n }\n}\n","export type MemoryType = \"correction\" | \"preference\" | \"decision\" | \"learning\" | \"fact\";\n\nexport const MEMORY_TYPE_VALUES = [\n \"correction\",\n \"preference\",\n \"decision\",\n \"learning\",\n \"fact\",\n] as const satisfies readonly MemoryType[];\n\nexport interface Memory {\n id: string;\n content: string;\n type: MemoryType;\n tags: string[];\n scope: string;\n sourceHarness: string | null;\n accessCount: number;\n pinned: boolean;\n needsReview: boolean;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface QueryOptions {\n query: string;\n type?: MemoryType;\n scope?: string;\n limit?: number;\n}\n\nexport interface SaveOptions {\n content: string;\n type: MemoryType;\n tags?: string[];\n scope?: string;\n sourceHarness?: string;\n}\n\nexport interface SessionContext {\n stats: Record<MemoryType, number>;\n pinnedGlobal: Memory[];\n pinnedProject: Memory[];\n}\n","import { randomUUID } from \"node:crypto\";\nimport type { DatabaseManager } from \"../db/manager.js\";\nimport type { MemoryRow } from \"../db/row-types.js\";\nimport { rowToMemory } from \"../db/row-types.js\";\nimport type { EmbeddingService } from \"../embedding/service.js\";\nimport type { Memory, MemoryType, SaveOptions } from \"../types.js\";\nimport { MEMORY_TYPE_VALUES } from \"../types.js\";\n\ninterface SimilarityRow extends MemoryRow {\n rowid: number;\n similarity: number;\n}\n\nexport class MemoryRepository {\n readonly #db: DatabaseManager;\n readonly #embedding: EmbeddingService;\n\n constructor(db: DatabaseManager, embeddingService: EmbeddingService) {\n this.#db = db;\n this.#embedding = embeddingService;\n }\n\n async save(options: SaveOptions): Promise<Memory> {\n const { content, type, tags = [], scope = \"global\", sourceHarness } = options;\n\n const embedding = await this.#embedding.embed(content);\n const embeddingBlob = Buffer.from(embedding.buffer);\n\n const top = this.#db.db\n .prepare<[Buffer, string, string], SimilarityRow>(\n `SELECT m.rowid, m.*, (1 - vec_distance_cosine(e.embedding, ?)) AS similarity\n FROM memories m JOIN embeddings e ON e.rowid = m.rowid\n WHERE m.type = ? AND m.scope = ?\n ORDER BY similarity DESC LIMIT 1`\n )\n .get(embeddingBlob, type, scope);\n\n const now = new Date().toISOString();\n\n if (top !== undefined && top.similarity > 0.92) {\n this.#db.db\n .prepare(`UPDATE memories SET content = ?, updated_at = ? WHERE id = ?`)\n .run(content, now, top.id);\n\n this.#db.db\n .prepare(`UPDATE embeddings SET embedding = ? WHERE rowid = ?`)\n .run(embeddingBlob, top.rowid);\n\n const updated = this.#db.db\n .prepare<[string], MemoryRow>(`SELECT * FROM memories WHERE id = ?`)\n .get(top.id);\n\n // updated is guaranteed to exist since we just updated it\n return rowToMemory(updated as MemoryRow);\n }\n\n if (top !== undefined && top.similarity >= 0.75) {\n this.#db.db.prepare(`UPDATE memories SET needs_review = 1 WHERE id = ?`).run(top.id);\n }\n\n const id = randomUUID();\n this.#db.db\n .prepare(\n `INSERT INTO memories (id, content, type, tags, scope, source, access_count, pinned, needs_review, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, 0, 0, 0, ?, ?)`\n )\n .run(id, content, type, JSON.stringify(tags), scope, sourceHarness ?? null, now, now);\n\n // sqlite-vec v0.1.9 does not accept parameterized rowid on INSERT into vec0 tables.\n // Use a SELECT subquery to copy the rowid from the memories row we just inserted.\n this.#db.db\n .prepare(\n `INSERT INTO embeddings (rowid, embedding) SELECT m.rowid, ? FROM memories m WHERE m.id = ?`\n )\n .run(embeddingBlob, id);\n\n const row = this.#db.db\n .prepare<[string], MemoryRow>(`SELECT * FROM memories WHERE id = ?`)\n .get(id) as MemoryRow;\n\n return rowToMemory(row);\n }\n\n async update(id: string, patch: { content?: string; tags?: string[] }): Promise<Memory> {\n const existing = this.#db.db\n .prepare<[string], MemoryRow & { rowid: number }>(\n `SELECT m.rowid, m.* FROM memories m WHERE m.id = ?`\n )\n .get(id);\n\n if (existing === undefined) {\n throw new Error(`Memory not found: ${id}`);\n }\n\n const now = new Date().toISOString();\n const sets: string[] = [\"updated_at = ?\"];\n const values: string[] = [now];\n\n if (patch.content !== undefined) {\n sets.push(\"content = ?\");\n values.push(patch.content);\n }\n\n if (patch.tags !== undefined) {\n sets.push(\"tags = ?\");\n values.push(JSON.stringify(patch.tags));\n }\n\n values.push(id);\n this.#db.db.prepare(`UPDATE memories SET ${sets.join(\", \")} WHERE id = ?`).run(...values);\n\n if (patch.content !== undefined) {\n const embedding = await this.#embedding.embed(patch.content);\n const embeddingBlob = Buffer.from(embedding.buffer);\n this.#db.db\n .prepare(`UPDATE embeddings SET embedding = ? WHERE rowid = ?`)\n .run(embeddingBlob, existing.rowid);\n }\n\n const updated = this.#db.db\n .prepare<[string], MemoryRow>(`SELECT * FROM memories WHERE id = ?`)\n .get(id) as MemoryRow;\n\n return rowToMemory(updated);\n }\n\n delete(id: string): Promise<void> {\n const row = this.#db.db\n .prepare<[string], { rowid: number }>(`SELECT rowid FROM memories WHERE id = ?`)\n .get(id);\n\n if (row !== undefined) {\n this.#db.db.prepare(`DELETE FROM embeddings WHERE rowid = ?`).run(row.rowid);\n }\n\n this.#db.db.prepare(`DELETE FROM memories WHERE id = ?`).run(id);\n\n return Promise.resolve();\n }\n\n list(opts?: { type?: MemoryType; pinned?: boolean }): Memory[] {\n const conditions: string[] = [];\n const params: (string | number)[] = [];\n\n if (opts?.type !== undefined) {\n conditions.push(\"type = ?\");\n params.push(opts.type);\n }\n\n if (opts?.pinned === true) {\n conditions.push(\"pinned = 1\");\n }\n\n const where = conditions.length > 0 ? `WHERE ${conditions.join(\" AND \")}` : \"\";\n const rows = this.#db.db\n .prepare<(string | number)[], MemoryRow>(\n `SELECT * FROM memories ${where} ORDER BY created_at DESC`\n )\n .all(...params);\n\n return rows.map(rowToMemory);\n }\n\n stats(): { byType: Record<MemoryType, number>; total: number; needsReview: number } {\n const byType = Object.fromEntries(MEMORY_TYPE_VALUES.map((t) => [t, 0])) as Record<\n MemoryType,\n number\n >;\n\n const typeRows = this.#db.db\n .prepare<[], { type: string; count: number }>(\n `SELECT type, COUNT(*) as count FROM memories GROUP BY type`\n )\n .all();\n\n for (const row of typeRows) {\n if (row.type in byType) {\n byType[row.type as MemoryType] = row.count;\n }\n }\n\n const totals = this.#db.db\n .prepare<[], { total: number; needsReview: number }>(\n `SELECT COUNT(*) as total, SUM(needs_review) as needsReview FROM memories`\n )\n .get() ?? { total: 0, needsReview: 0 };\n\n return {\n byType,\n total: totals.total,\n needsReview: totals.needsReview ?? 0,\n };\n }\n\n setPin(id: string, pinned: boolean): Memory {\n const existing = this.#db.db\n .prepare<[string], MemoryRow>(`SELECT * FROM memories WHERE id = ?`)\n .get(id);\n\n if (existing === undefined) {\n throw new Error(`Memory not found: ${id}`);\n }\n\n const now = new Date().toISOString();\n this.#db.db\n .prepare(`UPDATE memories SET pinned = ?, updated_at = ? WHERE id = ?`)\n .run(pinned ? 1 : 0, now, id);\n\n const updated = this.#db.db\n .prepare<[string], MemoryRow>(`SELECT * FROM memories WHERE id = ?`)\n .get(id) as MemoryRow;\n\n return rowToMemory(updated);\n }\n\n incrementAccessCount(id: string): void {\n this.#db.db.prepare(`UPDATE memories SET access_count = access_count + 1 WHERE id = ?`).run(id);\n }\n}\n","import type { DatabaseManager } from \"../db/manager.js\";\nimport type { MemoryRow } from \"../db/row-types.js\";\nimport { rowToMemory } from \"../db/row-types.js\";\nimport type { EmbeddingService } from \"../embedding/service.js\";\nimport type { MemoryRepository } from \"../memory/repository.js\";\nimport type { Memory, MemoryType, QueryOptions } from \"../types.js\";\n\ninterface QueryMemoryRow extends MemoryRow {\n cosine_sim: number;\n}\n\nconst TYPE_WEIGHTS = {\n correction: 1.0,\n preference: 0.8,\n decision: 0.6,\n learning: 0.4,\n fact: 0.2,\n} satisfies Record<MemoryType, number>;\n\nexport class QueryEngine {\n readonly #db: DatabaseManager;\n readonly #embedding: EmbeddingService;\n readonly #repo: MemoryRepository;\n\n constructor(db: DatabaseManager, embeddingService: EmbeddingService, repo: MemoryRepository) {\n this.#db = db;\n this.#embedding = embeddingService;\n this.#repo = repo;\n }\n\n async query(options: QueryOptions): Promise<Array<Memory & { score: number }>> {\n const { query, type, scope, limit = 10 } = options;\n\n const queryEmbedding = await this.#embedding.embed(query);\n const queryBlob = Buffer.from(queryEmbedding.buffer);\n\n const whereClauses: string[] = [];\n const params: unknown[] = [queryBlob];\n\n if (type !== undefined) {\n whereClauses.push(\"m.type = ?\");\n params.push(type);\n }\n\n if (scope !== undefined) {\n whereClauses.push(\"m.scope = ?\");\n params.push(scope);\n }\n\n const whereSQL = whereClauses.length > 0 ? `WHERE ${whereClauses.join(\" AND \")}` : \"\";\n\n const sql = `\n SELECT m.*, (1 - vec_distance_cosine(e.embedding, ?)) AS cosine_sim\n FROM memories m JOIN embeddings e ON e.rowid = m.rowid\n ${whereSQL}\n `;\n\n const rows = this.#db.db.prepare<unknown[], QueryMemoryRow>(sql).all(...params);\n\n const now = Date.now();\n\n const scored = rows\n .filter((row) => row.cosine_sim > 0)\n .map((row) => {\n const memory = rowToMemory(row);\n const score = this.#computeScore(memory, now);\n return { ...memory, score };\n });\n\n scored.sort((a, b) => b.score - a.score);\n\n const results = scored.slice(0, limit);\n\n for (const result of results) {\n this.#repo.incrementAccessCount(result.id);\n }\n\n return results;\n }\n\n #computeScore(memory: Memory, now: number): number {\n const typeWeight = TYPE_WEIGHTS[memory.type];\n const accessCountNorm = memory.accessCount / (memory.accessCount + 10);\n const daysSinceUpdate = (now - new Date(memory.updatedAt).getTime()) / 86400000;\n const recencyNorm = 1 / (1 + daysSinceUpdate);\n const pinned = memory.pinned ? 1.0 : 0.0;\n\n return typeWeight * 0.4 + accessCountNorm * 0.3 + recencyNorm * 0.2 + pinned * 0.1;\n }\n}\n","import { execFile } from \"node:child_process\";\nimport { createHash } from \"node:crypto\";\nimport { promisify } from \"node:util\";\n\nconst execFileAsync = promisify(execFile);\n\nfunction sha256Truncated(input: string): string {\n return createHash(\"sha256\").update(input).digest(\"hex\").slice(0, 16);\n}\n\nexport async function resolveScope(): Promise<string> {\n try {\n const { stdout } = await execFileAsync(\"git\", [\"remote\", \"get-url\", \"origin\"]);\n const url = stdout.trim();\n if (url) {\n return sha256Truncated(url);\n }\n } catch {\n // git not available, not a repo, or no remote — fall through to cwd fallback\n }\n\n return sha256Truncated(process.cwd());\n}\n","import type { DatabaseManager } from \"../db/manager.js\";\nimport type { MemoryRow } from \"../db/row-types.js\";\nimport { rowToMemory } from \"../db/row-types.js\";\nimport type { MemoryType, SessionContext } from \"../types.js\";\nimport { MEMORY_TYPE_VALUES } from \"../types.js\";\n\ninterface TypeCountRow {\n type: string;\n count: number;\n}\n\nexport function listMemoryTypes(): MemoryType[] {\n return [...MEMORY_TYPE_VALUES];\n}\n\nexport class SessionContextBuilder {\n readonly #db: DatabaseManager;\n\n constructor(db: DatabaseManager) {\n this.#db = db;\n }\n\n getSessionContext(projectScope: string): SessionContext {\n const pinnedGlobal = this.#db.db\n .prepare<[], MemoryRow>(\"SELECT * FROM memories WHERE scope = 'global' AND pinned = 1\")\n .all()\n .map(rowToMemory);\n\n const pinnedProject = this.#db.db\n .prepare<[string], MemoryRow>(\"SELECT * FROM memories WHERE scope = ? AND pinned = 1\")\n .all(projectScope)\n .map(rowToMemory);\n\n const typeCounts = this.#db.db\n .prepare<[], TypeCountRow>(\"SELECT type, COUNT(*) as count FROM memories GROUP BY type\")\n .all();\n\n const stats = Object.fromEntries(MEMORY_TYPE_VALUES.map((t) => [t, 0])) as Record<\n MemoryType,\n number\n >;\n for (const row of typeCounts) {\n if (stats[row.type as MemoryType] !== undefined) {\n stats[row.type as MemoryType] = row.count;\n }\n }\n\n return { stats, pinnedGlobal, pinnedProject };\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["#db","#init","#initInMemory","#runMigrations","#db","#embedding","#projects","#db","#db","#embedding","#repo","#computeScore","#db"],"sources":["../src/db/errors.ts","../src/db/manager.ts","../src/db/row-types.ts","../src/embedding/service.ts","../src/types.ts","../src/memory/repository.ts","../src/project/repository.ts","../src/query/engine.ts","../src/scope/resolver.ts","../src/session/builder.ts"],"sourcesContent":["export class MembankError extends Error {\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = \"MembankError\";\n }\n}\n\nexport class DatabaseError extends MembankError {\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = \"DatabaseError\";\n }\n}\n","import { mkdirSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport BetterSqlite3 from \"better-sqlite3\";\nimport * as sqliteVec from \"sqlite-vec\";\nimport { DatabaseError } from \"./errors.js\";\n\nconst DEFAULT_DB_PATH = join(homedir(), \".membank\", \"memory.db\");\n\ntype VecLoader = (db: BetterSqlite3.Database) => void;\n\nconst MIGRATIONS: [number, string][] = [\n [\n 1,\n `\nCREATE TABLE IF NOT EXISTS memories (\n id TEXT PRIMARY KEY,\n content TEXT NOT NULL,\n type TEXT NOT NULL,\n tags TEXT NOT NULL DEFAULT '[]',\n scope TEXT NOT NULL,\n source TEXT,\n access_count INTEGER NOT NULL DEFAULT 0,\n pinned INTEGER NOT NULL DEFAULT 0,\n needs_review INTEGER NOT NULL DEFAULT 0,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL\n);\n\nCREATE VIRTUAL TABLE IF NOT EXISTS embeddings USING vec0(\n embedding FLOAT[384]\n);\n`,\n ],\n [\n 2,\n `\nCREATE TABLE IF NOT EXISTS projects (\n id TEXT PRIMARY KEY,\n name TEXT NOT NULL,\n scope_hash TEXT NOT NULL UNIQUE,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL\n);\n\nCREATE TABLE IF NOT EXISTS memory_projects (\n memory_id TEXT NOT NULL REFERENCES memories(id) ON DELETE CASCADE,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n PRIMARY KEY (memory_id, project_id)\n);\n\nINSERT OR IGNORE INTO projects (id, name, scope_hash, created_at, updated_at)\nSELECT\n lower(hex(randomblob(16))),\n 'project-' || substr(scope, 1, 8),\n scope,\n datetime('now'),\n datetime('now')\nFROM memories\nWHERE scope != 'global'\nGROUP BY scope;\n\nINSERT OR IGNORE INTO memory_projects (memory_id, project_id)\nSELECT m.id, p.id\nFROM memories m\nJOIN projects p ON p.scope_hash = m.scope\nWHERE m.scope != 'global';\n\nALTER TABLE memories DROP COLUMN scope;\n`,\n ],\n];\n\nexport class DatabaseManager {\n readonly #db: BetterSqlite3.Database;\n\n private constructor(db: BetterSqlite3.Database) {\n this.#db = db;\n }\n\n static open(dbPath?: string): DatabaseManager {\n const resolvedPath = dbPath ?? DEFAULT_DB_PATH;\n mkdirSync(dirname(resolvedPath), { recursive: true });\n const db = new BetterSqlite3(resolvedPath);\n return DatabaseManager.#init(db, sqliteVec.load);\n }\n\n static openInMemory(): DatabaseManager {\n return DatabaseManager.#initInMemory(sqliteVec.load);\n }\n\n /** For testing: inject a custom vec loader (e.g. a throwing stub). */\n static _openInMemoryWithLoader(loader: VecLoader): DatabaseManager {\n return DatabaseManager.#initInMemory(loader);\n }\n\n static #initInMemory(loader: VecLoader): DatabaseManager {\n const db = new BetterSqlite3(\":memory:\");\n return DatabaseManager.#init(db, loader);\n }\n\n static #init(db: BetterSqlite3.Database, loader: VecLoader): DatabaseManager {\n try {\n loader(db);\n } catch (err) {\n throw new DatabaseError(\"Failed to load sqlite-vec extension\", {\n cause: err,\n });\n }\n\n db.pragma(\"journal_mode = WAL\");\n db.pragma(\"foreign_keys = ON\");\n\n const manager = new DatabaseManager(db);\n manager.#runMigrations();\n return manager;\n }\n\n #runMigrations(): void {\n // Bootstrap the meta table before reading schema_version from it\n this.#db.exec(`\n CREATE TABLE IF NOT EXISTS meta (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL\n );\n `);\n\n const row = this.#db\n .prepare<[], { value: string }>(\"SELECT value FROM meta WHERE key = 'schema_version'\")\n .get();\n\n const currentVersion = row ? Number.parseInt(row.value, 10) : 0;\n\n for (const [targetVersion, sql] of MIGRATIONS) {\n if (currentVersion < targetVersion) {\n this.#db.exec(sql);\n this.#db\n .prepare(\"INSERT OR REPLACE INTO meta (key, value) VALUES ('schema_version', ?)\")\n .run(String(targetVersion));\n }\n }\n }\n\n get db(): BetterSqlite3.Database {\n return this.#db;\n }\n\n close(): void {\n this.#db.close();\n }\n}\n","import type { Memory, MemoryType, Project } from \"../types.js\";\n\nexport interface MemoryRow {\n id: string;\n content: string;\n type: string;\n tags: string;\n source: string | null;\n access_count: number;\n pinned: number;\n needs_review: number;\n created_at: string;\n updated_at: string;\n}\n\nexport interface ProjectRow {\n id: string;\n name: string;\n scope_hash: string;\n created_at: string;\n updated_at: string;\n}\n\nexport function rowToMemory(row: MemoryRow, projects: Project[]): Memory {\n return {\n id: row.id,\n content: row.content,\n type: row.type as MemoryType,\n tags: JSON.parse(row.tags) as string[],\n projects,\n sourceHarness: row.source,\n accessCount: row.access_count,\n pinned: row.pinned !== 0,\n needsReview: row.needs_review !== 0,\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n };\n}\n\nexport function rowToProject(row: ProjectRow): Project {\n return {\n id: row.id,\n name: row.name,\n scopeHash: row.scope_hash,\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n };\n}\n","import { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { pipeline } from \"@huggingface/transformers\";\n\nexport type ProgressCallback = (progress: { status: string; progress?: number }) => void;\n\nexport class EmbeddingService {\n private readonly modelCachePath: string;\n private readonly onProgress: ProgressCallback | undefined;\n private pipelineInstance: Awaited<ReturnType<typeof pipeline>> | null = null;\n\n constructor(modelCachePath?: string, onProgress?: ProgressCallback) {\n this.modelCachePath = modelCachePath ?? join(homedir(), \".membank\", \"models\");\n this.onProgress = onProgress;\n }\n\n private async getPipeline(): Promise<Awaited<ReturnType<typeof pipeline>>> {\n if (this.pipelineInstance === null) {\n this.pipelineInstance = await pipeline(\"feature-extraction\", \"Xenova/bge-small-en-v1.5\", {\n cache_dir: this.modelCachePath,\n progress_callback: this.onProgress,\n });\n }\n return this.pipelineInstance;\n }\n\n async embed(text: string): Promise<Float32Array> {\n const pipe = await this.getPipeline();\n // Shape: [1, seq_len, 384]. Cast to any to bypass the non-unified pipeline union signature.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const output = await (\n pipe as (input: string, opts: Record<string, unknown>) => Promise<unknown>\n )(text, { pooling: \"mean\", normalize: true });\n\n // @huggingface/transformers Tensor has a .data property with the flat array\n const tensor = output as { data: Float32Array | number[] };\n const flat = tensor.data;\n\n return flat instanceof Float32Array ? flat : new Float32Array(flat);\n }\n}\n","export type MemoryType = \"correction\" | \"preference\" | \"decision\" | \"learning\" | \"fact\";\n\nexport const MEMORY_TYPE_VALUES = [\n \"correction\",\n \"preference\",\n \"decision\",\n \"learning\",\n \"fact\",\n] as const satisfies readonly MemoryType[];\n\nexport interface Project {\n id: string;\n name: string;\n scopeHash: string;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface Memory {\n id: string;\n content: string;\n type: MemoryType;\n tags: string[];\n projects: Project[];\n sourceHarness: string | null;\n accessCount: number;\n pinned: boolean;\n needsReview: boolean;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface QueryOptions {\n query: string;\n type?: MemoryType;\n projectHash?: string;\n limit?: number;\n}\n\nexport interface SaveOptions {\n content: string;\n type: MemoryType;\n tags?: string[];\n projectHash?: string;\n sourceHarness?: string;\n}\n\nexport interface SessionContext {\n stats: Record<MemoryType, number>;\n pinnedGlobal: Memory[];\n pinnedProject: Memory[];\n}\n","import { randomUUID } from \"node:crypto\";\nimport type { DatabaseManager } from \"../db/manager.js\";\nimport type { MemoryRow } from \"../db/row-types.js\";\nimport { rowToMemory } from \"../db/row-types.js\";\nimport type { EmbeddingService } from \"../embedding/service.js\";\nimport type { ProjectRepository } from \"../project/repository.js\";\nimport type { Memory, MemoryType, SaveOptions } from \"../types.js\";\nimport { MEMORY_TYPE_VALUES } from \"../types.js\";\n\ninterface SimilarityRow extends MemoryRow {\n rowid: number;\n similarity: number;\n}\n\nexport class MemoryRepository {\n readonly #db: DatabaseManager;\n readonly #embedding: EmbeddingService;\n readonly #projects: ProjectRepository;\n\n constructor(\n db: DatabaseManager,\n embeddingService: EmbeddingService,\n projects: ProjectRepository\n ) {\n this.#db = db;\n this.#embedding = embeddingService;\n this.#projects = projects;\n }\n\n async save(options: SaveOptions): Promise<Memory> {\n const { content, type, tags = [], projectHash, sourceHarness } = options;\n\n const embedding = await this.#embedding.embed(content);\n const embeddingBlob = Buffer.from(embedding.buffer);\n\n // Dedup: find similar memory in same context\n let top: SimilarityRow | undefined;\n if (projectHash !== undefined) {\n top = this.#db.db\n .prepare<[Buffer, string, string], SimilarityRow>(\n `SELECT m.rowid, m.*, (1 - vec_distance_cosine(e.embedding, ?)) AS similarity\n FROM memories m JOIN embeddings e ON e.rowid = m.rowid\n JOIN memory_projects mp ON mp.memory_id = m.id\n JOIN projects p ON p.id = mp.project_id\n WHERE m.type = ? AND p.scope_hash = ?\n ORDER BY similarity DESC LIMIT 1`\n )\n .get(embeddingBlob, type, projectHash);\n } else {\n top = this.#db.db\n .prepare<[Buffer, string], SimilarityRow>(\n `SELECT m.rowid, m.*, (1 - vec_distance_cosine(e.embedding, ?)) AS similarity\n FROM memories m JOIN embeddings e ON e.rowid = m.rowid\n WHERE m.type = ?\n AND m.id NOT IN (SELECT memory_id FROM memory_projects)\n ORDER BY similarity DESC LIMIT 1`\n )\n .get(embeddingBlob, type);\n }\n\n const now = new Date().toISOString();\n\n if (top !== undefined && top.similarity > 0.92) {\n this.#db.db\n .prepare(`UPDATE memories SET content = ?, updated_at = ? WHERE id = ?`)\n .run(content, now, top.id);\n this.#db.db\n .prepare(`UPDATE embeddings SET embedding = ? WHERE rowid = ?`)\n .run(embeddingBlob, top.rowid);\n\n const updated = this.#db.db\n .prepare<[string], MemoryRow>(`SELECT * FROM memories WHERE id = ?`)\n .get(top.id) as MemoryRow;\n\n const projectMap = this.#projects.getProjectsForMemories([top.id]);\n return rowToMemory(updated, projectMap.get(top.id) ?? []);\n }\n\n if (top !== undefined && top.similarity >= 0.75) {\n this.#db.db.prepare(`UPDATE memories SET needs_review = 1 WHERE id = ?`).run(top.id);\n }\n\n const id = randomUUID();\n this.#db.db\n .prepare(\n `INSERT INTO memories (id, content, type, tags, source, access_count, pinned, needs_review, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, 0, 0, 0, ?, ?)`\n )\n .run(id, content, type, JSON.stringify(tags), sourceHarness ?? null, now, now);\n\n this.#db.db\n .prepare(\n `INSERT INTO embeddings (rowid, embedding) SELECT m.rowid, ? FROM memories m WHERE m.id = ?`\n )\n .run(embeddingBlob, id);\n\n if (projectHash !== undefined) {\n // resolveProject name not available here; caller should have upserted already\n // if project not yet upserted (e.g. CLI path), upsert with hash as placeholder name\n const project = this.#projects.upsertByHash(\n projectHash,\n `project-${projectHash.slice(0, 8)}`\n );\n this.#projects.addAssociation(id, project.id);\n }\n\n const row = this.#db.db\n .prepare<[string], MemoryRow>(`SELECT * FROM memories WHERE id = ?`)\n .get(id) as MemoryRow;\n\n const projectMap = this.#projects.getProjectsForMemories([id]);\n return rowToMemory(row, projectMap.get(id) ?? []);\n }\n\n async update(id: string, patch: { content?: string; tags?: string[] }): Promise<Memory> {\n const existing = this.#db.db\n .prepare<[string], MemoryRow & { rowid: number }>(\n `SELECT m.rowid, m.* FROM memories m WHERE m.id = ?`\n )\n .get(id);\n\n if (existing === undefined) {\n throw new Error(`Memory not found: ${id}`);\n }\n\n const now = new Date().toISOString();\n const sets: string[] = [\"updated_at = ?\"];\n const values: string[] = [now];\n\n if (patch.content !== undefined) {\n sets.push(\"content = ?\");\n values.push(patch.content);\n }\n\n if (patch.tags !== undefined) {\n sets.push(\"tags = ?\");\n values.push(JSON.stringify(patch.tags));\n }\n\n values.push(id);\n this.#db.db.prepare(`UPDATE memories SET ${sets.join(\", \")} WHERE id = ?`).run(...values);\n\n if (patch.content !== undefined) {\n const embedding = await this.#embedding.embed(patch.content);\n const embeddingBlob = Buffer.from(embedding.buffer);\n this.#db.db\n .prepare(`UPDATE embeddings SET embedding = ? WHERE rowid = ?`)\n .run(embeddingBlob, existing.rowid);\n }\n\n const updated = this.#db.db\n .prepare<[string], MemoryRow>(`SELECT * FROM memories WHERE id = ?`)\n .get(id) as MemoryRow;\n\n const projectMap = this.#projects.getProjectsForMemories([id]);\n return rowToMemory(updated, projectMap.get(id) ?? []);\n }\n\n delete(id: string): Promise<void> {\n const row = this.#db.db\n .prepare<[string], { rowid: number }>(`SELECT rowid FROM memories WHERE id = ?`)\n .get(id);\n\n if (row !== undefined) {\n this.#db.db.prepare(`DELETE FROM embeddings WHERE rowid = ?`).run(row.rowid);\n }\n\n this.#db.db.prepare(`DELETE FROM memory_projects WHERE memory_id = ?`).run(id);\n this.#db.db.prepare(`DELETE FROM memories WHERE id = ?`).run(id);\n\n return Promise.resolve();\n }\n\n list(opts?: { type?: MemoryType; pinned?: boolean }): Memory[] {\n const conditions: string[] = [];\n const params: (string | number)[] = [];\n\n if (opts?.type !== undefined) {\n conditions.push(\"type = ?\");\n params.push(opts.type);\n }\n\n if (opts?.pinned === true) {\n conditions.push(\"pinned = 1\");\n }\n\n const where = conditions.length > 0 ? `WHERE ${conditions.join(\" AND \")}` : \"\";\n const rows = this.#db.db\n .prepare<(string | number)[], MemoryRow>(\n `SELECT * FROM memories ${where} ORDER BY created_at DESC`\n )\n .all(...params);\n\n if (rows.length === 0) return [];\n\n const ids = rows.map((r) => r.id);\n const projectMap = this.#projects.getProjectsForMemories(ids);\n return rows.map((row) => rowToMemory(row, projectMap.get(row.id) ?? []));\n }\n\n stats(): { byType: Record<MemoryType, number>; total: number; needsReview: number } {\n const byType = Object.fromEntries(MEMORY_TYPE_VALUES.map((t) => [t, 0])) as Record<\n MemoryType,\n number\n >;\n\n const typeRows = this.#db.db\n .prepare<[], { type: string; count: number }>(\n `SELECT type, COUNT(*) as count FROM memories GROUP BY type`\n )\n .all();\n\n for (const row of typeRows) {\n if (row.type in byType) {\n byType[row.type as MemoryType] = row.count;\n }\n }\n\n const totals = this.#db.db\n .prepare<[], { total: number; needsReview: number }>(\n `SELECT COUNT(*) as total, SUM(needs_review) as needsReview FROM memories`\n )\n .get() ?? { total: 0, needsReview: 0 };\n\n return {\n byType,\n total: totals.total,\n needsReview: totals.needsReview ?? 0,\n };\n }\n\n setPin(id: string, pinned: boolean): Memory {\n const existing = this.#db.db\n .prepare<[string], MemoryRow>(`SELECT * FROM memories WHERE id = ?`)\n .get(id);\n\n if (existing === undefined) {\n throw new Error(`Memory not found: ${id}`);\n }\n\n const now = new Date().toISOString();\n this.#db.db\n .prepare(`UPDATE memories SET pinned = ?, updated_at = ? WHERE id = ?`)\n .run(pinned ? 1 : 0, now, id);\n\n const updated = this.#db.db\n .prepare<[string], MemoryRow>(`SELECT * FROM memories WHERE id = ?`)\n .get(id) as MemoryRow;\n\n const projectMap = this.#projects.getProjectsForMemories([id]);\n return rowToMemory(updated, projectMap.get(id) ?? []);\n }\n\n incrementAccessCount(id: string): void {\n this.#db.db.prepare(`UPDATE memories SET access_count = access_count + 1 WHERE id = ?`).run(id);\n }\n}\n","import { randomUUID } from \"node:crypto\";\nimport type { DatabaseManager } from \"../db/manager.js\";\nimport type { ProjectRow } from \"../db/row-types.js\";\nimport { rowToProject } from \"../db/row-types.js\";\nimport type { Project } from \"../types.js\";\n\ninterface ProjectMemoryRow extends ProjectRow {\n memory_id: string;\n}\n\nexport class ProjectRepository {\n readonly #db: DatabaseManager;\n\n constructor(db: DatabaseManager) {\n this.#db = db;\n }\n\n upsertByHash(hash: string, name: string): Project {\n const now = new Date().toISOString();\n const id = randomUUID();\n this.#db.db\n .prepare(\n `INSERT OR IGNORE INTO projects (id, name, scope_hash, created_at, updated_at) VALUES (?, ?, ?, ?, ?)`\n )\n .run(id, name, hash, now, now);\n\n const row = this.#db.db\n .prepare<[string], ProjectRow>(`SELECT * FROM projects WHERE scope_hash = ?`)\n .get(hash) as ProjectRow;\n\n return rowToProject(row);\n }\n\n rename(id: string, name: string): Project {\n const now = new Date().toISOString();\n this.#db.db\n .prepare(`UPDATE projects SET name = ?, updated_at = ? WHERE id = ?`)\n .run(name, now, id);\n\n const row = this.#db.db\n .prepare<[string], ProjectRow>(`SELECT * FROM projects WHERE id = ?`)\n .get(id);\n\n if (row === undefined) throw new Error(`Project not found: ${id}`);\n return rowToProject(row);\n }\n\n list(): Project[] {\n return this.#db.db\n .prepare<[], ProjectRow>(`SELECT * FROM projects ORDER BY name ASC`)\n .all()\n .map(rowToProject);\n }\n\n getByHash(hash: string): Project | undefined {\n const row = this.#db.db\n .prepare<[string], ProjectRow>(`SELECT * FROM projects WHERE scope_hash = ?`)\n .get(hash);\n return row !== undefined ? rowToProject(row) : undefined;\n }\n\n addAssociation(memoryId: string, projectId: string): void {\n this.#db.db\n .prepare(`INSERT OR IGNORE INTO memory_projects (memory_id, project_id) VALUES (?, ?)`)\n .run(memoryId, projectId);\n }\n\n removeAssociation(memoryId: string, projectId: string): void {\n this.#db.db\n .prepare(`DELETE FROM memory_projects WHERE memory_id = ? AND project_id = ?`)\n .run(memoryId, projectId);\n }\n\n getProjectsForMemories(memoryIds: string[]): Map<string, Project[]> {\n if (memoryIds.length === 0) return new Map();\n const placeholders = memoryIds.map(() => \"?\").join(\",\");\n const rows = this.#db.db\n .prepare<string[], ProjectMemoryRow>(\n `SELECT p.*, mp.memory_id FROM projects p\n JOIN memory_projects mp ON mp.project_id = p.id\n WHERE mp.memory_id IN (${placeholders})`\n )\n .all(...memoryIds);\n\n const result = new Map<string, Project[]>();\n for (const row of rows) {\n const list = result.get(row.memory_id) ?? [];\n list.push(rowToProject(row));\n result.set(row.memory_id, list);\n }\n return result;\n }\n}\n","import type { DatabaseManager } from \"../db/manager.js\";\nimport type { MemoryRow } from \"../db/row-types.js\";\nimport { rowToMemory } from \"../db/row-types.js\";\nimport type { EmbeddingService } from \"../embedding/service.js\";\nimport type { MemoryRepository } from \"../memory/repository.js\";\nimport type { Memory, MemoryType, QueryOptions } from \"../types.js\";\n\ninterface QueryMemoryRow extends MemoryRow {\n cosine_sim: number;\n}\n\nconst TYPE_WEIGHTS = {\n correction: 1.0,\n preference: 0.8,\n decision: 0.6,\n learning: 0.4,\n fact: 0.2,\n} satisfies Record<MemoryType, number>;\n\nexport class QueryEngine {\n readonly #db: DatabaseManager;\n readonly #embedding: EmbeddingService;\n readonly #repo: MemoryRepository;\n\n constructor(db: DatabaseManager, embeddingService: EmbeddingService, repo: MemoryRepository) {\n this.#db = db;\n this.#embedding = embeddingService;\n this.#repo = repo;\n }\n\n async query(options: QueryOptions): Promise<Array<Memory & { score: number }>> {\n const { query, type, projectHash, limit = 10 } = options;\n\n const queryEmbedding = await this.#embedding.embed(query);\n const queryBlob = Buffer.from(queryEmbedding.buffer);\n\n const whereClauses: string[] = [];\n const params: unknown[] = [queryBlob];\n let joinClause = \"\";\n\n if (type !== undefined) {\n whereClauses.push(\"m.type = ?\");\n params.push(type);\n }\n\n if (projectHash !== undefined) {\n joinClause =\n \"LEFT JOIN memory_projects mp ON mp.memory_id = m.id LEFT JOIN projects p ON p.id = mp.project_id\";\n whereClauses.push(\"p.scope_hash = ?\");\n params.push(projectHash);\n }\n\n const whereSQL = whereClauses.length > 0 ? `WHERE ${whereClauses.join(\" AND \")}` : \"\";\n\n const sql = `\n SELECT m.*, (1 - vec_distance_cosine(e.embedding, ?)) AS cosine_sim\n FROM memories m JOIN embeddings e ON e.rowid = m.rowid\n ${joinClause}\n ${whereSQL}\n `;\n\n const rows = this.#db.db.prepare<unknown[], QueryMemoryRow>(sql).all(...params);\n\n const now = Date.now();\n\n const scored = rows\n .filter((row) => row.cosine_sim > 0)\n .map((row) => {\n const memory = rowToMemory(row, []);\n const score = this.#computeScore(memory, now);\n return { ...memory, score };\n });\n\n scored.sort((a, b) => b.score - a.score);\n\n const results = scored.slice(0, limit);\n\n for (const result of results) {\n this.#repo.incrementAccessCount(result.id);\n }\n\n return results;\n }\n\n #computeScore(memory: Memory, now: number): number {\n const typeWeight = TYPE_WEIGHTS[memory.type];\n const accessCountNorm = memory.accessCount / (memory.accessCount + 10);\n const daysSinceUpdate = (now - new Date(memory.updatedAt).getTime()) / 86400000;\n const recencyNorm = 1 / (1 + daysSinceUpdate);\n const pinned = memory.pinned ? 1.0 : 0.0;\n\n return typeWeight * 0.4 + accessCountNorm * 0.3 + recencyNorm * 0.2 + pinned * 0.1;\n }\n}\n","import { execFile } from \"node:child_process\";\nimport { createHash } from \"node:crypto\";\nimport { promisify } from \"node:util\";\n\nconst execFileAsync = promisify(execFile);\n\nfunction sha256Truncated(input: string): string {\n return createHash(\"sha256\").update(input).digest(\"hex\").slice(0, 16);\n}\n\nexport async function resolveProject(): Promise<{ hash: string; name: string }> {\n try {\n const { stdout } = await execFileAsync(\"git\", [\"remote\", \"get-url\", \"origin\"]);\n const url = stdout.trim();\n if (url) {\n const hash = sha256Truncated(url);\n // parse last path segment, strip .git suffix\n const name =\n url\n .split(\"/\")\n .pop()\n ?.replace(/\\.git$/, \"\") ?? hash.slice(0, 8);\n return { hash, name };\n }\n } catch {\n // fall through\n }\n\n const cwd = process.cwd();\n const hash = sha256Truncated(cwd);\n const name = cwd.split(/[/\\\\]/).filter(Boolean).pop() ?? hash.slice(0, 8);\n return { hash, name };\n}\n\nexport async function resolveScope(): Promise<string> {\n try {\n const { stdout } = await execFileAsync(\"git\", [\"remote\", \"get-url\", \"origin\"]);\n const url = stdout.trim();\n if (url) {\n return sha256Truncated(url);\n }\n } catch {\n // git not available, not a repo, or no remote — fall through to cwd fallback\n }\n\n return sha256Truncated(process.cwd());\n}\n","import type { DatabaseManager } from \"../db/manager.js\";\nimport type { MemoryRow } from \"../db/row-types.js\";\nimport { rowToMemory } from \"../db/row-types.js\";\nimport type { MemoryType, SessionContext } from \"../types.js\";\nimport { MEMORY_TYPE_VALUES } from \"../types.js\";\n\ninterface TypeCountRow {\n type: string;\n count: number;\n}\n\nexport function listMemoryTypes(): MemoryType[] {\n return [...MEMORY_TYPE_VALUES];\n}\n\nexport class SessionContextBuilder {\n readonly #db: DatabaseManager;\n\n constructor(db: DatabaseManager) {\n this.#db = db;\n }\n\n getSessionContext(projectHash: string): SessionContext {\n const pinnedGlobal = this.#db.db\n .prepare<[], MemoryRow>(\n `SELECT * FROM memories\n WHERE id NOT IN (SELECT memory_id FROM memory_projects)\n AND pinned = 1`\n )\n .all()\n .map((row) => rowToMemory(row, []));\n\n const pinnedProject = this.#db.db\n .prepare<[string], MemoryRow>(\n `SELECT m.* FROM memories m\n JOIN memory_projects mp ON mp.memory_id = m.id\n JOIN projects p ON p.id = mp.project_id\n WHERE p.scope_hash = ? AND m.pinned = 1`\n )\n .all(projectHash)\n .map((row) => rowToMemory(row, []));\n\n const typeCounts = this.#db.db\n .prepare<[], TypeCountRow>(\"SELECT type, COUNT(*) as count FROM memories GROUP BY type\")\n .all();\n\n const stats = Object.fromEntries(MEMORY_TYPE_VALUES.map((t) => [t, 0])) as Record<\n MemoryType,\n number\n >;\n for (const row of typeCounts) {\n if (stats[row.type as MemoryType] !== undefined) {\n stats[row.type as MemoryType] = row.count;\n }\n }\n\n return { stats, pinnedGlobal, pinnedProject };\n }\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@membank/core",
3
- "version": "0.5.1",
3
+ "version": "0.6.0",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",