@membank/core 0.8.0 → 0.9.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/README.md CHANGED
@@ -28,11 +28,12 @@ Default location can be overridden via `DatabaseManager.open(customPath)`.
28
28
  ### Initialize
29
29
 
30
30
  ```typescript
31
- import { DatabaseManager, EmbeddingService, MemoryRepository, QueryEngine } from '@membank/core'
31
+ import { DatabaseManager, EmbeddingService, MemoryRepository, ProjectRepository, QueryEngine } from '@membank/core'
32
32
 
33
33
  const db = DatabaseManager.open()
34
34
  const embedding = new EmbeddingService()
35
- const repo = new MemoryRepository(db, embedding)
35
+ const projects = new ProjectRepository(db)
36
+ const repo = new MemoryRepository(db, embedding, projects)
36
37
  const engine = new QueryEngine(db, embedding, repo)
37
38
  ```
38
39
 
@@ -64,8 +65,8 @@ for (const { content, score } of results) {
64
65
  ```typescript
65
66
  import { SessionContextBuilder } from '@membank/core'
66
67
 
67
- const builder = new SessionContextBuilder(db, repo)
68
- const { stats, pinnedGlobal, pinnedProject } = await builder.getSessionContext(projectScope)
68
+ const builder = new SessionContextBuilder(db)
69
+ const { stats, pinnedGlobal, pinnedProject } = builder.getSessionContext(projectHash)
69
70
  ```
70
71
 
71
72
  ## Memory types
@@ -104,9 +105,10 @@ score = 0.40 × type_weight
104
105
  Each memory is tagged with a scope derived from the project's git remote URL (SHA256, first 16 chars). Falls back to a hash of the current working directory if git is unavailable. Global memories use `"global"` as scope.
105
106
 
106
107
  ```typescript
107
- import { resolveScope } from '@membank/core'
108
+ import { resolveProject, resolveScope } from '@membank/core'
108
109
 
109
- const scope = await resolveScope()
110
+ const { hash, name } = await resolveProject() // preferred: returns hash + repo name
111
+ const scopeHash = await resolveScope() // returns hash string only
110
112
  ```
111
113
 
112
114
  ## Embeddings
@@ -149,6 +151,15 @@ query(options: QueryOptions): Promise<Array<Memory & { score: number }>>
149
151
  ### `SessionContextBuilder`
150
152
 
151
153
  ```typescript
152
- getSessionContext(projectScope: string): Promise<SessionContext>
154
+ new SessionContextBuilder(db: DatabaseManager)
155
+ getSessionContext(projectHash: string, synthesis?: string): SessionContext
156
+ ```
157
+
158
+ ### `listMemoryTypes`
159
+
160
+ Standalone function (not a class method):
161
+
162
+ ```typescript
163
+ import { listMemoryTypes } from '@membank/core'
153
164
  listMemoryTypes(): MemoryType[]
154
165
  ```
package/dist/index.cjs CHANGED
@@ -33,6 +33,20 @@ let _huggingface_transformers = require("@huggingface/transformers");
33
33
  let node_crypto = require("node:crypto");
34
34
  let node_child_process = require("node:child_process");
35
35
  let node_util = require("node:util");
36
+ //#region src/config/loader.ts
37
+ function loadConfig() {
38
+ const configPath = (0, node_path.join)((0, node_os.homedir)(), ".membank", "config.json");
39
+ try {
40
+ const raw = (0, node_fs.readFileSync)(configPath, "utf8");
41
+ return JSON.parse(raw);
42
+ } catch {
43
+ return null;
44
+ }
45
+ }
46
+ function isSynthesisEnabled() {
47
+ return loadConfig()?.synthesis?.enabled === true;
48
+ }
49
+ //#endregion
36
50
  //#region src/db/errors.ts
37
51
  var MembankError = class extends Error {
38
52
  constructor(message, options) {
@@ -119,6 +133,27 @@ CREATE INDEX IF NOT EXISTS idx_review_events_memory_open
119
133
  ON memory_review_events(memory_id) WHERE resolved_at IS NULL;
120
134
 
121
135
  ALTER TABLE memories DROP COLUMN needs_review;
136
+ `],
137
+ [4, `
138
+ CREATE TABLE IF NOT EXISTS syntheses (
139
+ id TEXT PRIMARY KEY,
140
+ scope TEXT NOT NULL,
141
+ content TEXT NOT NULL,
142
+ source_memory_hash TEXT NOT NULL,
143
+ synthesized_at TEXT NOT NULL,
144
+ expires_at TEXT NOT NULL,
145
+ in_flight_since TEXT,
146
+ created_at TEXT NOT NULL,
147
+ updated_at TEXT NOT NULL,
148
+ UNIQUE(scope),
149
+ CHECK(expires_at > synthesized_at)
150
+ );
151
+
152
+ CREATE INDEX IF NOT EXISTS idx_syntheses_expires_at
153
+ ON syntheses(expires_at);
154
+
155
+ CREATE INDEX IF NOT EXISTS idx_syntheses_scope_inflight
156
+ ON syntheses(scope) WHERE in_flight_since IS NOT NULL;
122
157
  `]
123
158
  ];
124
159
  var DatabaseManager = class DatabaseManager {
@@ -247,12 +282,25 @@ const SaveOptionsSchema = zod.z.object({
247
282
  });
248
283
  const MemoryPatchSchema = zod.z.object({
249
284
  content: zod.z.string().min(1).optional(),
250
- tags: zod.z.array(zod.z.string()).optional()
285
+ tags: zod.z.array(zod.z.string()).optional(),
286
+ type: MemoryTypeSchema.optional()
287
+ });
288
+ const SynthesisSchema = zod.z.object({
289
+ id: zod.z.string(),
290
+ scope: zod.z.string(),
291
+ content: zod.z.string(),
292
+ sourceMemoryHash: zod.z.string(),
293
+ synthesizedAt: zod.z.string(),
294
+ expiresAt: zod.z.string(),
295
+ inFlightSince: zod.z.string().nullable(),
296
+ createdAt: zod.z.string(),
297
+ updatedAt: zod.z.string()
251
298
  });
252
299
  const SessionContextSchema = zod.z.object({
253
300
  stats: zod.z.record(MemoryTypeSchema, zod.z.number()),
254
301
  pinnedGlobal: zod.z.array(MemorySchema),
255
- pinnedProject: zod.z.array(MemorySchema)
302
+ pinnedProject: zod.z.array(MemorySchema),
303
+ synthesis: zod.z.string().optional()
256
304
  });
257
305
  const MemoryRowSchema = zod.z.object({
258
306
  id: zod.z.string(),
@@ -338,6 +386,7 @@ var EmbeddingService = class {
338
386
  };
339
387
  //#endregion
340
388
  //#region src/memory/repository.ts
389
+ const PIN_BUDGET_THRESHOLD = 8e3;
341
390
  var MemoryRepository = class {
342
391
  #db;
343
392
  #embedding;
@@ -386,7 +435,7 @@ var MemoryRepository = class {
386
435
  return rowToMemory(MemoryRowSchema.parse(this.#db.db.prepare(`SELECT * FROM memories WHERE id = ?`).get(id)), this.#projects.getProjectsForMemories([id]).get(id) ?? [], []);
387
436
  }
388
437
  async update(id, patch) {
389
- const { content, tags } = MemoryPatchSchema.parse(patch);
438
+ const { content, tags, type } = MemoryPatchSchema.parse(patch);
390
439
  const existing = this.#db.db.prepare(`SELECT m.rowid, m.* FROM memories m WHERE m.id = ?`).get(id);
391
440
  if (existing === void 0) throw new Error(`Memory not found: ${id}`);
392
441
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -400,6 +449,10 @@ var MemoryRepository = class {
400
449
  sets.push("tags = ?");
401
450
  values.push(JSON.stringify(tags));
402
451
  }
452
+ if (type !== void 0) {
453
+ sets.push("type = ?");
454
+ values.push(type);
455
+ }
403
456
  values.push(id);
404
457
  this.#db.db.prepare(`UPDATE memories SET ${sets.join(", ")} WHERE id = ?`).run(...values);
405
458
  if (content !== void 0) {
@@ -472,6 +525,9 @@ var MemoryRepository = class {
472
525
  }
473
526
  return map;
474
527
  }
528
+ getPinnedCharCount() {
529
+ return (this.#db.db.prepare(`SELECT COALESCE(SUM(LENGTH(content)), 0) as total FROM memories WHERE pinned = 1`).get() ?? { total: 0 }).total;
530
+ }
475
531
  stats() {
476
532
  const byType = Object.fromEntries(MEMORY_TYPE_VALUES.map((t) => [t, 0]));
477
533
  const typeRows = this.#db.db.prepare(`SELECT type, COUNT(*) as count FROM memories GROUP BY type`).all();
@@ -479,12 +535,17 @@ var MemoryRepository = class {
479
535
  const parsed = MemoryTypeSchema.safeParse(row.type);
480
536
  if (parsed.success) byType[parsed.data] = row.count;
481
537
  }
482
- const totals = this.#db.db.prepare(`SELECT COUNT(*) as total FROM memories`).get() ?? { total: 0 };
538
+ const aggregates = this.#db.db.prepare(`SELECT COUNT(*) as total, SUM(pinned) as pinned FROM memories`).get() ?? {
539
+ total: 0,
540
+ pinned: 0
541
+ };
483
542
  const reviewRow = this.#db.db.prepare(`SELECT COUNT(DISTINCT memory_id) as needsReview FROM memory_review_events WHERE resolved_at IS NULL`).get() ?? { needsReview: 0 };
484
543
  return {
485
544
  byType,
486
- total: totals.total,
487
- needsReview: reviewRow.needsReview
545
+ total: aggregates.total,
546
+ pinned: aggregates.pinned ?? 0,
547
+ needsReview: reviewRow.needsReview,
548
+ pinBudgetChars: this.getPinnedCharCount()
488
549
  };
489
550
  }
490
551
  setPin(id, pinned) {
@@ -658,7 +719,7 @@ var QueryEngine = class {
658
719
  const now = Date.now();
659
720
  const scored = rows.filter((row) => row.cosine_sim > 0).map((row) => {
660
721
  const memory = rowToMemory(row, []);
661
- const score = this.#computeScore(memory, now);
722
+ const score = this.#computeScore(memory, row.cosine_sim, now);
662
723
  return {
663
724
  ...memory,
664
725
  score
@@ -669,12 +730,12 @@ var QueryEngine = class {
669
730
  for (const result of results) this.#repo.incrementAccessCount(result.id);
670
731
  return results;
671
732
  }
672
- #computeScore(memory, now) {
733
+ #computeScore(memory, cosine_sim, now) {
673
734
  const typeWeight = TYPE_WEIGHTS[memory.type];
674
735
  const accessCountNorm = memory.accessCount / (memory.accessCount + 10);
675
736
  const recencyNorm = 1 / (1 + (now - new Date(memory.updatedAt).getTime()) / 864e5);
676
737
  const pinned = memory.pinned ? 1 : 0;
677
- return typeWeight * .4 + accessCountNorm * .3 + recencyNorm * .2 + pinned * .1;
738
+ return cosine_sim * .4 + typeWeight * .25 + accessCountNorm * .2 + recencyNorm * .1 + pinned * .05;
678
739
  }
679
740
  };
680
741
  //#endregion
@@ -687,28 +748,139 @@ var SessionContextBuilder = class {
687
748
  constructor(db) {
688
749
  this.#db = db;
689
750
  }
690
- getSessionContext(projectHash) {
691
- const pinnedGlobal = this.#db.db.prepare(`SELECT * FROM memories
692
- WHERE id NOT IN (SELECT memory_id FROM memory_projects)
693
- AND pinned = 1`).all().map((row) => rowToMemory(row, []));
694
- const pinnedProject = this.#db.db.prepare(`SELECT m.* FROM memories m
695
- JOIN memory_projects mp ON mp.memory_id = m.id
696
- JOIN projects p ON p.id = mp.project_id
697
- WHERE p.scope_hash = ? AND m.pinned = 1`).all(projectHash).map((row) => rowToMemory(row, []));
751
+ getSessionContext(projectHash, synthesis) {
698
752
  const typeCounts = this.#db.db.prepare("SELECT type, COUNT(*) as count FROM memories GROUP BY type").all();
699
753
  const stats = Object.fromEntries(MEMORY_TYPE_VALUES.map((t) => [t, 0]));
700
754
  for (const row of typeCounts) {
701
755
  const parsed = MemoryTypeSchema.safeParse(row.type);
702
756
  if (parsed.success) stats[parsed.data] = row.count;
703
757
  }
758
+ if (synthesis !== void 0 && synthesis.length > 0) return {
759
+ stats,
760
+ pinnedGlobal: [],
761
+ pinnedProject: [],
762
+ synthesis
763
+ };
704
764
  return {
705
765
  stats,
706
- pinnedGlobal,
707
- pinnedProject
766
+ pinnedGlobal: this.#db.db.prepare(`SELECT * FROM memories
767
+ WHERE id NOT IN (SELECT memory_id FROM memory_projects)
768
+ AND pinned = 1`).all().map((row) => rowToMemory(row, [])),
769
+ pinnedProject: this.#db.db.prepare(`SELECT m.* FROM memories m
770
+ JOIN memory_projects mp ON mp.memory_id = m.id
771
+ JOIN projects p ON p.id = mp.project_id
772
+ WHERE p.scope_hash = ? AND m.pinned = 1`).all(projectHash).map((row) => rowToMemory(row, []))
708
773
  };
709
774
  }
710
775
  };
711
776
  //#endregion
777
+ //#region src/synthesis/repository.ts
778
+ function rowToSynthesis(row) {
779
+ return SynthesisSchema.parse({
780
+ id: row.id,
781
+ scope: row.scope,
782
+ content: row.content,
783
+ sourceMemoryHash: row.source_memory_hash,
784
+ synthesizedAt: row.synthesized_at,
785
+ expiresAt: row.expires_at,
786
+ inFlightSince: row.in_flight_since,
787
+ createdAt: row.created_at,
788
+ updatedAt: row.updated_at
789
+ });
790
+ }
791
+ const STALENESS_DAYS = 30;
792
+ var SynthesisRepository = class {
793
+ #db;
794
+ constructor(db) {
795
+ this.#db = db;
796
+ }
797
+ saveSynthesis(scope, content, sourceHash) {
798
+ const now = (/* @__PURE__ */ new Date()).toISOString();
799
+ const expiresAt = new Date(Date.now() + STALENESS_DAYS * 24 * 60 * 60 * 1e3).toISOString();
800
+ if (this.#db.db.prepare("SELECT id FROM syntheses WHERE scope = ?").get(scope) !== void 0) this.#db.db.prepare(`UPDATE syntheses
801
+ SET content = ?, source_memory_hash = ?, synthesized_at = ?, expires_at = ?,
802
+ in_flight_since = NULL, updated_at = ?
803
+ WHERE scope = ?`).run(content, sourceHash, now, expiresAt, now, scope);
804
+ else {
805
+ const id = (0, node_crypto.randomUUID)();
806
+ this.#db.db.prepare(`INSERT INTO syntheses
807
+ (id, scope, content, source_memory_hash, synthesized_at, expires_at,
808
+ in_flight_since, created_at, updated_at)
809
+ VALUES (?, ?, ?, ?, ?, ?, NULL, ?, ?)`).run(id, scope, content, sourceHash, now, expiresAt, now, now);
810
+ }
811
+ const row = this.#db.db.prepare("SELECT * FROM syntheses WHERE scope = ?").get(scope);
812
+ if (row === void 0) throw new Error(`Failed to save synthesis for scope: ${scope}`);
813
+ return rowToSynthesis(row);
814
+ }
815
+ getSynthesis(scope) {
816
+ const row = this.#db.db.prepare("SELECT * FROM syntheses WHERE scope = ?").get(scope);
817
+ return row !== void 0 ? rowToSynthesis(row) : void 0;
818
+ }
819
+ markInFlight(scope) {
820
+ const now = (/* @__PURE__ */ new Date()).toISOString();
821
+ if (this.#db.db.prepare("SELECT id FROM syntheses WHERE scope = ?").get(scope) !== void 0) this.#db.db.prepare("UPDATE syntheses SET in_flight_since = ?, updated_at = ? WHERE scope = ?").run(now, now, scope);
822
+ else {
823
+ const id = (0, node_crypto.randomUUID)();
824
+ const placeholder = "pending";
825
+ const future = new Date(Date.now() + STALENESS_DAYS * 24 * 60 * 60 * 1e3).toISOString();
826
+ this.#db.db.prepare(`INSERT INTO syntheses
827
+ (id, scope, content, source_memory_hash, synthesized_at, expires_at,
828
+ in_flight_since, created_at, updated_at)
829
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(id, scope, placeholder, "", now, future, now, now, now);
830
+ }
831
+ }
832
+ clearInFlight(scope) {
833
+ const now = (/* @__PURE__ */ new Date()).toISOString();
834
+ this.#db.db.prepare("UPDATE syntheses SET in_flight_since = NULL, updated_at = ? WHERE scope = ?").run(now, scope);
835
+ }
836
+ computeSourceMemoryHash(scope) {
837
+ let contents;
838
+ if (scope === "global") contents = this.#db.db.prepare(`SELECT content FROM memories
839
+ WHERE id NOT IN (SELECT memory_id FROM memory_projects)
840
+ ORDER BY id`).all();
841
+ else contents = this.#db.db.prepare(`SELECT m.content FROM memories m
842
+ JOIN memory_projects mp ON mp.memory_id = m.id
843
+ JOIN projects p ON p.id = mp.project_id
844
+ WHERE p.scope_hash = ?
845
+ ORDER BY m.id`).all(scope);
846
+ return (0, node_crypto.createHash)("sha256").update(JSON.stringify(contents.map((r) => r.content))).digest("hex");
847
+ }
848
+ getExpiredOrDirtyScopes() {
849
+ const allScopes = this.getAllActiveScopes();
850
+ const now = (/* @__PURE__ */ new Date()).toISOString();
851
+ const results = [];
852
+ for (const scope of allScopes) {
853
+ const row = this.#db.db.prepare("SELECT * FROM syntheses WHERE scope = ?").get(scope);
854
+ if (row === void 0 || row.content === "pending" && row.source_memory_hash === "") {
855
+ results.push({
856
+ scope,
857
+ reason: "missing"
858
+ });
859
+ continue;
860
+ }
861
+ if (row.expires_at <= now) {
862
+ results.push({
863
+ scope,
864
+ reason: "expired"
865
+ });
866
+ continue;
867
+ }
868
+ if (this.computeSourceMemoryHash(scope) !== row.source_memory_hash) results.push({
869
+ scope,
870
+ reason: "dirty"
871
+ });
872
+ }
873
+ return results;
874
+ }
875
+ getAllActiveScopes() {
876
+ return ["global", ...this.#db.db.prepare("SELECT DISTINCT scope_hash FROM projects").all().map((r) => r.scope_hash)];
877
+ }
878
+ expireStale() {
879
+ const now = (/* @__PURE__ */ new Date()).toISOString();
880
+ this.#db.db.prepare("DELETE FROM syntheses WHERE expires_at < ?").run(now);
881
+ }
882
+ };
883
+ //#endregion
712
884
  exports.DatabaseError = DatabaseError;
713
885
  exports.DatabaseManager = DatabaseManager;
714
886
  exports.EmbeddingService = EmbeddingService;
@@ -720,6 +892,7 @@ exports.MemoryRepository = MemoryRepository;
720
892
  exports.MemoryRowSchema = MemoryRowSchema;
721
893
  exports.MemorySchema = MemorySchema;
722
894
  exports.MemoryTypeSchema = MemoryTypeSchema;
895
+ exports.PIN_BUDGET_THRESHOLD = PIN_BUDGET_THRESHOLD;
723
896
  exports.ProjectRepository = ProjectRepository;
724
897
  exports.ProjectRowSchema = ProjectRowSchema;
725
898
  exports.ProjectSchema = ProjectSchema;
@@ -731,7 +904,10 @@ exports.ReviewReasonSchema = ReviewReasonSchema;
731
904
  exports.SaveOptionsSchema = SaveOptionsSchema;
732
905
  exports.SessionContextBuilder = SessionContextBuilder;
733
906
  exports.SessionContextSchema = SessionContextSchema;
907
+ exports.SynthesisRepository = SynthesisRepository;
908
+ exports.SynthesisSchema = SynthesisSchema;
734
909
  exports.TagsJsonSchema = TagsJsonSchema;
910
+ exports.isSynthesisEnabled = isSynthesisEnabled;
735
911
  exports.listMemoryTypes = listMemoryTypes;
736
912
  exports.resolveProject = resolveProject;
737
913
  exports.resolveScope = resolveScope;
package/dist/index.d.cts CHANGED
@@ -1,6 +1,9 @@
1
1
  import BetterSqlite3 from "better-sqlite3";
2
2
  import { z } from "zod";
3
3
 
4
+ //#region src/config/loader.d.ts
5
+ declare function isSynthesisEnabled(): boolean;
6
+ //#endregion
4
7
  //#region src/db/errors.d.ts
5
8
  declare class MembankError extends Error {
6
9
  constructor(message: string, options?: ErrorOptions);
@@ -142,8 +145,27 @@ type SaveOptions = z.infer<typeof SaveOptionsSchema>;
142
145
  declare const MemoryPatchSchema: z.ZodObject<{
143
146
  content: z.ZodOptional<z.ZodString>;
144
147
  tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
148
+ type: z.ZodOptional<z.ZodEnum<{
149
+ correction: "correction";
150
+ preference: "preference";
151
+ decision: "decision";
152
+ learning: "learning";
153
+ fact: "fact";
154
+ }>>;
145
155
  }, z.core.$strip>;
146
156
  type MemoryPatch = z.infer<typeof MemoryPatchSchema>;
157
+ declare const SynthesisSchema: z.ZodObject<{
158
+ id: z.ZodString;
159
+ scope: z.ZodString;
160
+ content: z.ZodString;
161
+ sourceMemoryHash: z.ZodString;
162
+ synthesizedAt: z.ZodString;
163
+ expiresAt: z.ZodString;
164
+ inFlightSince: z.ZodNullable<z.ZodString>;
165
+ createdAt: z.ZodString;
166
+ updatedAt: z.ZodString;
167
+ }, z.core.$strip>;
168
+ type Synthesis = z.infer<typeof SynthesisSchema>;
147
169
  declare const SessionContextSchema: z.ZodObject<{
148
170
  stats: z.ZodRecord<z.ZodEnum<{
149
171
  correction: "correction";
@@ -224,6 +246,7 @@ declare const SessionContextSchema: z.ZodObject<{
224
246
  createdAt: z.ZodString;
225
247
  updatedAt: z.ZodString;
226
248
  }, z.core.$strip>>;
249
+ synthesis: z.ZodOptional<z.ZodString>;
227
250
  }, z.core.$strip>;
228
251
  type SessionContext = z.infer<typeof SessionContextSchema>;
229
252
  declare const MemoryRowSchema: z.ZodObject<{
@@ -280,6 +303,7 @@ declare class ProjectRepository {
280
303
  }
281
304
  //#endregion
282
305
  //#region src/memory/repository.d.ts
306
+ declare const PIN_BUDGET_THRESHOLD = 8000;
283
307
  declare class MemoryRepository {
284
308
  #private;
285
309
  constructor(db: DatabaseManager, embeddingService: EmbeddingService, projects: ProjectRepository);
@@ -295,10 +319,13 @@ declare class MemoryRepository {
295
319
  unresolvedOnly?: boolean;
296
320
  }): ReviewEvent[];
297
321
  resolveReviewEvents(memoryId: string): void;
322
+ getPinnedCharCount(): number;
298
323
  stats(): {
299
324
  byType: Record<MemoryType, number>;
300
325
  total: number;
326
+ pinned: number;
301
327
  needsReview: number;
328
+ pinBudgetChars: number;
302
329
  };
303
330
  setPin(id: string, pinned: boolean): Memory;
304
331
  incrementAccessCount(id: string): void;
@@ -339,8 +366,25 @@ declare function listMemoryTypes(): MemoryType[];
339
366
  declare class SessionContextBuilder {
340
367
  #private;
341
368
  constructor(db: DatabaseManager);
342
- getSessionContext(projectHash: string): SessionContext;
369
+ getSessionContext(projectHash: string, synthesis?: string): SessionContext;
370
+ }
371
+ //#endregion
372
+ //#region src/synthesis/repository.d.ts
373
+ declare class SynthesisRepository {
374
+ #private;
375
+ constructor(db: DatabaseManager);
376
+ saveSynthesis(scope: string, content: string, sourceHash: string): Synthesis;
377
+ getSynthesis(scope: string): Synthesis | undefined;
378
+ markInFlight(scope: string): void;
379
+ clearInFlight(scope: string): void;
380
+ computeSourceMemoryHash(scope: string): string;
381
+ getExpiredOrDirtyScopes(): {
382
+ scope: string;
383
+ reason: "expired" | "dirty" | "missing";
384
+ }[];
385
+ getAllActiveScopes(): string[];
386
+ expireStale(): void;
343
387
  }
344
388
  //#endregion
345
- export { DatabaseError, DatabaseManager, EmbeddingService, MEMORY_TYPE_VALUES, MIGRATIONS, MembankError, Memory, MemoryPatch, MemoryPatchSchema, MemoryRepository, MemoryRow, MemoryRowSchema, MemorySchema, MemoryType, MemoryTypeSchema, MigrationMeta, ProgressCallback, Project, ProjectRepository, ProjectRow, ProjectRowSchema, ProjectSchema, QueryEngine, QueryOptions, QueryOptionsSchema, ReviewEvent, ReviewEventRow, ReviewEventRowSchema, ReviewEventSchema, ReviewReason, ReviewReasonSchema, SaveOptions, SaveOptionsSchema, ScopeToProjectsResult, SessionContext, SessionContextBuilder, SessionContextSchema, TagsJsonSchema, listMemoryTypes, resolveProject, resolveScope, rowToMemory, rowToProject, runScopeToProjectsMigration };
389
+ export { DatabaseError, DatabaseManager, EmbeddingService, MEMORY_TYPE_VALUES, MIGRATIONS, MembankError, Memory, MemoryPatch, MemoryPatchSchema, MemoryRepository, MemoryRow, MemoryRowSchema, MemorySchema, MemoryType, MemoryTypeSchema, MigrationMeta, PIN_BUDGET_THRESHOLD, ProgressCallback, Project, ProjectRepository, ProjectRow, ProjectRowSchema, ProjectSchema, QueryEngine, QueryOptions, QueryOptionsSchema, ReviewEvent, ReviewEventRow, ReviewEventRowSchema, ReviewEventSchema, ReviewReason, ReviewReasonSchema, SaveOptions, SaveOptionsSchema, ScopeToProjectsResult, SessionContext, SessionContextBuilder, SessionContextSchema, Synthesis, SynthesisRepository, SynthesisSchema, TagsJsonSchema, isSynthesisEnabled, listMemoryTypes, resolveProject, resolveScope, rowToMemory, rowToProject, runScopeToProjectsMigration };
346
390
  //# 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/schemas.ts","../src/db/row-types.ts","../src/embedding/service.ts","../src/project/repository.ts","../src/memory/repository.ts","../src/migrations/index.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,cAoFvB,eAAA;EAAA;UAGJ,WAAA,CAAA;EAAA,OAIA,IAAA,CAAK,MAAA,YAAkB,eAAA;EAAA,OAOvB,YAAA,CAAA,GAAgB,eAAA;ED3Gc;EAAA,OCgH9B,uBAAA,CAAwB,MAAA,EAAQ,SAAA,GAAY,eAAA;EAAA,IAmD/C,EAAA,CAAA,GAAM,aAAA,CAAc,QAAA;EAIxB,KAAA,CAAA;AAAA;;;cCrKW,kBAAA;AAAA,cAQA,gBAAA,EAAgB,CAAA,CAAA,OAAA;;;;;;;KACjB,UAAA,GAAa,CAAA,CAAE,KAAA,QAAa,gBAAA;AAAA,cAE3B,cAAA,EAAc,CAAA,CAAA,QAAA,CAAA,CAAA,CAAA,SAAA;AAAA,cAEd,aAAA,EAAa,CAAA,CAAA,SAAA;;;;;;;KAOd,OAAA,GAAU,CAAA,CAAE,KAAA,QAAa,aAAA;AAAA,cAExB,kBAAA,EAAkB,CAAA,CAAA,OAAA;;;KACnB,YAAA,GAAe,CAAA,CAAE,KAAA,QAAa,kBAAA;AAAA,cAE7B,iBAAA,EAAiB,CAAA,CAAA,SAAA;;;;;;;;;;;;KAUlB,WAAA,GAAc,CAAA,CAAE,KAAA,QAAa,iBAAA;AAAA,cAE5B,oBAAA,EAAoB,CAAA,CAAA,SAAA;;;;;;;;;;;;KAUrB,cAAA,GAAiB,CAAA,CAAE,KAAA,QAAa,oBAAA;AAAA,cAE/B,YAAA,EAAY,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAab,MAAA,GAAS,CAAA,CAAE,KAAA,QAAa,YAAA;AAAA,cAEvB,kBAAA,EAAkB,CAAA,CAAA,SAAA;;;;;;;;;;;;;KAOnB,YAAA,GAAe,CAAA,CAAE,KAAA,QAAa,kBAAA;AAAA,cAE7B,iBAAA,EAAiB,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;KAOlB,WAAA,GAAc,CAAA,CAAE,KAAA,QAAa,iBAAA;AAAA,cAE5B,iBAAA,EAAiB,CAAA,CAAA,SAAA;;;;KAIlB,WAAA,GAAc,CAAA,CAAE,KAAA,QAAa,iBAAA;AAAA,cAE5B,oBAAA,EAAoB,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAKrB,cAAA,GAAiB,CAAA,CAAE,KAAA,QAAa,oBAAA;AAAA,cAE/B,eAAA,EAAe,CAAA,CAAA,SAAA;;;;;;;;;;;KAWhB,SAAA,GAAY,CAAA,CAAE,KAAA,QAAa,eAAA;AAAA,cAE1B,gBAAA,EAAgB,CAAA,CAAA,SAAA;;;;;;;KAOjB,UAAA,GAAa,CAAA,CAAE,KAAA,QAAa,gBAAA;;;iBC3GxB,WAAA,CACd,GAAA,EAAK,SAAA,EACL,QAAA,EAAU,OAAA,IACV,YAAA,GAAc,WAAA,KACb,MAAA;AAAA,iBA8Ba,YAAA,CAAa,GAAA,EAAK,UAAA,GAAa,OAAA;;;KCxCnC,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;EAkB1C,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,aAAA,CAAc,SAAA;EASd,sBAAA,CAAuB,SAAA,aAAsB,GAAA,SAAY,OAAA;AAAA;;;cCxD9C,gBAAA;EAAA;cAMT,EAAA,EAAI,eAAA,EACJ,gBAAA,EAAkB,gBAAA,EAClB,QAAA,EAAU,iBAAA;EAON,IAAA,CAAK,OAAA,EAAS,WAAA,GAAc,OAAA,CAAQ,MAAA;EA8FpC,MAAA,CAAO,EAAA,UAAY,KAAA,EAAO,WAAA,GAAc,OAAA,CAAQ,MAAA;EA+CtD,MAAA,CAAO,EAAA,WAAa,OAAA;EAepB,IAAA,CAAK,IAAA;IAAS,IAAA,GAAO,UAAA;IAAY,MAAA;EAAA,IAAqB,MAAA;EA8BtD,WAAA,CAAA,GAAe,MAAA;EAsBf,gBAAA,CAAiB,QAAA,UAAkB,IAAA;IAAS,cAAA;EAAA,IAA6B,WAAA;EAezE,mBAAA,CAAoB,QAAA;EAmCpB,KAAA,CAAA;IAAW,MAAA,EAAQ,MAAA,CAAO,UAAA;IAAqB,KAAA;IAAe,WAAA;EAAA;EAoC9D,MAAA,CAAO,EAAA,UAAY,MAAA,YAAkB,MAAA;EAuBrC,oBAAA,CAAqB,EAAA;AAAA;;;UCrWN,aAAA;EACf,IAAA;EACA,WAAA;AAAA;AAAA,UAGe,qBAAA;EACf,SAAA;EACA,OAAA;EACA,OAAA;EACA,WAAA;AAAA;AAAA,cAGW,UAAA,EAAY,aAAA;AAAA,iBAQH,2BAAA,CACpB,QAAA,EAAU,iBAAA,GACT,OAAA,CAAQ,qBAAA;;;cCNE,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;;;iBCxBtB,eAAA,CAAA,GAAmB,UAAA;AAAA,cAItB,qBAAA;EAAA;cAGC,EAAA,EAAI,eAAA;EAIhB,iBAAA,CAAkB,WAAA,WAAsB,cAAA;AAAA"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/config/loader.ts","../src/db/errors.ts","../src/db/manager.ts","../src/schemas.ts","../src/db/row-types.ts","../src/embedding/service.ts","../src/project/repository.ts","../src/memory/repository.ts","../src/migrations/index.ts","../src/query/engine.ts","../src/scope/resolver.ts","../src/session/builder.ts","../src/synthesis/repository.ts"],"mappings":"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"}
package/dist/index.d.mts CHANGED
@@ -1,6 +1,9 @@
1
1
  import BetterSqlite3 from "better-sqlite3";
2
2
  import { z } from "zod";
3
3
 
4
+ //#region src/config/loader.d.ts
5
+ declare function isSynthesisEnabled(): boolean;
6
+ //#endregion
4
7
  //#region src/db/errors.d.ts
5
8
  declare class MembankError extends Error {
6
9
  constructor(message: string, options?: ErrorOptions);
@@ -142,8 +145,27 @@ type SaveOptions = z.infer<typeof SaveOptionsSchema>;
142
145
  declare const MemoryPatchSchema: z.ZodObject<{
143
146
  content: z.ZodOptional<z.ZodString>;
144
147
  tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
148
+ type: z.ZodOptional<z.ZodEnum<{
149
+ correction: "correction";
150
+ preference: "preference";
151
+ decision: "decision";
152
+ learning: "learning";
153
+ fact: "fact";
154
+ }>>;
145
155
  }, z.core.$strip>;
146
156
  type MemoryPatch = z.infer<typeof MemoryPatchSchema>;
157
+ declare const SynthesisSchema: z.ZodObject<{
158
+ id: z.ZodString;
159
+ scope: z.ZodString;
160
+ content: z.ZodString;
161
+ sourceMemoryHash: z.ZodString;
162
+ synthesizedAt: z.ZodString;
163
+ expiresAt: z.ZodString;
164
+ inFlightSince: z.ZodNullable<z.ZodString>;
165
+ createdAt: z.ZodString;
166
+ updatedAt: z.ZodString;
167
+ }, z.core.$strip>;
168
+ type Synthesis = z.infer<typeof SynthesisSchema>;
147
169
  declare const SessionContextSchema: z.ZodObject<{
148
170
  stats: z.ZodRecord<z.ZodEnum<{
149
171
  correction: "correction";
@@ -224,6 +246,7 @@ declare const SessionContextSchema: z.ZodObject<{
224
246
  createdAt: z.ZodString;
225
247
  updatedAt: z.ZodString;
226
248
  }, z.core.$strip>>;
249
+ synthesis: z.ZodOptional<z.ZodString>;
227
250
  }, z.core.$strip>;
228
251
  type SessionContext = z.infer<typeof SessionContextSchema>;
229
252
  declare const MemoryRowSchema: z.ZodObject<{
@@ -280,6 +303,7 @@ declare class ProjectRepository {
280
303
  }
281
304
  //#endregion
282
305
  //#region src/memory/repository.d.ts
306
+ declare const PIN_BUDGET_THRESHOLD = 8000;
283
307
  declare class MemoryRepository {
284
308
  #private;
285
309
  constructor(db: DatabaseManager, embeddingService: EmbeddingService, projects: ProjectRepository);
@@ -295,10 +319,13 @@ declare class MemoryRepository {
295
319
  unresolvedOnly?: boolean;
296
320
  }): ReviewEvent[];
297
321
  resolveReviewEvents(memoryId: string): void;
322
+ getPinnedCharCount(): number;
298
323
  stats(): {
299
324
  byType: Record<MemoryType, number>;
300
325
  total: number;
326
+ pinned: number;
301
327
  needsReview: number;
328
+ pinBudgetChars: number;
302
329
  };
303
330
  setPin(id: string, pinned: boolean): Memory;
304
331
  incrementAccessCount(id: string): void;
@@ -339,8 +366,25 @@ declare function listMemoryTypes(): MemoryType[];
339
366
  declare class SessionContextBuilder {
340
367
  #private;
341
368
  constructor(db: DatabaseManager);
342
- getSessionContext(projectHash: string): SessionContext;
369
+ getSessionContext(projectHash: string, synthesis?: string): SessionContext;
370
+ }
371
+ //#endregion
372
+ //#region src/synthesis/repository.d.ts
373
+ declare class SynthesisRepository {
374
+ #private;
375
+ constructor(db: DatabaseManager);
376
+ saveSynthesis(scope: string, content: string, sourceHash: string): Synthesis;
377
+ getSynthesis(scope: string): Synthesis | undefined;
378
+ markInFlight(scope: string): void;
379
+ clearInFlight(scope: string): void;
380
+ computeSourceMemoryHash(scope: string): string;
381
+ getExpiredOrDirtyScopes(): {
382
+ scope: string;
383
+ reason: "expired" | "dirty" | "missing";
384
+ }[];
385
+ getAllActiveScopes(): string[];
386
+ expireStale(): void;
343
387
  }
344
388
  //#endregion
345
- export { DatabaseError, DatabaseManager, EmbeddingService, MEMORY_TYPE_VALUES, MIGRATIONS, MembankError, Memory, MemoryPatch, MemoryPatchSchema, MemoryRepository, MemoryRow, MemoryRowSchema, MemorySchema, MemoryType, MemoryTypeSchema, MigrationMeta, ProgressCallback, Project, ProjectRepository, ProjectRow, ProjectRowSchema, ProjectSchema, QueryEngine, QueryOptions, QueryOptionsSchema, ReviewEvent, ReviewEventRow, ReviewEventRowSchema, ReviewEventSchema, ReviewReason, ReviewReasonSchema, SaveOptions, SaveOptionsSchema, ScopeToProjectsResult, SessionContext, SessionContextBuilder, SessionContextSchema, TagsJsonSchema, listMemoryTypes, resolveProject, resolveScope, rowToMemory, rowToProject, runScopeToProjectsMigration };
389
+ export { DatabaseError, DatabaseManager, EmbeddingService, MEMORY_TYPE_VALUES, MIGRATIONS, MembankError, Memory, MemoryPatch, MemoryPatchSchema, MemoryRepository, MemoryRow, MemoryRowSchema, MemorySchema, MemoryType, MemoryTypeSchema, MigrationMeta, PIN_BUDGET_THRESHOLD, ProgressCallback, Project, ProjectRepository, ProjectRow, ProjectRowSchema, ProjectSchema, QueryEngine, QueryOptions, QueryOptionsSchema, ReviewEvent, ReviewEventRow, ReviewEventRowSchema, ReviewEventSchema, ReviewReason, ReviewReasonSchema, SaveOptions, SaveOptionsSchema, ScopeToProjectsResult, SessionContext, SessionContextBuilder, SessionContextSchema, Synthesis, SynthesisRepository, SynthesisSchema, TagsJsonSchema, isSynthesisEnabled, listMemoryTypes, resolveProject, resolveScope, rowToMemory, rowToProject, runScopeToProjectsMigration };
346
390
  //# 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/schemas.ts","../src/db/row-types.ts","../src/embedding/service.ts","../src/project/repository.ts","../src/memory/repository.ts","../src/migrations/index.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,cAoFvB,eAAA;EAAA;UAGJ,WAAA,CAAA;EAAA,OAIA,IAAA,CAAK,MAAA,YAAkB,eAAA;EAAA,OAOvB,YAAA,CAAA,GAAgB,eAAA;ED3Gc;EAAA,OCgH9B,uBAAA,CAAwB,MAAA,EAAQ,SAAA,GAAY,eAAA;EAAA,IAmD/C,EAAA,CAAA,GAAM,aAAA,CAAc,QAAA;EAIxB,KAAA,CAAA;AAAA;;;cCrKW,kBAAA;AAAA,cAQA,gBAAA,EAAgB,CAAA,CAAA,OAAA;;;;;;;KACjB,UAAA,GAAa,CAAA,CAAE,KAAA,QAAa,gBAAA;AAAA,cAE3B,cAAA,EAAc,CAAA,CAAA,QAAA,CAAA,CAAA,CAAA,SAAA;AAAA,cAEd,aAAA,EAAa,CAAA,CAAA,SAAA;;;;;;;KAOd,OAAA,GAAU,CAAA,CAAE,KAAA,QAAa,aAAA;AAAA,cAExB,kBAAA,EAAkB,CAAA,CAAA,OAAA;;;KACnB,YAAA,GAAe,CAAA,CAAE,KAAA,QAAa,kBAAA;AAAA,cAE7B,iBAAA,EAAiB,CAAA,CAAA,SAAA;;;;;;;;;;;;KAUlB,WAAA,GAAc,CAAA,CAAE,KAAA,QAAa,iBAAA;AAAA,cAE5B,oBAAA,EAAoB,CAAA,CAAA,SAAA;;;;;;;;;;;;KAUrB,cAAA,GAAiB,CAAA,CAAE,KAAA,QAAa,oBAAA;AAAA,cAE/B,YAAA,EAAY,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAab,MAAA,GAAS,CAAA,CAAE,KAAA,QAAa,YAAA;AAAA,cAEvB,kBAAA,EAAkB,CAAA,CAAA,SAAA;;;;;;;;;;;;;KAOnB,YAAA,GAAe,CAAA,CAAE,KAAA,QAAa,kBAAA;AAAA,cAE7B,iBAAA,EAAiB,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;KAOlB,WAAA,GAAc,CAAA,CAAE,KAAA,QAAa,iBAAA;AAAA,cAE5B,iBAAA,EAAiB,CAAA,CAAA,SAAA;;;;KAIlB,WAAA,GAAc,CAAA,CAAE,KAAA,QAAa,iBAAA;AAAA,cAE5B,oBAAA,EAAoB,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAKrB,cAAA,GAAiB,CAAA,CAAE,KAAA,QAAa,oBAAA;AAAA,cAE/B,eAAA,EAAe,CAAA,CAAA,SAAA;;;;;;;;;;;KAWhB,SAAA,GAAY,CAAA,CAAE,KAAA,QAAa,eAAA;AAAA,cAE1B,gBAAA,EAAgB,CAAA,CAAA,SAAA;;;;;;;KAOjB,UAAA,GAAa,CAAA,CAAE,KAAA,QAAa,gBAAA;;;iBC3GxB,WAAA,CACd,GAAA,EAAK,SAAA,EACL,QAAA,EAAU,OAAA,IACV,YAAA,GAAc,WAAA,KACb,MAAA;AAAA,iBA8Ba,YAAA,CAAa,GAAA,EAAK,UAAA,GAAa,OAAA;;;KCxCnC,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;EAkB1C,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,aAAA,CAAc,SAAA;EASd,sBAAA,CAAuB,SAAA,aAAsB,GAAA,SAAY,OAAA;AAAA;;;cCxD9C,gBAAA;EAAA;cAMT,EAAA,EAAI,eAAA,EACJ,gBAAA,EAAkB,gBAAA,EAClB,QAAA,EAAU,iBAAA;EAON,IAAA,CAAK,OAAA,EAAS,WAAA,GAAc,OAAA,CAAQ,MAAA;EA8FpC,MAAA,CAAO,EAAA,UAAY,KAAA,EAAO,WAAA,GAAc,OAAA,CAAQ,MAAA;EA+CtD,MAAA,CAAO,EAAA,WAAa,OAAA;EAepB,IAAA,CAAK,IAAA;IAAS,IAAA,GAAO,UAAA;IAAY,MAAA;EAAA,IAAqB,MAAA;EA8BtD,WAAA,CAAA,GAAe,MAAA;EAsBf,gBAAA,CAAiB,QAAA,UAAkB,IAAA;IAAS,cAAA;EAAA,IAA6B,WAAA;EAezE,mBAAA,CAAoB,QAAA;EAmCpB,KAAA,CAAA;IAAW,MAAA,EAAQ,MAAA,CAAO,UAAA;IAAqB,KAAA;IAAe,WAAA;EAAA;EAoC9D,MAAA,CAAO,EAAA,UAAY,MAAA,YAAkB,MAAA;EAuBrC,oBAAA,CAAqB,EAAA;AAAA;;;UCrWN,aAAA;EACf,IAAA;EACA,WAAA;AAAA;AAAA,UAGe,qBAAA;EACf,SAAA;EACA,OAAA;EACA,OAAA;EACA,WAAA;AAAA;AAAA,cAGW,UAAA,EAAY,aAAA;AAAA,iBAQH,2BAAA,CACpB,QAAA,EAAU,iBAAA,GACT,OAAA,CAAQ,qBAAA;;;cCNE,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;;;iBCxBtB,eAAA,CAAA,GAAmB,UAAA;AAAA,cAItB,qBAAA;EAAA;cAGC,EAAA,EAAI,eAAA;EAIhB,iBAAA,CAAkB,WAAA,WAAsB,cAAA;AAAA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/config/loader.ts","../src/db/errors.ts","../src/db/manager.ts","../src/schemas.ts","../src/db/row-types.ts","../src/embedding/service.ts","../src/project/repository.ts","../src/memory/repository.ts","../src/migrations/index.ts","../src/query/engine.ts","../src/scope/resolver.ts","../src/session/builder.ts","../src/synthesis/repository.ts"],"mappings":"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"}
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { mkdirSync } from "node:fs";
1
+ import { mkdirSync, readFileSync } from "node:fs";
2
2
  import { homedir } from "node:os";
3
3
  import { dirname, join } from "node:path";
4
4
  import BetterSqlite3 from "better-sqlite3";
@@ -8,6 +8,20 @@ import { pipeline } from "@huggingface/transformers";
8
8
  import { createHash, randomUUID } from "node:crypto";
9
9
  import { execFile } from "node:child_process";
10
10
  import { promisify } from "node:util";
11
+ //#region src/config/loader.ts
12
+ function loadConfig() {
13
+ const configPath = join(homedir(), ".membank", "config.json");
14
+ try {
15
+ const raw = readFileSync(configPath, "utf8");
16
+ return JSON.parse(raw);
17
+ } catch {
18
+ return null;
19
+ }
20
+ }
21
+ function isSynthesisEnabled() {
22
+ return loadConfig()?.synthesis?.enabled === true;
23
+ }
24
+ //#endregion
11
25
  //#region src/db/errors.ts
12
26
  var MembankError = class extends Error {
13
27
  constructor(message, options) {
@@ -94,6 +108,27 @@ CREATE INDEX IF NOT EXISTS idx_review_events_memory_open
94
108
  ON memory_review_events(memory_id) WHERE resolved_at IS NULL;
95
109
 
96
110
  ALTER TABLE memories DROP COLUMN needs_review;
111
+ `],
112
+ [4, `
113
+ CREATE TABLE IF NOT EXISTS syntheses (
114
+ id TEXT PRIMARY KEY,
115
+ scope TEXT NOT NULL,
116
+ content TEXT NOT NULL,
117
+ source_memory_hash TEXT NOT NULL,
118
+ synthesized_at TEXT NOT NULL,
119
+ expires_at TEXT NOT NULL,
120
+ in_flight_since TEXT,
121
+ created_at TEXT NOT NULL,
122
+ updated_at TEXT NOT NULL,
123
+ UNIQUE(scope),
124
+ CHECK(expires_at > synthesized_at)
125
+ );
126
+
127
+ CREATE INDEX IF NOT EXISTS idx_syntheses_expires_at
128
+ ON syntheses(expires_at);
129
+
130
+ CREATE INDEX IF NOT EXISTS idx_syntheses_scope_inflight
131
+ ON syntheses(scope) WHERE in_flight_since IS NOT NULL;
97
132
  `]
98
133
  ];
99
134
  var DatabaseManager = class DatabaseManager {
@@ -222,12 +257,25 @@ const SaveOptionsSchema = z.object({
222
257
  });
223
258
  const MemoryPatchSchema = z.object({
224
259
  content: z.string().min(1).optional(),
225
- tags: z.array(z.string()).optional()
260
+ tags: z.array(z.string()).optional(),
261
+ type: MemoryTypeSchema.optional()
262
+ });
263
+ const SynthesisSchema = z.object({
264
+ id: z.string(),
265
+ scope: z.string(),
266
+ content: z.string(),
267
+ sourceMemoryHash: z.string(),
268
+ synthesizedAt: z.string(),
269
+ expiresAt: z.string(),
270
+ inFlightSince: z.string().nullable(),
271
+ createdAt: z.string(),
272
+ updatedAt: z.string()
226
273
  });
227
274
  const SessionContextSchema = z.object({
228
275
  stats: z.record(MemoryTypeSchema, z.number()),
229
276
  pinnedGlobal: z.array(MemorySchema),
230
- pinnedProject: z.array(MemorySchema)
277
+ pinnedProject: z.array(MemorySchema),
278
+ synthesis: z.string().optional()
231
279
  });
232
280
  const MemoryRowSchema = z.object({
233
281
  id: z.string(),
@@ -313,6 +361,7 @@ var EmbeddingService = class {
313
361
  };
314
362
  //#endregion
315
363
  //#region src/memory/repository.ts
364
+ const PIN_BUDGET_THRESHOLD = 8e3;
316
365
  var MemoryRepository = class {
317
366
  #db;
318
367
  #embedding;
@@ -361,7 +410,7 @@ var MemoryRepository = class {
361
410
  return rowToMemory(MemoryRowSchema.parse(this.#db.db.prepare(`SELECT * FROM memories WHERE id = ?`).get(id)), this.#projects.getProjectsForMemories([id]).get(id) ?? [], []);
362
411
  }
363
412
  async update(id, patch) {
364
- const { content, tags } = MemoryPatchSchema.parse(patch);
413
+ const { content, tags, type } = MemoryPatchSchema.parse(patch);
365
414
  const existing = this.#db.db.prepare(`SELECT m.rowid, m.* FROM memories m WHERE m.id = ?`).get(id);
366
415
  if (existing === void 0) throw new Error(`Memory not found: ${id}`);
367
416
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -375,6 +424,10 @@ var MemoryRepository = class {
375
424
  sets.push("tags = ?");
376
425
  values.push(JSON.stringify(tags));
377
426
  }
427
+ if (type !== void 0) {
428
+ sets.push("type = ?");
429
+ values.push(type);
430
+ }
378
431
  values.push(id);
379
432
  this.#db.db.prepare(`UPDATE memories SET ${sets.join(", ")} WHERE id = ?`).run(...values);
380
433
  if (content !== void 0) {
@@ -447,6 +500,9 @@ var MemoryRepository = class {
447
500
  }
448
501
  return map;
449
502
  }
503
+ getPinnedCharCount() {
504
+ return (this.#db.db.prepare(`SELECT COALESCE(SUM(LENGTH(content)), 0) as total FROM memories WHERE pinned = 1`).get() ?? { total: 0 }).total;
505
+ }
450
506
  stats() {
451
507
  const byType = Object.fromEntries(MEMORY_TYPE_VALUES.map((t) => [t, 0]));
452
508
  const typeRows = this.#db.db.prepare(`SELECT type, COUNT(*) as count FROM memories GROUP BY type`).all();
@@ -454,12 +510,17 @@ var MemoryRepository = class {
454
510
  const parsed = MemoryTypeSchema.safeParse(row.type);
455
511
  if (parsed.success) byType[parsed.data] = row.count;
456
512
  }
457
- const totals = this.#db.db.prepare(`SELECT COUNT(*) as total FROM memories`).get() ?? { total: 0 };
513
+ const aggregates = this.#db.db.prepare(`SELECT COUNT(*) as total, SUM(pinned) as pinned FROM memories`).get() ?? {
514
+ total: 0,
515
+ pinned: 0
516
+ };
458
517
  const reviewRow = this.#db.db.prepare(`SELECT COUNT(DISTINCT memory_id) as needsReview FROM memory_review_events WHERE resolved_at IS NULL`).get() ?? { needsReview: 0 };
459
518
  return {
460
519
  byType,
461
- total: totals.total,
462
- needsReview: reviewRow.needsReview
520
+ total: aggregates.total,
521
+ pinned: aggregates.pinned ?? 0,
522
+ needsReview: reviewRow.needsReview,
523
+ pinBudgetChars: this.getPinnedCharCount()
463
524
  };
464
525
  }
465
526
  setPin(id, pinned) {
@@ -633,7 +694,7 @@ var QueryEngine = class {
633
694
  const now = Date.now();
634
695
  const scored = rows.filter((row) => row.cosine_sim > 0).map((row) => {
635
696
  const memory = rowToMemory(row, []);
636
- const score = this.#computeScore(memory, now);
697
+ const score = this.#computeScore(memory, row.cosine_sim, now);
637
698
  return {
638
699
  ...memory,
639
700
  score
@@ -644,12 +705,12 @@ var QueryEngine = class {
644
705
  for (const result of results) this.#repo.incrementAccessCount(result.id);
645
706
  return results;
646
707
  }
647
- #computeScore(memory, now) {
708
+ #computeScore(memory, cosine_sim, now) {
648
709
  const typeWeight = TYPE_WEIGHTS[memory.type];
649
710
  const accessCountNorm = memory.accessCount / (memory.accessCount + 10);
650
711
  const recencyNorm = 1 / (1 + (now - new Date(memory.updatedAt).getTime()) / 864e5);
651
712
  const pinned = memory.pinned ? 1 : 0;
652
- return typeWeight * .4 + accessCountNorm * .3 + recencyNorm * .2 + pinned * .1;
713
+ return cosine_sim * .4 + typeWeight * .25 + accessCountNorm * .2 + recencyNorm * .1 + pinned * .05;
653
714
  }
654
715
  };
655
716
  //#endregion
@@ -662,28 +723,139 @@ var SessionContextBuilder = class {
662
723
  constructor(db) {
663
724
  this.#db = db;
664
725
  }
665
- getSessionContext(projectHash) {
666
- const pinnedGlobal = this.#db.db.prepare(`SELECT * FROM memories
667
- WHERE id NOT IN (SELECT memory_id FROM memory_projects)
668
- AND pinned = 1`).all().map((row) => rowToMemory(row, []));
669
- const pinnedProject = this.#db.db.prepare(`SELECT m.* FROM memories m
670
- JOIN memory_projects mp ON mp.memory_id = m.id
671
- JOIN projects p ON p.id = mp.project_id
672
- WHERE p.scope_hash = ? AND m.pinned = 1`).all(projectHash).map((row) => rowToMemory(row, []));
726
+ getSessionContext(projectHash, synthesis) {
673
727
  const typeCounts = this.#db.db.prepare("SELECT type, COUNT(*) as count FROM memories GROUP BY type").all();
674
728
  const stats = Object.fromEntries(MEMORY_TYPE_VALUES.map((t) => [t, 0]));
675
729
  for (const row of typeCounts) {
676
730
  const parsed = MemoryTypeSchema.safeParse(row.type);
677
731
  if (parsed.success) stats[parsed.data] = row.count;
678
732
  }
733
+ if (synthesis !== void 0 && synthesis.length > 0) return {
734
+ stats,
735
+ pinnedGlobal: [],
736
+ pinnedProject: [],
737
+ synthesis
738
+ };
679
739
  return {
680
740
  stats,
681
- pinnedGlobal,
682
- pinnedProject
741
+ pinnedGlobal: this.#db.db.prepare(`SELECT * FROM memories
742
+ WHERE id NOT IN (SELECT memory_id FROM memory_projects)
743
+ AND pinned = 1`).all().map((row) => rowToMemory(row, [])),
744
+ pinnedProject: this.#db.db.prepare(`SELECT m.* FROM memories m
745
+ JOIN memory_projects mp ON mp.memory_id = m.id
746
+ JOIN projects p ON p.id = mp.project_id
747
+ WHERE p.scope_hash = ? AND m.pinned = 1`).all(projectHash).map((row) => rowToMemory(row, []))
683
748
  };
684
749
  }
685
750
  };
686
751
  //#endregion
687
- export { DatabaseError, DatabaseManager, EmbeddingService, MEMORY_TYPE_VALUES, MIGRATIONS, MembankError, MemoryPatchSchema, MemoryRepository, MemoryRowSchema, MemorySchema, MemoryTypeSchema, ProjectRepository, ProjectRowSchema, ProjectSchema, QueryEngine, QueryOptionsSchema, ReviewEventRowSchema, ReviewEventSchema, ReviewReasonSchema, SaveOptionsSchema, SessionContextBuilder, SessionContextSchema, TagsJsonSchema, listMemoryTypes, resolveProject, resolveScope, rowToMemory, rowToProject, runScopeToProjectsMigration };
752
+ //#region src/synthesis/repository.ts
753
+ function rowToSynthesis(row) {
754
+ return SynthesisSchema.parse({
755
+ id: row.id,
756
+ scope: row.scope,
757
+ content: row.content,
758
+ sourceMemoryHash: row.source_memory_hash,
759
+ synthesizedAt: row.synthesized_at,
760
+ expiresAt: row.expires_at,
761
+ inFlightSince: row.in_flight_since,
762
+ createdAt: row.created_at,
763
+ updatedAt: row.updated_at
764
+ });
765
+ }
766
+ const STALENESS_DAYS = 30;
767
+ var SynthesisRepository = class {
768
+ #db;
769
+ constructor(db) {
770
+ this.#db = db;
771
+ }
772
+ saveSynthesis(scope, content, sourceHash) {
773
+ const now = (/* @__PURE__ */ new Date()).toISOString();
774
+ const expiresAt = new Date(Date.now() + STALENESS_DAYS * 24 * 60 * 60 * 1e3).toISOString();
775
+ if (this.#db.db.prepare("SELECT id FROM syntheses WHERE scope = ?").get(scope) !== void 0) this.#db.db.prepare(`UPDATE syntheses
776
+ SET content = ?, source_memory_hash = ?, synthesized_at = ?, expires_at = ?,
777
+ in_flight_since = NULL, updated_at = ?
778
+ WHERE scope = ?`).run(content, sourceHash, now, expiresAt, now, scope);
779
+ else {
780
+ const id = randomUUID();
781
+ this.#db.db.prepare(`INSERT INTO syntheses
782
+ (id, scope, content, source_memory_hash, synthesized_at, expires_at,
783
+ in_flight_since, created_at, updated_at)
784
+ VALUES (?, ?, ?, ?, ?, ?, NULL, ?, ?)`).run(id, scope, content, sourceHash, now, expiresAt, now, now);
785
+ }
786
+ const row = this.#db.db.prepare("SELECT * FROM syntheses WHERE scope = ?").get(scope);
787
+ if (row === void 0) throw new Error(`Failed to save synthesis for scope: ${scope}`);
788
+ return rowToSynthesis(row);
789
+ }
790
+ getSynthesis(scope) {
791
+ const row = this.#db.db.prepare("SELECT * FROM syntheses WHERE scope = ?").get(scope);
792
+ return row !== void 0 ? rowToSynthesis(row) : void 0;
793
+ }
794
+ markInFlight(scope) {
795
+ const now = (/* @__PURE__ */ new Date()).toISOString();
796
+ if (this.#db.db.prepare("SELECT id FROM syntheses WHERE scope = ?").get(scope) !== void 0) this.#db.db.prepare("UPDATE syntheses SET in_flight_since = ?, updated_at = ? WHERE scope = ?").run(now, now, scope);
797
+ else {
798
+ const id = randomUUID();
799
+ const placeholder = "pending";
800
+ const future = new Date(Date.now() + STALENESS_DAYS * 24 * 60 * 60 * 1e3).toISOString();
801
+ this.#db.db.prepare(`INSERT INTO syntheses
802
+ (id, scope, content, source_memory_hash, synthesized_at, expires_at,
803
+ in_flight_since, created_at, updated_at)
804
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(id, scope, placeholder, "", now, future, now, now, now);
805
+ }
806
+ }
807
+ clearInFlight(scope) {
808
+ const now = (/* @__PURE__ */ new Date()).toISOString();
809
+ this.#db.db.prepare("UPDATE syntheses SET in_flight_since = NULL, updated_at = ? WHERE scope = ?").run(now, scope);
810
+ }
811
+ computeSourceMemoryHash(scope) {
812
+ let contents;
813
+ if (scope === "global") contents = this.#db.db.prepare(`SELECT content FROM memories
814
+ WHERE id NOT IN (SELECT memory_id FROM memory_projects)
815
+ ORDER BY id`).all();
816
+ else contents = this.#db.db.prepare(`SELECT m.content FROM memories m
817
+ JOIN memory_projects mp ON mp.memory_id = m.id
818
+ JOIN projects p ON p.id = mp.project_id
819
+ WHERE p.scope_hash = ?
820
+ ORDER BY m.id`).all(scope);
821
+ return createHash("sha256").update(JSON.stringify(contents.map((r) => r.content))).digest("hex");
822
+ }
823
+ getExpiredOrDirtyScopes() {
824
+ const allScopes = this.getAllActiveScopes();
825
+ const now = (/* @__PURE__ */ new Date()).toISOString();
826
+ const results = [];
827
+ for (const scope of allScopes) {
828
+ const row = this.#db.db.prepare("SELECT * FROM syntheses WHERE scope = ?").get(scope);
829
+ if (row === void 0 || row.content === "pending" && row.source_memory_hash === "") {
830
+ results.push({
831
+ scope,
832
+ reason: "missing"
833
+ });
834
+ continue;
835
+ }
836
+ if (row.expires_at <= now) {
837
+ results.push({
838
+ scope,
839
+ reason: "expired"
840
+ });
841
+ continue;
842
+ }
843
+ if (this.computeSourceMemoryHash(scope) !== row.source_memory_hash) results.push({
844
+ scope,
845
+ reason: "dirty"
846
+ });
847
+ }
848
+ return results;
849
+ }
850
+ getAllActiveScopes() {
851
+ return ["global", ...this.#db.db.prepare("SELECT DISTINCT scope_hash FROM projects").all().map((r) => r.scope_hash)];
852
+ }
853
+ expireStale() {
854
+ const now = (/* @__PURE__ */ new Date()).toISOString();
855
+ this.#db.db.prepare("DELETE FROM syntheses WHERE expires_at < ?").run(now);
856
+ }
857
+ };
858
+ //#endregion
859
+ export { DatabaseError, DatabaseManager, EmbeddingService, MEMORY_TYPE_VALUES, MIGRATIONS, MembankError, MemoryPatchSchema, MemoryRepository, MemoryRowSchema, MemorySchema, MemoryTypeSchema, PIN_BUDGET_THRESHOLD, ProjectRepository, ProjectRowSchema, ProjectSchema, QueryEngine, QueryOptionsSchema, ReviewEventRowSchema, ReviewEventSchema, ReviewReasonSchema, SaveOptionsSchema, SessionContextBuilder, SessionContextSchema, SynthesisRepository, SynthesisSchema, TagsJsonSchema, isSynthesisEnabled, listMemoryTypes, resolveProject, resolveScope, rowToMemory, rowToProject, runScopeToProjectsMigration };
688
860
 
689
861
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["MIGRATIONS","#db","#init","#initInMemory","#runMigrations","#db","#embedding","#projects","#getEventsForMemories","#db","#db","#embedding","#repo","#computeScore","#db"],"sources":["../src/db/errors.ts","../src/db/manager.ts","../src/schemas.ts","../src/db/row-types.ts","../src/embedding/service.ts","../src/memory/repository.ts","../src/scope/resolver.ts","../src/migrations/index.ts","../src/project/repository.ts","../src/query/engine.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 3,\n `\nCREATE TABLE IF NOT EXISTS memory_review_events (\n id TEXT PRIMARY KEY,\n memory_id TEXT NOT NULL REFERENCES memories(id) ON DELETE CASCADE,\n conflicting_memory_id TEXT REFERENCES memories(id) ON DELETE SET NULL,\n similarity REAL NOT NULL,\n conflict_content_snapshot TEXT NOT NULL,\n reason TEXT NOT NULL,\n created_at TEXT NOT NULL,\n resolved_at TEXT\n);\n\nCREATE INDEX IF NOT EXISTS idx_review_events_memory_open\n ON memory_review_events(memory_id) WHERE resolved_at IS NULL;\n\nALTER TABLE memories DROP COLUMN needs_review;\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 { z } from \"zod\";\n\nexport const MEMORY_TYPE_VALUES = [\n \"correction\",\n \"preference\",\n \"decision\",\n \"learning\",\n \"fact\",\n] as const;\n\nexport const MemoryTypeSchema = z.enum(MEMORY_TYPE_VALUES);\nexport type MemoryType = z.infer<typeof MemoryTypeSchema>;\n\nexport const TagsJsonSchema = z.array(z.string());\n\nexport const ProjectSchema = z.object({\n id: z.string(),\n name: z.string(),\n scopeHash: z.string(),\n createdAt: z.string(),\n updatedAt: z.string(),\n});\nexport type Project = z.infer<typeof ProjectSchema>;\n\nexport const ReviewReasonSchema = z.enum([\"similarity_dedup\"]);\nexport type ReviewReason = z.infer<typeof ReviewReasonSchema>;\n\nexport const ReviewEventSchema = z.object({\n id: z.string(),\n memoryId: z.string(),\n conflictingMemoryId: z.string().nullable(),\n similarity: z.number(),\n conflictContentSnapshot: z.string(),\n reason: ReviewReasonSchema,\n createdAt: z.string(),\n resolvedAt: z.string().nullable(),\n});\nexport type ReviewEvent = z.infer<typeof ReviewEventSchema>;\n\nexport const ReviewEventRowSchema = z.object({\n id: z.string(),\n memory_id: z.string(),\n conflicting_memory_id: z.string().nullable(),\n similarity: z.number(),\n conflict_content_snapshot: z.string(),\n reason: ReviewReasonSchema,\n created_at: z.string(),\n resolved_at: z.string().nullable(),\n});\nexport type ReviewEventRow = z.infer<typeof ReviewEventRowSchema>;\n\nexport const MemorySchema = z.object({\n id: z.string(),\n content: z.string(),\n type: MemoryTypeSchema,\n tags: z.array(z.string()),\n projects: z.array(ProjectSchema),\n sourceHarness: z.string().nullable(),\n accessCount: z.number().int().nonnegative(),\n pinned: z.boolean(),\n reviewEvents: z.array(ReviewEventSchema),\n createdAt: z.string(),\n updatedAt: z.string(),\n});\nexport type Memory = z.infer<typeof MemorySchema>;\n\nexport const QueryOptionsSchema = z.object({\n query: z.string().min(1),\n type: MemoryTypeSchema.optional(),\n projectHash: z.string().optional(),\n limit: z.number().int().positive().optional(),\n includePinned: z.boolean().optional(),\n});\nexport type QueryOptions = z.infer<typeof QueryOptionsSchema>;\n\nexport const SaveOptionsSchema = z.object({\n content: z.string().min(1),\n type: MemoryTypeSchema,\n tags: z.array(z.string()).optional(),\n projectScope: z.object({ hash: z.string(), name: z.string() }).optional(),\n sourceHarness: z.string().optional(),\n});\nexport type SaveOptions = z.infer<typeof SaveOptionsSchema>;\n\nexport const MemoryPatchSchema = z.object({\n content: z.string().min(1).optional(),\n tags: z.array(z.string()).optional(),\n});\nexport type MemoryPatch = z.infer<typeof MemoryPatchSchema>;\n\nexport const SessionContextSchema = z.object({\n stats: z.record(MemoryTypeSchema, z.number()),\n pinnedGlobal: z.array(MemorySchema),\n pinnedProject: z.array(MemorySchema),\n});\nexport type SessionContext = z.infer<typeof SessionContextSchema>;\n\nexport const MemoryRowSchema = z.object({\n id: z.string(),\n content: z.string(),\n type: z.string(),\n tags: z.string(),\n source: z.string().nullable(),\n access_count: z.number(),\n pinned: z.number(),\n created_at: z.string(),\n updated_at: z.string(),\n});\nexport type MemoryRow = z.infer<typeof MemoryRowSchema>;\n\nexport const ProjectRowSchema = z.object({\n id: z.string(),\n name: z.string(),\n scope_hash: z.string(),\n created_at: z.string(),\n updated_at: z.string(),\n});\nexport type ProjectRow = z.infer<typeof ProjectRowSchema>;\n","import { MemoryTypeSchema, ReviewEventRowSchema, TagsJsonSchema } from \"../schemas.js\";\nimport type {\n Memory,\n MemoryRow,\n Project,\n ProjectRow,\n ReviewEvent,\n ReviewEventRow,\n} from \"../types.js\";\n\nexport function rowToMemory(\n row: MemoryRow,\n projects: Project[],\n reviewEvents: ReviewEvent[] = []\n): Memory {\n return {\n id: row.id,\n content: row.content,\n type: MemoryTypeSchema.parse(row.type),\n tags: TagsJsonSchema.parse(JSON.parse(row.tags)),\n projects,\n sourceHarness: row.source,\n accessCount: row.access_count,\n pinned: row.pinned !== 0,\n reviewEvents,\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n };\n}\n\nexport function rowToReviewEvent(row: ReviewEventRow): ReviewEvent {\n const parsed = ReviewEventRowSchema.parse(row);\n return {\n id: parsed.id,\n memoryId: parsed.memory_id,\n conflictingMemoryId: parsed.conflicting_memory_id,\n similarity: parsed.similarity,\n conflictContentSnapshot: parsed.conflict_content_snapshot,\n reason: parsed.reason,\n createdAt: parsed.created_at,\n resolvedAt: parsed.resolved_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","import { randomUUID } from \"node:crypto\";\nimport type { DatabaseManager } from \"../db/manager.js\";\nimport { rowToMemory, rowToReviewEvent } from \"../db/row-types.js\";\nimport type { EmbeddingService } from \"../embedding/service.js\";\nimport type { ProjectRepository } from \"../project/repository.js\";\nimport {\n MEMORY_TYPE_VALUES,\n MemoryPatchSchema,\n MemoryRowSchema,\n MemoryTypeSchema,\n ReviewEventRowSchema,\n SaveOptionsSchema,\n} from \"../schemas.js\";\nimport type {\n Memory,\n MemoryPatch,\n MemoryRow,\n MemoryType,\n ReviewEvent,\n ReviewEventRow,\n SaveOptions,\n} 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 {\n content,\n type,\n tags = [],\n projectScope,\n sourceHarness,\n } = SaveOptionsSchema.parse(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 (projectScope !== 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, projectScope.hash);\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 = MemoryRowSchema.parse(\n this.#db.db.prepare<[string], unknown>(`SELECT * FROM memories WHERE id = ?`).get(top.id)\n );\n\n const projectMap = this.#projects.getProjectsForMemories([top.id]);\n const events = this.#getEventsForMemories([top.id]);\n return rowToMemory(updated, projectMap.get(top.id) ?? [], events.get(top.id) ?? []);\n }\n\n const id = randomUUID();\n\n this.#db.db\n .prepare(\n `INSERT INTO memories (id, content, type, tags, source, access_count, pinned, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, 0, 0, ?, ?)`\n )\n .run(id, content, type, JSON.stringify(tags), sourceHarness ?? null, now, now);\n\n if (top !== undefined && top.similarity >= 0.75) {\n this.#db.db\n .prepare(\n `INSERT INTO memory_review_events\n (id, memory_id, conflicting_memory_id, similarity, conflict_content_snapshot, reason, created_at)\n VALUES (?, ?, ?, ?, ?, 'similarity_dedup', ?)`\n )\n .run(randomUUID(), top.id, id, top.similarity, content, now);\n }\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 (projectScope !== undefined) {\n const project = this.#projects.upsertByHash(projectScope.hash, projectScope.name);\n this.#projects.addAssociation(id, project.id);\n }\n\n const row = MemoryRowSchema.parse(\n this.#db.db.prepare<[string], unknown>(`SELECT * FROM memories WHERE id = ?`).get(id)\n );\n\n const projectMap = this.#projects.getProjectsForMemories([id]);\n return rowToMemory(row, projectMap.get(id) ?? [], []);\n }\n\n async update(id: string, patch: MemoryPatch): Promise<Memory> {\n const { content, tags } = MemoryPatchSchema.parse(patch);\n\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 (content !== undefined) {\n sets.push(\"content = ?\");\n values.push(content);\n }\n\n if (tags !== undefined) {\n sets.push(\"tags = ?\");\n values.push(JSON.stringify(tags));\n }\n\n values.push(id);\n this.#db.db.prepare(`UPDATE memories SET ${sets.join(\", \")} WHERE id = ?`).run(...values);\n\n if (content !== undefined) {\n const embedding = await this.#embedding.embed(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 = MemoryRowSchema.parse(\n this.#db.db.prepare<[string], unknown>(`SELECT * FROM memories WHERE id = ?`).get(id)\n );\n\n const projectMap = this.#projects.getProjectsForMemories([id]);\n const events = this.#getEventsForMemories([id]);\n return rowToMemory(updated, projectMap.get(id) ?? [], events.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 const eventMap = this.#getEventsForMemories(ids);\n return rows.map((row) =>\n rowToMemory(row, projectMap.get(row.id) ?? [], eventMap.get(row.id) ?? [])\n );\n }\n\n listFlagged(): Memory[] {\n const rows = this.#db.db\n .prepare<[], MemoryRow>(\n `SELECT * FROM memories\n WHERE EXISTS (\n SELECT 1 FROM memory_review_events e\n WHERE e.memory_id = memories.id AND e.resolved_at IS NULL\n )\n ORDER BY created_at DESC`\n )\n .all();\n\n if (rows.length === 0) return [];\n\n const ids = rows.map((r) => r.id);\n const projectMap = this.#projects.getProjectsForMemories(ids);\n const eventMap = this.#getEventsForMemories(ids, { unresolvedOnly: true });\n return rows.map((row) =>\n rowToMemory(row, projectMap.get(row.id) ?? [], eventMap.get(row.id) ?? [])\n );\n }\n\n listReviewEvents(memoryId: string, opts?: { unresolvedOnly?: boolean }): ReviewEvent[] {\n const where =\n opts?.unresolvedOnly === true\n ? \"WHERE memory_id = ? AND resolved_at IS NULL\"\n : \"WHERE memory_id = ?\";\n\n const rows = this.#db.db\n .prepare<[string], ReviewEventRow>(\n `SELECT * FROM memory_review_events ${where} ORDER BY created_at DESC`\n )\n .all(memoryId);\n\n return rows.map((r) => rowToReviewEvent(ReviewEventRowSchema.parse(r)));\n }\n\n resolveReviewEvents(memoryId: string): void {\n const now = new Date().toISOString();\n this.#db.db\n .prepare(\n `UPDATE memory_review_events SET resolved_at = ? WHERE memory_id = ? AND resolved_at IS NULL`\n )\n .run(now, memoryId);\n }\n\n #getEventsForMemories(\n ids: string[],\n opts?: { unresolvedOnly?: boolean }\n ): Map<string, ReviewEvent[]> {\n if (ids.length === 0) return new Map();\n\n const placeholders = ids.map(() => \"?\").join(\", \");\n const unresolvedClause = opts?.unresolvedOnly === true ? \"AND resolved_at IS NULL\" : \"\";\n const rows = this.#db.db\n .prepare<string[], ReviewEventRow>(\n `SELECT * FROM memory_review_events\n WHERE memory_id IN (${placeholders}) ${unresolvedClause}\n ORDER BY created_at DESC`\n )\n .all(...ids);\n\n const map = new Map<string, ReviewEvent[]>();\n for (const row of rows) {\n const event = rowToReviewEvent(ReviewEventRowSchema.parse(row));\n const existing = map.get(event.memoryId) ?? [];\n existing.push(event);\n map.set(event.memoryId, existing);\n }\n return map;\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 const parsed = MemoryTypeSchema.safeParse(row.type);\n if (parsed.success) {\n byType[parsed.data] = row.count;\n }\n }\n\n const totals = this.#db.db\n .prepare<[], { total: number }>(`SELECT COUNT(*) as total FROM memories`)\n .get() ?? { total: 0 };\n\n const reviewRow = this.#db.db\n .prepare<[], { needsReview: number }>(\n `SELECT COUNT(DISTINCT memory_id) as needsReview FROM memory_review_events WHERE resolved_at IS NULL`\n )\n .get() ?? { needsReview: 0 };\n\n return {\n byType,\n total: totals.total,\n needsReview: reviewRow.needsReview,\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 = MemoryRowSchema.parse(\n this.#db.db.prepare<[string], unknown>(`SELECT * FROM memories WHERE id = ?`).get(id)\n );\n\n const projectMap = this.#projects.getProjectsForMemories([id]);\n const events = this.#getEventsForMemories([id]);\n return rowToMemory(updated, projectMap.get(id) ?? [], events.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 { 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 { ProjectRepository } from \"../project/index.js\";\nimport { resolveProject } from \"../scope/index.js\";\n\nexport interface MigrationMeta {\n name: string;\n description: string;\n}\n\nexport interface ScopeToProjectsResult {\n migration: \"scope-to-projects\";\n oldName: string;\n newName: string;\n memoryCount: number;\n}\n\nexport const MIGRATIONS: MigrationMeta[] = [\n {\n name: \"scope-to-projects\",\n description:\n \"Rename the auto-migrated project for the current directory from its generic hash-derived name to the resolved repo/directory name.\",\n },\n];\n\nexport async function runScopeToProjectsMigration(\n projects: ProjectRepository\n): Promise<ScopeToProjectsResult | null> {\n const resolved = await resolveProject();\n const project = projects.getByHash(resolved.hash);\n\n if (project === undefined) {\n return null;\n }\n\n const oldName = project.name;\n const memoryCount = projects.countMemories(project.id);\n projects.rename(project.id, resolved.name);\n\n return {\n migration: \"scope-to-projects\",\n oldName,\n newName: resolved.name,\n memoryCount,\n };\n}\n","import { randomUUID } from \"node:crypto\";\nimport type { DatabaseManager } from \"../db/manager.js\";\nimport { rowToProject } from \"../db/row-types.js\";\nimport { ProjectRowSchema } from \"../schemas.js\";\nimport type { Project, ProjectRow } 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 = ProjectRowSchema.parse(\n this.#db.db\n .prepare<[string], unknown>(`SELECT * FROM projects WHERE scope_hash = ?`)\n .get(hash)\n );\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 countMemories(projectId: string): number {\n const row = this.#db.db\n .prepare<[string], { count: number }>(\n `SELECT COUNT(*) AS count FROM memory_projects WHERE project_id = ?`\n )\n .get(projectId);\n return row?.count ?? 0;\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 { rowToMemory } from \"../db/row-types.js\";\nimport type { EmbeddingService } from \"../embedding/service.js\";\nimport type { MemoryRepository } from \"../memory/repository.js\";\nimport { QueryOptionsSchema } from \"../schemas.js\";\nimport type { Memory, MemoryRow, 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 {\n query,\n type,\n projectHash,\n limit = 10,\n includePinned,\n } = QueryOptionsSchema.parse(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 (!includePinned) {\n whereClauses.push(\"m.pinned = 0\");\n }\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 type { DatabaseManager } from \"../db/manager.js\";\nimport { rowToMemory } from \"../db/row-types.js\";\nimport { MEMORY_TYPE_VALUES, MemoryTypeSchema } from \"../schemas.js\";\nimport type { MemoryRow, MemoryType, SessionContext } 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 const parsed = MemoryTypeSchema.safeParse(row.type);\n if (parsed.success) {\n stats[parsed.data] = 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":["MIGRATIONS","#db","#init","#initInMemory","#runMigrations","#db","#embedding","#projects","#getEventsForMemories","#db","#db","#embedding","#repo","#computeScore","#db","#db"],"sources":["../src/config/loader.ts","../src/db/errors.ts","../src/db/manager.ts","../src/schemas.ts","../src/db/row-types.ts","../src/embedding/service.ts","../src/memory/repository.ts","../src/scope/resolver.ts","../src/migrations/index.ts","../src/project/repository.ts","../src/query/engine.ts","../src/session/builder.ts","../src/synthesis/repository.ts"],"sourcesContent":["import { readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\ninterface MemoryConfig {\n synthesis?: { enabled?: boolean };\n}\n\nfunction loadConfig(): MemoryConfig | null {\n const configPath = join(homedir(), \".membank\", \"config.json\");\n try {\n const raw = readFileSync(configPath, \"utf8\");\n return JSON.parse(raw) as MemoryConfig;\n } catch {\n return null;\n }\n}\n\nexport function isSynthesisEnabled(): boolean {\n const config = loadConfig();\n return config?.synthesis?.enabled === true;\n}\n","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 3,\n `\nCREATE TABLE IF NOT EXISTS memory_review_events (\n id TEXT PRIMARY KEY,\n memory_id TEXT NOT NULL REFERENCES memories(id) ON DELETE CASCADE,\n conflicting_memory_id TEXT REFERENCES memories(id) ON DELETE SET NULL,\n similarity REAL NOT NULL,\n conflict_content_snapshot TEXT NOT NULL,\n reason TEXT NOT NULL,\n created_at TEXT NOT NULL,\n resolved_at TEXT\n);\n\nCREATE INDEX IF NOT EXISTS idx_review_events_memory_open\n ON memory_review_events(memory_id) WHERE resolved_at IS NULL;\n\nALTER TABLE memories DROP COLUMN needs_review;\n`,\n ],\n [\n 4,\n `\nCREATE TABLE IF NOT EXISTS syntheses (\n id TEXT PRIMARY KEY,\n scope TEXT NOT NULL,\n content TEXT NOT NULL,\n source_memory_hash TEXT NOT NULL,\n synthesized_at TEXT NOT NULL,\n expires_at TEXT NOT NULL,\n in_flight_since TEXT,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL,\n UNIQUE(scope),\n CHECK(expires_at > synthesized_at)\n);\n\nCREATE INDEX IF NOT EXISTS idx_syntheses_expires_at\n ON syntheses(expires_at);\n\nCREATE INDEX IF NOT EXISTS idx_syntheses_scope_inflight\n ON syntheses(scope) WHERE in_flight_since IS NOT NULL;\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 { z } from \"zod\";\n\nexport const MEMORY_TYPE_VALUES = [\n \"correction\",\n \"preference\",\n \"decision\",\n \"learning\",\n \"fact\",\n] as const;\n\nexport const MemoryTypeSchema = z.enum(MEMORY_TYPE_VALUES);\nexport type MemoryType = z.infer<typeof MemoryTypeSchema>;\n\nexport const TagsJsonSchema = z.array(z.string());\n\nexport const ProjectSchema = z.object({\n id: z.string(),\n name: z.string(),\n scopeHash: z.string(),\n createdAt: z.string(),\n updatedAt: z.string(),\n});\nexport type Project = z.infer<typeof ProjectSchema>;\n\nexport const ReviewReasonSchema = z.enum([\"similarity_dedup\"]);\nexport type ReviewReason = z.infer<typeof ReviewReasonSchema>;\n\nexport const ReviewEventSchema = z.object({\n id: z.string(),\n memoryId: z.string(),\n conflictingMemoryId: z.string().nullable(),\n similarity: z.number(),\n conflictContentSnapshot: z.string(),\n reason: ReviewReasonSchema,\n createdAt: z.string(),\n resolvedAt: z.string().nullable(),\n});\nexport type ReviewEvent = z.infer<typeof ReviewEventSchema>;\n\nexport const ReviewEventRowSchema = z.object({\n id: z.string(),\n memory_id: z.string(),\n conflicting_memory_id: z.string().nullable(),\n similarity: z.number(),\n conflict_content_snapshot: z.string(),\n reason: ReviewReasonSchema,\n created_at: z.string(),\n resolved_at: z.string().nullable(),\n});\nexport type ReviewEventRow = z.infer<typeof ReviewEventRowSchema>;\n\nexport const MemorySchema = z.object({\n id: z.string(),\n content: z.string(),\n type: MemoryTypeSchema,\n tags: z.array(z.string()),\n projects: z.array(ProjectSchema),\n sourceHarness: z.string().nullable(),\n accessCount: z.number().int().nonnegative(),\n pinned: z.boolean(),\n reviewEvents: z.array(ReviewEventSchema),\n createdAt: z.string(),\n updatedAt: z.string(),\n});\nexport type Memory = z.infer<typeof MemorySchema>;\n\nexport const QueryOptionsSchema = z.object({\n query: z.string().min(1),\n type: MemoryTypeSchema.optional(),\n projectHash: z.string().optional(),\n limit: z.number().int().positive().optional(),\n includePinned: z.boolean().optional(),\n});\nexport type QueryOptions = z.infer<typeof QueryOptionsSchema>;\n\nexport const SaveOptionsSchema = z.object({\n content: z.string().min(1),\n type: MemoryTypeSchema,\n tags: z.array(z.string()).optional(),\n projectScope: z.object({ hash: z.string(), name: z.string() }).optional(),\n sourceHarness: z.string().optional(),\n});\nexport type SaveOptions = z.infer<typeof SaveOptionsSchema>;\n\nexport const MemoryPatchSchema = z.object({\n content: z.string().min(1).optional(),\n tags: z.array(z.string()).optional(),\n type: MemoryTypeSchema.optional(),\n});\nexport type MemoryPatch = z.infer<typeof MemoryPatchSchema>;\n\nexport const SynthesisSchema = z.object({\n id: z.string(),\n scope: z.string(),\n content: z.string(),\n sourceMemoryHash: z.string(),\n synthesizedAt: z.string(),\n expiresAt: z.string(),\n inFlightSince: z.string().nullable(),\n createdAt: z.string(),\n updatedAt: z.string(),\n});\nexport type Synthesis = z.infer<typeof SynthesisSchema>;\n\nexport const SessionContextSchema = z.object({\n stats: z.record(MemoryTypeSchema, z.number()),\n pinnedGlobal: z.array(MemorySchema),\n pinnedProject: z.array(MemorySchema),\n synthesis: z.string().optional(),\n});\nexport type SessionContext = z.infer<typeof SessionContextSchema>;\n\nexport const MemoryRowSchema = z.object({\n id: z.string(),\n content: z.string(),\n type: z.string(),\n tags: z.string(),\n source: z.string().nullable(),\n access_count: z.number(),\n pinned: z.number(),\n created_at: z.string(),\n updated_at: z.string(),\n});\nexport type MemoryRow = z.infer<typeof MemoryRowSchema>;\n\nexport const ProjectRowSchema = z.object({\n id: z.string(),\n name: z.string(),\n scope_hash: z.string(),\n created_at: z.string(),\n updated_at: z.string(),\n});\nexport type ProjectRow = z.infer<typeof ProjectRowSchema>;\n","import { MemoryTypeSchema, ReviewEventRowSchema, TagsJsonSchema } from \"../schemas.js\";\nimport type {\n Memory,\n MemoryRow,\n Project,\n ProjectRow,\n ReviewEvent,\n ReviewEventRow,\n} from \"../types.js\";\n\nexport function rowToMemory(\n row: MemoryRow,\n projects: Project[],\n reviewEvents: ReviewEvent[] = []\n): Memory {\n return {\n id: row.id,\n content: row.content,\n type: MemoryTypeSchema.parse(row.type),\n tags: TagsJsonSchema.parse(JSON.parse(row.tags)),\n projects,\n sourceHarness: row.source,\n accessCount: row.access_count,\n pinned: row.pinned !== 0,\n reviewEvents,\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n };\n}\n\nexport function rowToReviewEvent(row: ReviewEventRow): ReviewEvent {\n const parsed = ReviewEventRowSchema.parse(row);\n return {\n id: parsed.id,\n memoryId: parsed.memory_id,\n conflictingMemoryId: parsed.conflicting_memory_id,\n similarity: parsed.similarity,\n conflictContentSnapshot: parsed.conflict_content_snapshot,\n reason: parsed.reason,\n createdAt: parsed.created_at,\n resolvedAt: parsed.resolved_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","import { randomUUID } from \"node:crypto\";\nimport type { DatabaseManager } from \"../db/manager.js\";\nimport { rowToMemory, rowToReviewEvent } from \"../db/row-types.js\";\nimport type { EmbeddingService } from \"../embedding/service.js\";\nimport type { ProjectRepository } from \"../project/repository.js\";\nimport {\n MEMORY_TYPE_VALUES,\n MemoryPatchSchema,\n MemoryRowSchema,\n MemoryTypeSchema,\n ReviewEventRowSchema,\n SaveOptionsSchema,\n} from \"../schemas.js\";\nimport type {\n Memory,\n MemoryPatch,\n MemoryRow,\n MemoryType,\n ReviewEvent,\n ReviewEventRow,\n SaveOptions,\n} from \"../types.js\";\n\nexport const PIN_BUDGET_THRESHOLD = 8000;\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 {\n content,\n type,\n tags = [],\n projectScope,\n sourceHarness,\n } = SaveOptionsSchema.parse(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 (projectScope !== 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, projectScope.hash);\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 = MemoryRowSchema.parse(\n this.#db.db.prepare<[string], unknown>(`SELECT * FROM memories WHERE id = ?`).get(top.id)\n );\n\n const projectMap = this.#projects.getProjectsForMemories([top.id]);\n const events = this.#getEventsForMemories([top.id]);\n return rowToMemory(updated, projectMap.get(top.id) ?? [], events.get(top.id) ?? []);\n }\n\n const id = randomUUID();\n\n this.#db.db\n .prepare(\n `INSERT INTO memories (id, content, type, tags, source, access_count, pinned, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, 0, 0, ?, ?)`\n )\n .run(id, content, type, JSON.stringify(tags), sourceHarness ?? null, now, now);\n\n if (top !== undefined && top.similarity >= 0.75) {\n this.#db.db\n .prepare(\n `INSERT INTO memory_review_events\n (id, memory_id, conflicting_memory_id, similarity, conflict_content_snapshot, reason, created_at)\n VALUES (?, ?, ?, ?, ?, 'similarity_dedup', ?)`\n )\n .run(randomUUID(), top.id, id, top.similarity, content, now);\n }\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 (projectScope !== undefined) {\n const project = this.#projects.upsertByHash(projectScope.hash, projectScope.name);\n this.#projects.addAssociation(id, project.id);\n }\n\n const row = MemoryRowSchema.parse(\n this.#db.db.prepare<[string], unknown>(`SELECT * FROM memories WHERE id = ?`).get(id)\n );\n\n const projectMap = this.#projects.getProjectsForMemories([id]);\n return rowToMemory(row, projectMap.get(id) ?? [], []);\n }\n\n async update(id: string, patch: MemoryPatch): Promise<Memory> {\n const { content, tags, type } = MemoryPatchSchema.parse(patch);\n\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 (content !== undefined) {\n sets.push(\"content = ?\");\n values.push(content);\n }\n\n if (tags !== undefined) {\n sets.push(\"tags = ?\");\n values.push(JSON.stringify(tags));\n }\n\n if (type !== undefined) {\n sets.push(\"type = ?\");\n values.push(type);\n }\n\n values.push(id);\n this.#db.db.prepare(`UPDATE memories SET ${sets.join(\", \")} WHERE id = ?`).run(...values);\n\n if (content !== undefined) {\n const embedding = await this.#embedding.embed(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 = MemoryRowSchema.parse(\n this.#db.db.prepare<[string], unknown>(`SELECT * FROM memories WHERE id = ?`).get(id)\n );\n\n const projectMap = this.#projects.getProjectsForMemories([id]);\n const events = this.#getEventsForMemories([id]);\n return rowToMemory(updated, projectMap.get(id) ?? [], events.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 const eventMap = this.#getEventsForMemories(ids);\n return rows.map((row) =>\n rowToMemory(row, projectMap.get(row.id) ?? [], eventMap.get(row.id) ?? [])\n );\n }\n\n listFlagged(): Memory[] {\n const rows = this.#db.db\n .prepare<[], MemoryRow>(\n `SELECT * FROM memories\n WHERE EXISTS (\n SELECT 1 FROM memory_review_events e\n WHERE e.memory_id = memories.id AND e.resolved_at IS NULL\n )\n ORDER BY created_at DESC`\n )\n .all();\n\n if (rows.length === 0) return [];\n\n const ids = rows.map((r) => r.id);\n const projectMap = this.#projects.getProjectsForMemories(ids);\n const eventMap = this.#getEventsForMemories(ids, { unresolvedOnly: true });\n return rows.map((row) =>\n rowToMemory(row, projectMap.get(row.id) ?? [], eventMap.get(row.id) ?? [])\n );\n }\n\n listReviewEvents(memoryId: string, opts?: { unresolvedOnly?: boolean }): ReviewEvent[] {\n const where =\n opts?.unresolvedOnly === true\n ? \"WHERE memory_id = ? AND resolved_at IS NULL\"\n : \"WHERE memory_id = ?\";\n\n const rows = this.#db.db\n .prepare<[string], ReviewEventRow>(\n `SELECT * FROM memory_review_events ${where} ORDER BY created_at DESC`\n )\n .all(memoryId);\n\n return rows.map((r) => rowToReviewEvent(ReviewEventRowSchema.parse(r)));\n }\n\n resolveReviewEvents(memoryId: string): void {\n const now = new Date().toISOString();\n this.#db.db\n .prepare(\n `UPDATE memory_review_events SET resolved_at = ? WHERE memory_id = ? AND resolved_at IS NULL`\n )\n .run(now, memoryId);\n }\n\n #getEventsForMemories(\n ids: string[],\n opts?: { unresolvedOnly?: boolean }\n ): Map<string, ReviewEvent[]> {\n if (ids.length === 0) return new Map();\n\n const placeholders = ids.map(() => \"?\").join(\", \");\n const unresolvedClause = opts?.unresolvedOnly === true ? \"AND resolved_at IS NULL\" : \"\";\n const rows = this.#db.db\n .prepare<string[], ReviewEventRow>(\n `SELECT * FROM memory_review_events\n WHERE memory_id IN (${placeholders}) ${unresolvedClause}\n ORDER BY created_at DESC`\n )\n .all(...ids);\n\n const map = new Map<string, ReviewEvent[]>();\n for (const row of rows) {\n const event = rowToReviewEvent(ReviewEventRowSchema.parse(row));\n const existing = map.get(event.memoryId) ?? [];\n existing.push(event);\n map.set(event.memoryId, existing);\n }\n return map;\n }\n\n getPinnedCharCount(): number {\n const row = this.#db.db\n .prepare<[], { total: number }>(\n `SELECT COALESCE(SUM(LENGTH(content)), 0) as total FROM memories WHERE pinned = 1`\n )\n .get() ?? { total: 0 };\n return row.total;\n }\n\n stats(): {\n byType: Record<MemoryType, number>;\n total: number;\n pinned: number;\n needsReview: number;\n pinBudgetChars: number;\n } {\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 const parsed = MemoryTypeSchema.safeParse(row.type);\n if (parsed.success) {\n byType[parsed.data] = row.count;\n }\n }\n\n const aggregates = this.#db.db\n .prepare<[], { total: number; pinned: number | null }>(\n `SELECT COUNT(*) as total, SUM(pinned) as pinned FROM memories`\n )\n .get() ?? { total: 0, pinned: 0 };\n\n const reviewRow = this.#db.db\n .prepare<[], { needsReview: number }>(\n `SELECT COUNT(DISTINCT memory_id) as needsReview FROM memory_review_events WHERE resolved_at IS NULL`\n )\n .get() ?? { needsReview: 0 };\n\n return {\n byType,\n total: aggregates.total,\n pinned: aggregates.pinned ?? 0,\n needsReview: reviewRow.needsReview,\n pinBudgetChars: this.getPinnedCharCount(),\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 = MemoryRowSchema.parse(\n this.#db.db.prepare<[string], unknown>(`SELECT * FROM memories WHERE id = ?`).get(id)\n );\n\n const projectMap = this.#projects.getProjectsForMemories([id]);\n const events = this.#getEventsForMemories([id]);\n return rowToMemory(updated, projectMap.get(id) ?? [], events.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 { 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 { ProjectRepository } from \"../project/index.js\";\nimport { resolveProject } from \"../scope/index.js\";\n\nexport interface MigrationMeta {\n name: string;\n description: string;\n}\n\nexport interface ScopeToProjectsResult {\n migration: \"scope-to-projects\";\n oldName: string;\n newName: string;\n memoryCount: number;\n}\n\nexport const MIGRATIONS: MigrationMeta[] = [\n {\n name: \"scope-to-projects\",\n description:\n \"Rename the auto-migrated project for the current directory from its generic hash-derived name to the resolved repo/directory name.\",\n },\n];\n\nexport async function runScopeToProjectsMigration(\n projects: ProjectRepository\n): Promise<ScopeToProjectsResult | null> {\n const resolved = await resolveProject();\n const project = projects.getByHash(resolved.hash);\n\n if (project === undefined) {\n return null;\n }\n\n const oldName = project.name;\n const memoryCount = projects.countMemories(project.id);\n projects.rename(project.id, resolved.name);\n\n return {\n migration: \"scope-to-projects\",\n oldName,\n newName: resolved.name,\n memoryCount,\n };\n}\n","import { randomUUID } from \"node:crypto\";\nimport type { DatabaseManager } from \"../db/manager.js\";\nimport { rowToProject } from \"../db/row-types.js\";\nimport { ProjectRowSchema } from \"../schemas.js\";\nimport type { Project, ProjectRow } 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 = ProjectRowSchema.parse(\n this.#db.db\n .prepare<[string], unknown>(`SELECT * FROM projects WHERE scope_hash = ?`)\n .get(hash)\n );\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 countMemories(projectId: string): number {\n const row = this.#db.db\n .prepare<[string], { count: number }>(\n `SELECT COUNT(*) AS count FROM memory_projects WHERE project_id = ?`\n )\n .get(projectId);\n return row?.count ?? 0;\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 { rowToMemory } from \"../db/row-types.js\";\nimport type { EmbeddingService } from \"../embedding/service.js\";\nimport type { MemoryRepository } from \"../memory/repository.js\";\nimport { QueryOptionsSchema } from \"../schemas.js\";\nimport type { Memory, MemoryRow, 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 {\n query,\n type,\n projectHash,\n limit = 10,\n includePinned,\n } = QueryOptionsSchema.parse(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 (!includePinned) {\n whereClauses.push(\"m.pinned = 0\");\n }\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, row.cosine_sim, 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, cosine_sim: number, 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 (\n cosine_sim * 0.4 +\n typeWeight * 0.25 +\n accessCountNorm * 0.2 +\n recencyNorm * 0.1 +\n pinned * 0.05\n );\n }\n}\n","import type { DatabaseManager } from \"../db/manager.js\";\nimport { rowToMemory } from \"../db/row-types.js\";\nimport { MEMORY_TYPE_VALUES, MemoryTypeSchema } from \"../schemas.js\";\nimport type { MemoryRow, MemoryType, SessionContext } 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, synthesis?: string): SessionContext {\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 const parsed = MemoryTypeSchema.safeParse(row.type);\n if (parsed.success) {\n stats[parsed.data] = row.count;\n }\n }\n\n if (synthesis !== undefined && synthesis.length > 0) {\n return { stats, pinnedGlobal: [], pinnedProject: [], synthesis };\n }\n\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 return { stats, pinnedGlobal, pinnedProject };\n }\n}\n","import { createHash, randomUUID } from \"node:crypto\";\nimport type { DatabaseManager } from \"../db/manager.js\";\nimport type { Synthesis } from \"../schemas.js\";\nimport { SynthesisSchema } from \"../schemas.js\";\n\ninterface SynthesisRow {\n id: string;\n scope: string;\n content: string;\n source_memory_hash: string;\n synthesized_at: string;\n expires_at: string;\n in_flight_since: string | null;\n created_at: string;\n updated_at: string;\n}\n\nfunction rowToSynthesis(row: SynthesisRow): Synthesis {\n return SynthesisSchema.parse({\n id: row.id,\n scope: row.scope,\n content: row.content,\n sourceMemoryHash: row.source_memory_hash,\n synthesizedAt: row.synthesized_at,\n expiresAt: row.expires_at,\n inFlightSince: row.in_flight_since,\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n });\n}\n\nconst STALENESS_DAYS = 30;\n\nexport class SynthesisRepository {\n readonly #db: DatabaseManager;\n\n constructor(db: DatabaseManager) {\n this.#db = db;\n }\n\n saveSynthesis(scope: string, content: string, sourceHash: string): Synthesis {\n const now = new Date().toISOString();\n const expiresAt = new Date(Date.now() + STALENESS_DAYS * 24 * 60 * 60 * 1000).toISOString();\n\n const existing = this.#db.db\n .prepare<[string], { id: string }>(\"SELECT id FROM syntheses WHERE scope = ?\")\n .get(scope);\n\n if (existing !== undefined) {\n this.#db.db\n .prepare(\n `UPDATE syntheses\n SET content = ?, source_memory_hash = ?, synthesized_at = ?, expires_at = ?,\n in_flight_since = NULL, updated_at = ?\n WHERE scope = ?`\n )\n .run(content, sourceHash, now, expiresAt, now, scope);\n } else {\n const id = randomUUID();\n this.#db.db\n .prepare(\n `INSERT INTO syntheses\n (id, scope, content, source_memory_hash, synthesized_at, expires_at,\n in_flight_since, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, NULL, ?, ?)`\n )\n .run(id, scope, content, sourceHash, now, expiresAt, now, now);\n }\n\n const row = this.#db.db\n .prepare<[string], SynthesisRow>(\"SELECT * FROM syntheses WHERE scope = ?\")\n .get(scope);\n\n if (row === undefined) throw new Error(`Failed to save synthesis for scope: ${scope}`);\n return rowToSynthesis(row);\n }\n\n getSynthesis(scope: string): Synthesis | undefined {\n const row = this.#db.db\n .prepare<[string], SynthesisRow>(\"SELECT * FROM syntheses WHERE scope = ?\")\n .get(scope);\n return row !== undefined ? rowToSynthesis(row) : undefined;\n }\n\n markInFlight(scope: string): void {\n const now = new Date().toISOString();\n const existing = this.#db.db\n .prepare<[string], { id: string }>(\"SELECT id FROM syntheses WHERE scope = ?\")\n .get(scope);\n\n if (existing !== undefined) {\n this.#db.db\n .prepare(\"UPDATE syntheses SET in_flight_since = ?, updated_at = ? WHERE scope = ?\")\n .run(now, now, scope);\n } else {\n // Create a placeholder row so in_flight_since is tracked before the first synthesis\n const id = randomUUID();\n const placeholder = \"pending\";\n const future = new Date(Date.now() + STALENESS_DAYS * 24 * 60 * 60 * 1000).toISOString();\n this.#db.db\n .prepare(\n `INSERT INTO syntheses\n (id, scope, content, source_memory_hash, synthesized_at, expires_at,\n in_flight_since, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`\n )\n .run(id, scope, placeholder, \"\", now, future, now, now, now);\n }\n }\n\n clearInFlight(scope: string): void {\n const now = new Date().toISOString();\n this.#db.db\n .prepare(\"UPDATE syntheses SET in_flight_since = NULL, updated_at = ? WHERE scope = ?\")\n .run(now, scope);\n }\n\n computeSourceMemoryHash(scope: string): string {\n let contents: { content: string }[];\n\n if (scope === \"global\") {\n contents = this.#db.db\n .prepare<[], { content: string }>(\n `SELECT content FROM memories\n WHERE id NOT IN (SELECT memory_id FROM memory_projects)\n ORDER BY id`\n )\n .all();\n } else {\n contents = this.#db.db\n .prepare<[string], { content: string }>(\n `SELECT m.content 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 = ?\n ORDER BY m.id`\n )\n .all(scope);\n }\n\n return createHash(\"sha256\")\n .update(JSON.stringify(contents.map((r) => r.content)))\n .digest(\"hex\");\n }\n\n getExpiredOrDirtyScopes(): { scope: string; reason: \"expired\" | \"dirty\" | \"missing\" }[] {\n const allScopes = this.getAllActiveScopes();\n const now = new Date().toISOString();\n const results: { scope: string; reason: \"expired\" | \"dirty\" | \"missing\" }[] = [];\n\n for (const scope of allScopes) {\n const row = this.#db.db\n .prepare<[string], SynthesisRow>(\"SELECT * FROM syntheses WHERE scope = ?\")\n .get(scope);\n\n if (row === undefined || (row.content === \"pending\" && row.source_memory_hash === \"\")) {\n results.push({ scope, reason: \"missing\" });\n continue;\n }\n\n if (row.expires_at <= now) {\n results.push({ scope, reason: \"expired\" });\n continue;\n }\n\n const currentHash = this.computeSourceMemoryHash(scope);\n if (currentHash !== row.source_memory_hash) {\n results.push({ scope, reason: \"dirty\" });\n }\n }\n\n return results;\n }\n\n getAllActiveScopes(): string[] {\n const projectScopes = this.#db.db\n .prepare<[], { scope_hash: string }>(\"SELECT DISTINCT scope_hash FROM projects\")\n .all()\n .map((r) => r.scope_hash);\n\n return [\"global\", ...projectScopes];\n }\n\n expireStale(): void {\n const now = new Date().toISOString();\n this.#db.db.prepare(\"DELETE FROM syntheses WHERE expires_at < ?\").run(now);\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.8.0",
3
+ "version": "0.9.1",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",