unforgit 0.5.1 → 0.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,3652 @@
1
+ #!/usr/bin/env node
2
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
3
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
4
+ }) : x)(function(x) {
5
+ if (typeof require !== "undefined") return require.apply(this, arguments);
6
+ throw Error('Dynamic require of "' + x + '" is not supported');
7
+ });
8
+
9
+ // ../../packages/core/dist/index.js
10
+ import OpenAI from "openai";
11
+ import OpenAI2 from "openai";
12
+ var DEFAULT_TTL_SECONDS_BY_TYPE = {
13
+ episodic: 30 * 24 * 60 * 60,
14
+ semantic: void 0,
15
+ procedural: void 0
16
+ };
17
+ var DEFAULT_USAGE_BOOST = {
18
+ enabled: true,
19
+ topKToRecord: 5,
20
+ minUsageCount: 2,
21
+ maxBoost: 0.15,
22
+ halfLifeDays: 30
23
+ };
24
+ var DEFAULT_MAINTENANCE = {
25
+ staleEpisodicDays: 30,
26
+ consolidationThreshold: 0.5,
27
+ consolidationMinGroupSize: 2,
28
+ consolidationMaxGroups: 5,
29
+ promoteRecallCount: 5,
30
+ pinRecallCount: 8,
31
+ dryRunDefault: true,
32
+ autoRunOnStore: true,
33
+ autoRunOnRecall: true,
34
+ debounceMs: 3e4
35
+ };
36
+ function resolveLifecycleConfig(config2) {
37
+ return {
38
+ ttlSecondsByType: {
39
+ ...DEFAULT_TTL_SECONDS_BY_TYPE,
40
+ ...config2?.ttlSecondsByType ?? {}
41
+ },
42
+ usageBoost: {
43
+ ...DEFAULT_USAGE_BOOST,
44
+ ...config2?.usageBoost ?? {}
45
+ },
46
+ maintenance: {
47
+ ...DEFAULT_MAINTENANCE,
48
+ ...config2?.maintenance ?? {}
49
+ }
50
+ };
51
+ }
52
+ function getDefaultTtlSeconds(memoryType, lifecycle) {
53
+ return resolveLifecycleConfig(lifecycle).ttlSecondsByType[memoryType];
54
+ }
55
+ function applyLifecycleDefaults(input, lifecycle) {
56
+ if (input.ttlSeconds !== void 0) {
57
+ return input;
58
+ }
59
+ const ttlSeconds = getDefaultTtlSeconds(input.memoryType, lifecycle);
60
+ if (ttlSeconds === void 0) {
61
+ return input;
62
+ }
63
+ return {
64
+ ...input,
65
+ ttlSeconds
66
+ };
67
+ }
68
+ function isExpiredTtl(createdAt, ttlSeconds, now = /* @__PURE__ */ new Date()) {
69
+ if (!ttlSeconds || ttlSeconds <= 0) {
70
+ return false;
71
+ }
72
+ return createdAt.getTime() + ttlSeconds * 1e3 <= now.getTime();
73
+ }
74
+ function isMemoryExpired(memory, now = /* @__PURE__ */ new Date()) {
75
+ if (memory.status === "deleted") {
76
+ return false;
77
+ }
78
+ return isExpiredTtl(memory.createdAt, memory.ttlSeconds, now);
79
+ }
80
+ function computeUsageBoost(usageCount, lastUsed, lifecycle, now = /* @__PURE__ */ new Date()) {
81
+ const { usageBoost } = resolveLifecycleConfig(lifecycle);
82
+ if (!usageBoost.enabled || usageCount < usageBoost.minUsageCount) {
83
+ return 0;
84
+ }
85
+ const effectiveCount = usageCount - usageBoost.minUsageCount + 1;
86
+ const usageFactor = 1 - Math.exp(-effectiveCount / usageBoost.minUsageCount);
87
+ const ageDays = lastUsed ? Math.max(0, (now.getTime() - lastUsed.getTime()) / (1e3 * 60 * 60 * 24)) : usageBoost.halfLifeDays;
88
+ const recencyFactor = Math.exp(-ageDays / usageBoost.halfLifeDays);
89
+ return Math.min(usageBoost.maxBoost, usageBoost.maxBoost * usageFactor * recencyFactor);
90
+ }
91
+ var LifecycleScheduler = class {
92
+ constructor(runner, options) {
93
+ this.runner = runner;
94
+ this.options = options;
95
+ }
96
+ states = /* @__PURE__ */ new Map();
97
+ schedule(orgId, repoId) {
98
+ const key = `${orgId}:${repoId}`;
99
+ const state = this.states.get(key) ?? {
100
+ running: false,
101
+ pending: false,
102
+ orgId,
103
+ repoId
104
+ };
105
+ state.orgId = orgId;
106
+ state.repoId = repoId;
107
+ if (state.running) {
108
+ state.pending = true;
109
+ this.states.set(key, state);
110
+ return;
111
+ }
112
+ if (state.timer) {
113
+ clearTimeout(state.timer);
114
+ }
115
+ state.timer = setTimeout(() => {
116
+ void this.run(key);
117
+ }, this.options.debounceMs);
118
+ this.states.set(key, state);
119
+ }
120
+ dispose() {
121
+ for (const state of this.states.values()) {
122
+ if (state.timer) {
123
+ clearTimeout(state.timer);
124
+ }
125
+ }
126
+ this.states.clear();
127
+ }
128
+ async run(key) {
129
+ const state = this.states.get(key);
130
+ if (!state) {
131
+ return;
132
+ }
133
+ state.timer = void 0;
134
+ state.running = true;
135
+ this.states.set(key, state);
136
+ try {
137
+ await this.runner(state.orgId, state.repoId);
138
+ } catch (error) {
139
+ this.options.onError?.(error, {
140
+ orgId: state.orgId,
141
+ repoId: state.repoId
142
+ });
143
+ } finally {
144
+ state.running = false;
145
+ if (state.pending) {
146
+ state.pending = false;
147
+ this.states.set(key, state);
148
+ this.schedule(state.orgId, state.repoId);
149
+ } else {
150
+ this.states.delete(key);
151
+ }
152
+ }
153
+ }
154
+ };
155
+ function recencyScore(createdAt) {
156
+ const ageMs = Date.now() - createdAt.getTime();
157
+ const ageDays = ageMs / (1e3 * 60 * 60 * 24);
158
+ return Math.max(0, 1 - ageDays / 365);
159
+ }
160
+ function rankResults(results) {
161
+ return results.sort((a, b) => b.score - a.score);
162
+ }
163
+ function computeCompositeScore(textScore, createdAt, confidence, usageBoost = 0) {
164
+ const recency = recencyScore(createdAt);
165
+ const conf = confidence ?? 0.5;
166
+ return Math.min(1, textScore * 0.55 + recency * 0.15 + conf * 0.15 + usageBoost);
167
+ }
168
+ function computeHybridScore(ftsScore, embeddingScore, createdAt, confidence, usageBoost = 0) {
169
+ const recency = recencyScore(createdAt);
170
+ const conf = confidence ?? 0.5;
171
+ return Math.min(
172
+ 1,
173
+ embeddingScore * 0.45 + ftsScore * 0.15 + recency * 0.125 + conf * 0.125 + usageBoost
174
+ );
175
+ }
176
+ function deduplicateResults(results) {
177
+ const seen = /* @__PURE__ */ new Map();
178
+ for (const r of results) {
179
+ const existing = seen.get(r.id);
180
+ if (!existing || r.score > existing.score) {
181
+ seen.set(r.id, r);
182
+ }
183
+ }
184
+ return Array.from(seen.values());
185
+ }
186
+ function mergeAndRank(localResults, remoteResults, k) {
187
+ const all = [...localResults, ...remoteResults];
188
+ const deduped = deduplicateResults(all);
189
+ const ranked = rankResults(deduped);
190
+ return ranked.slice(0, k);
191
+ }
192
+ var SENSITIVE_PATTERNS = [
193
+ /password/i,
194
+ /secret/i,
195
+ /api[_-]?key/i,
196
+ /token/i,
197
+ /credential/i,
198
+ /private[_-]?key/i,
199
+ /-----BEGIN/
200
+ ];
201
+ var RULE_LIKE_TAGS = /* @__PURE__ */ new Set([
202
+ "decision",
203
+ "adr",
204
+ "playbook",
205
+ "gotcha",
206
+ "convention",
207
+ "rule",
208
+ "standard",
209
+ "process",
210
+ "checklist"
211
+ ]);
212
+ function containsSensitive(text) {
213
+ return SENSITIVE_PATTERNS.some((p) => p.test(text));
214
+ }
215
+ function hasRuleLikeTags(tags) {
216
+ return tags.some((t) => RULE_LIKE_TAGS.has(t.toLowerCase()));
217
+ }
218
+ function resolveVisibility(input) {
219
+ if (containsSensitive(input.text)) {
220
+ return { visibility: "private" };
221
+ }
222
+ if (input.memoryType === "episodic" && !input.sourceRefs) {
223
+ return { visibility: "private" };
224
+ }
225
+ const hasSource = input.sourceRefs && Object.keys(input.sourceRefs).length > 0;
226
+ const tags = input.tags ?? [];
227
+ if ((input.memoryType === "semantic" || input.memoryType === "procedural") && (hasSource || hasRuleLikeTags(tags))) {
228
+ return { visibility: "repo" };
229
+ }
230
+ return { visibility: "private", suggestion: "promote" };
231
+ }
232
+ var EMBEDDING_MODEL = "text-embedding-3-small";
233
+ var cachedClient = null;
234
+ function isOpenAIConfigured(apiKey) {
235
+ const key = apiKey ?? process.env.OPENAI_API_KEY;
236
+ return !!key && key !== "sk-your-api-key-here" && key.startsWith("sk-");
237
+ }
238
+ function getClient(apiKey) {
239
+ const key = apiKey ?? process.env.OPENAI_API_KEY;
240
+ if (!key) {
241
+ throw new Error(
242
+ "OpenAI API key not configured. Set OPENAI_API_KEY environment variable or pass apiKey option. Semantic search features are disabled. Unforgit will use FTS-only search."
243
+ );
244
+ }
245
+ if (!cachedClient || apiKey) {
246
+ cachedClient = new OpenAI({ apiKey: key });
247
+ }
248
+ return cachedClient;
249
+ }
250
+ async function generateEmbedding(text, config2) {
251
+ const client = getClient(config2?.apiKey);
252
+ const model = config2?.model ?? EMBEDDING_MODEL;
253
+ const cleanText = text.trim().slice(0, 8e3);
254
+ const response = await client.embeddings.create({
255
+ model,
256
+ input: cleanText
257
+ });
258
+ const data = response.data[0];
259
+ if (!data?.embedding) {
260
+ throw new Error("OpenAI returned empty embedding");
261
+ }
262
+ return {
263
+ embedding: data.embedding,
264
+ model,
265
+ tokensUsed: response.usage?.total_tokens ?? 0
266
+ };
267
+ }
268
+ function cosineSimilarity(a, b) {
269
+ if (a.length !== b.length) {
270
+ throw new Error(
271
+ `Embedding dimensions mismatch: ${a.length} vs ${b.length}`
272
+ );
273
+ }
274
+ let dotProduct = 0;
275
+ let normA = 0;
276
+ let normB = 0;
277
+ for (let i = 0; i < a.length; i++) {
278
+ dotProduct += a[i] * b[i];
279
+ normA += a[i] * a[i];
280
+ normB += b[i] * b[i];
281
+ }
282
+ const magnitude = Math.sqrt(normA) * Math.sqrt(normB);
283
+ if (magnitude === 0) return 0;
284
+ return dotProduct / magnitude;
285
+ }
286
+ function serializeEmbedding(embedding) {
287
+ const buffer = Buffer.alloc(embedding.length * 4);
288
+ for (let i = 0; i < embedding.length; i++) {
289
+ buffer.writeFloatLE(embedding[i], i * 4);
290
+ }
291
+ return buffer;
292
+ }
293
+ function deserializeEmbedding(buffer) {
294
+ const embedding = [];
295
+ const count = buffer.length / 4;
296
+ for (let i = 0; i < count; i++) {
297
+ embedding.push(buffer.readFloatLE(i * 4));
298
+ }
299
+ return embedding;
300
+ }
301
+ var CONSOLIDATION_PROMPT = `You are consolidating multiple related memories into a single unified memory.
302
+
303
+ Source memories:
304
+ {{MEMORIES}}
305
+
306
+ Instructions:
307
+ 1. Identify the core knowledge/insight shared across these memories
308
+ 2. Merge complementary information without losing important details
309
+ 3. Remove redundancy while preserving unique facts
310
+ 4. Keep the consolidated text concise (ideally under 200 words)
311
+ 5. Maintain technical accuracy
312
+ 6. Write in the same language as the source memories
313
+
314
+ Output format (JSON):
315
+ {
316
+ "text": "The consolidated memory text",
317
+ "suggestedTags": ["tag1", "tag2"],
318
+ "suggestedType": "semantic" | "procedural" | "episodic"
319
+ }
320
+
321
+ Output only valid JSON, nothing else.`;
322
+ function formatMemoriesForPrompt(memories) {
323
+ return memories.map(
324
+ (m, i) => `${i + 1}. [${m.type}] ${m.text}
325
+ Tags: ${m.tags.length > 0 ? m.tags.join(", ") : "none"}`
326
+ ).join("\n\n");
327
+ }
328
+ function inferMemoryType(memories) {
329
+ const hasProcedural = memories.some((m) => m.type === "procedural");
330
+ const hasSemantic = memories.some((m) => m.type === "semantic");
331
+ if (hasProcedural) return "procedural";
332
+ if (hasSemantic) return "semantic";
333
+ return "episodic";
334
+ }
335
+ function mergeTags(memories) {
336
+ const tagSet = /* @__PURE__ */ new Set();
337
+ for (const m of memories) {
338
+ for (const tag of m.tags) {
339
+ tagSet.add(tag);
340
+ }
341
+ }
342
+ return Array.from(tagSet);
343
+ }
344
+ async function generateConsolidatedText(input, options) {
345
+ const apiKey = options?.apiKey ?? process.env.OPENAI_API_KEY;
346
+ if (!apiKey) {
347
+ throw new Error(
348
+ "OpenAI API key not configured. Set OPENAI_API_KEY environment variable."
349
+ );
350
+ }
351
+ const client = new OpenAI2({ apiKey });
352
+ const model = options?.model ?? "gpt-5.4";
353
+ const memoriesText = formatMemoriesForPrompt(input.memories);
354
+ const prompt = CONSOLIDATION_PROMPT.replace("{{MEMORIES}}", memoriesText);
355
+ const response = await client.chat.completions.create({
356
+ model,
357
+ messages: [
358
+ {
359
+ role: "user",
360
+ content: prompt
361
+ }
362
+ ],
363
+ temperature: 0.3,
364
+ max_completion_tokens: 1e3
365
+ });
366
+ const content = response.choices[0]?.message?.content;
367
+ if (!content) {
368
+ throw new Error("OpenAI returned empty response");
369
+ }
370
+ try {
371
+ const parsed = JSON.parse(content);
372
+ if (!parsed.text || typeof parsed.text !== "string") {
373
+ throw new Error("Invalid response: missing text field");
374
+ }
375
+ const validTypes = ["episodic", "semantic", "procedural"];
376
+ const suggestedType = parsed.suggestedType && validTypes.includes(parsed.suggestedType) ? parsed.suggestedType : inferMemoryType(input.memories);
377
+ return {
378
+ text: parsed.text,
379
+ suggestedTags: Array.isArray(parsed.suggestedTags) ? parsed.suggestedTags.filter((t) => typeof t === "string") : mergeTags(input.memories),
380
+ suggestedType
381
+ };
382
+ } catch (_parseError) {
383
+ const textMatch = content.match(/"text"\s*:\s*"([^"]+)"/);
384
+ if (textMatch) {
385
+ return {
386
+ text: textMatch[1],
387
+ suggestedTags: mergeTags(input.memories),
388
+ suggestedType: inferMemoryType(input.memories)
389
+ };
390
+ }
391
+ return {
392
+ text: content.trim(),
393
+ suggestedTags: mergeTags(input.memories),
394
+ suggestedType: inferMemoryType(input.memories)
395
+ };
396
+ }
397
+ }
398
+ function memoriesToConsolidationInput(memories) {
399
+ return {
400
+ memories: memories.map((m) => ({
401
+ text: m.text,
402
+ type: m.memoryType,
403
+ tags: m.tags
404
+ }))
405
+ };
406
+ }
407
+ var QUALITY_WEIGHTS = {
408
+ textQuality: 0.2,
409
+ recallCount: 0.25,
410
+ consolidationStatus: 0.1,
411
+ age: 0.15,
412
+ hasLinks: 0.1,
413
+ hasTags: 0.1,
414
+ hasEmbedding: 0.1
415
+ };
416
+ function computeTextQuality(text) {
417
+ const length = text.trim().length;
418
+ if (length < 20) return 0.2;
419
+ if (length < 50) return 0.4;
420
+ if (length < 100) return 0.6;
421
+ if (length < 300) return 0.9;
422
+ if (length < 500) return 1;
423
+ if (length < 1e3) return 0.9;
424
+ return 0.7;
425
+ }
426
+ function computeRecallScore(recallCount) {
427
+ if (recallCount === 0) return 0;
428
+ if (recallCount < 3) return 0.3;
429
+ if (recallCount < 10) return 0.6;
430
+ if (recallCount < 25) return 0.8;
431
+ return 1;
432
+ }
433
+ function computeAgeScore(daysSinceCreation, daysSinceLastRecall) {
434
+ if (daysSinceLastRecall !== null && daysSinceLastRecall < 7) {
435
+ return 1;
436
+ }
437
+ if (daysSinceCreation < 7) return 1;
438
+ if (daysSinceCreation < 30) return 0.9;
439
+ if (daysSinceCreation < 90) return 0.7;
440
+ if (daysSinceCreation < 180) return 0.5;
441
+ if (daysSinceCreation < 365) return 0.3;
442
+ return 0.1;
443
+ }
444
+ function computeConsolidationScore(memory) {
445
+ if (memory.isConsolidation) return 1;
446
+ if (memory.status === "superseded") return 0.3;
447
+ if (memory.status === "deprecated") return 0.1;
448
+ return 0.7;
449
+ }
450
+ function computeQualityScore(memory, stats) {
451
+ const factors = {
452
+ textQuality: computeTextQuality(memory.text),
453
+ recallCount: computeRecallScore(stats.recallCount),
454
+ consolidationStatus: computeConsolidationScore(memory),
455
+ age: computeAgeScore(stats.daysSinceCreation, stats.daysSinceLastRecall),
456
+ hasLinks: stats.linkCount > 0 ? 1 : 0.3,
457
+ hasTags: memory.tags.length > 0 ? 1 : 0.3,
458
+ hasEmbedding: stats.hasEmbedding ? 1 : 0.5
459
+ };
460
+ const overall = factors.textQuality * QUALITY_WEIGHTS.textQuality + factors.recallCount * QUALITY_WEIGHTS.recallCount + factors.consolidationStatus * QUALITY_WEIGHTS.consolidationStatus + factors.age * QUALITY_WEIGHTS.age + factors.hasLinks * QUALITY_WEIGHTS.hasLinks + factors.hasTags * QUALITY_WEIGHTS.hasTags + factors.hasEmbedding * QUALITY_WEIGHTS.hasEmbedding;
461
+ const suggestions = [];
462
+ if (factors.textQuality < 0.5) {
463
+ suggestions.push("Consider expanding this memory with more detail");
464
+ }
465
+ if (factors.recallCount < 0.3 && stats.daysSinceCreation > 30) {
466
+ suggestions.push("This memory has never been recalled - consider deprecating if no longer relevant");
467
+ }
468
+ if (factors.hasLinks < 0.5) {
469
+ suggestions.push("Consider linking this memory to related memories");
470
+ }
471
+ if (factors.hasTags < 0.5) {
472
+ suggestions.push("Add tags to improve discoverability");
473
+ }
474
+ if (!stats.hasEmbedding) {
475
+ suggestions.push("Generate embedding for better semantic search");
476
+ }
477
+ if (stats.daysSinceCreation > 180 && stats.daysSinceLastRecall === null) {
478
+ suggestions.push("Old memory with no recalls - review for deprecation");
479
+ }
480
+ return {
481
+ overall: Math.round(overall * 100) / 100,
482
+ factors,
483
+ suggestions
484
+ };
485
+ }
486
+ function getHealthStatus(score) {
487
+ if (score >= 0.7) return "healthy";
488
+ if (score >= 0.4) return "needs_attention";
489
+ return "critical";
490
+ }
491
+ function computeRepositoryHealth(memories) {
492
+ if (memories.length === 0) {
493
+ return {
494
+ overallScore: 1,
495
+ status: "healthy",
496
+ memoryCounts: { total: 0, healthy: 0, needs_attention: 0, critical: 0 },
497
+ topIssues: []
498
+ };
499
+ }
500
+ const scores = memories.map(
501
+ ({ memory, stats }) => computeQualityScore(memory, stats)
502
+ );
503
+ const totalScore = scores.reduce((sum, s) => sum + s.overall, 0);
504
+ const overallScore = Math.round(totalScore / scores.length * 100) / 100;
505
+ const counts = { healthy: 0, needs_attention: 0, critical: 0 };
506
+ for (const score of scores) {
507
+ const status = getHealthStatus(score.overall);
508
+ counts[status]++;
509
+ }
510
+ const issueCount = {};
511
+ for (const score of scores) {
512
+ for (const suggestion of score.suggestions) {
513
+ issueCount[suggestion] = (issueCount[suggestion] || 0) + 1;
514
+ }
515
+ }
516
+ const topIssues = Object.entries(issueCount).sort((a, b) => b[1] - a[1]).slice(0, 5).map(([description, count]) => ({
517
+ type: categorizeIssue(description),
518
+ count,
519
+ description
520
+ }));
521
+ return {
522
+ overallScore,
523
+ status: getHealthStatus(overallScore),
524
+ memoryCounts: {
525
+ total: memories.length,
526
+ ...counts
527
+ },
528
+ topIssues
529
+ };
530
+ }
531
+ function categorizeIssue(description) {
532
+ if (description.includes("tag")) return "tagging";
533
+ if (description.includes("link")) return "linking";
534
+ if (description.includes("embedding")) return "embedding";
535
+ if (description.includes("deprecat") || description.includes("recall")) return "maintenance";
536
+ if (description.includes("detail") || description.includes("expand")) return "content";
537
+ return "other";
538
+ }
539
+ function generateSuggestions(store, orgId, repoId, options) {
540
+ const maxSuggestions = options?.maxSuggestions ?? 20;
541
+ const suggestions = [];
542
+ const memories = store.list({
543
+ orgId,
544
+ repoId,
545
+ status: ["active"],
546
+ limit: 500
547
+ });
548
+ const usageStats = store.getUsageStats(orgId, repoId);
549
+ const usageMap = new Map(usageStats.map((s) => [s.memoryId, s]));
550
+ const memoryData = [];
551
+ for (const memory of memories) {
552
+ const usage = usageMap.get(memory.id);
553
+ const links = store.getLinks({ memoryId: memory.id });
554
+ const hasEmbedding = store.hasEmbedding(memory.id);
555
+ const stats = {
556
+ recallCount: usage?.count ?? 0,
557
+ linkCount: links.length,
558
+ hasEmbedding,
559
+ daysSinceCreation: Math.floor(
560
+ (Date.now() - memory.createdAt.getTime()) / (1e3 * 60 * 60 * 24)
561
+ ),
562
+ daysSinceLastRecall: usage ? Math.floor(
563
+ (Date.now() - usage.lastUsed.getTime()) / (1e3 * 60 * 60 * 24)
564
+ ) : null
565
+ };
566
+ const quality = computeQualityScore(memory, stats);
567
+ memoryData.push({ memory, stats, quality });
568
+ }
569
+ const similarPairs = findSimilarMemoryPairs(store, memoryData, orgId, repoId);
570
+ for (const pair of similarPairs.slice(0, 5)) {
571
+ suggestions.push({
572
+ id: `consolidate-${pair.id1.slice(0, 8)}-${pair.id2.slice(0, 8)}`,
573
+ type: "consolidate",
574
+ priority: pair.similarity > 0.8 ? "high" : "medium",
575
+ memoryIds: [pair.id1, pair.id2],
576
+ reason: `These memories are ${Math.round(pair.similarity * 100)}% similar and could be merged`,
577
+ confidence: pair.similarity,
578
+ action: {
579
+ command: `unforgit merge ${pair.id1} ${pair.id2}`,
580
+ description: "Merge these memories into one"
581
+ }
582
+ });
583
+ }
584
+ const staleMemories = memoryData.filter(
585
+ ({ stats, quality }) => stats.daysSinceCreation > 90 && stats.recallCount === 0 && quality.overall < 0.5
586
+ );
587
+ for (const { memory } of staleMemories.slice(0, 5)) {
588
+ suggestions.push({
589
+ id: `deprecate-${memory.id.slice(0, 8)}`,
590
+ type: "deprecate",
591
+ priority: "medium",
592
+ memoryIds: [memory.id],
593
+ reason: "No recalls in 90+ days with low quality score",
594
+ confidence: 0.7,
595
+ action: {
596
+ command: `unforgit deprecate ${memory.id}`,
597
+ description: "Mark as deprecated"
598
+ }
599
+ });
600
+ }
601
+ const untagged = memoryData.filter(({ memory }) => memory.tags.length === 0);
602
+ if (untagged.length > 0) {
603
+ const ids = untagged.slice(0, 10).map(({ memory }) => memory.id);
604
+ suggestions.push({
605
+ id: "add-tags-batch",
606
+ type: "add_tags",
607
+ priority: "low",
608
+ memoryIds: ids,
609
+ reason: `${untagged.length} memories have no tags`,
610
+ confidence: 0.9,
611
+ action: {
612
+ command: "unforgit web",
613
+ description: "Open dashboard to add tags"
614
+ }
615
+ });
616
+ }
617
+ const unlinked = memoryData.filter(
618
+ ({ stats, memory }) => stats.linkCount === 0 && !memory.isConsolidation && stats.daysSinceCreation > 7
619
+ );
620
+ if (unlinked.length > 5) {
621
+ suggestions.push({
622
+ id: "add-links-batch",
623
+ type: "add_links",
624
+ priority: "low",
625
+ memoryIds: unlinked.slice(0, 10).map(({ memory }) => memory.id),
626
+ reason: `${unlinked.length} memories are isolated (no links)`,
627
+ confidence: 0.8,
628
+ action: {
629
+ command: "unforgit web",
630
+ description: "Open graph view to create links"
631
+ }
632
+ });
633
+ }
634
+ const withoutEmbedding = memoryData.filter(({ stats }) => !stats.hasEmbedding);
635
+ if (withoutEmbedding.length > 0) {
636
+ suggestions.push({
637
+ id: "generate-embeddings",
638
+ type: "generate_embedding",
639
+ priority: withoutEmbedding.length > 10 ? "high" : "medium",
640
+ memoryIds: withoutEmbedding.map(({ memory }) => memory.id),
641
+ reason: `${withoutEmbedding.length} memories lack embeddings for semantic search`,
642
+ confidence: 1,
643
+ action: {
644
+ command: "unforgit embeddings backfill",
645
+ description: "Generate embeddings for all memories"
646
+ }
647
+ });
648
+ }
649
+ const popularPrivate = memoryData.filter(
650
+ ({ memory, stats }) => memory.visibility === "private" && stats.recallCount >= 5
651
+ );
652
+ for (const { memory, stats } of popularPrivate.slice(0, 3)) {
653
+ suggestions.push({
654
+ id: `promote-${memory.id.slice(0, 8)}`,
655
+ type: "promote",
656
+ priority: "medium",
657
+ memoryIds: [memory.id],
658
+ reason: `Private memory with ${stats.recallCount} recalls - consider sharing with team`,
659
+ confidence: 0.75,
660
+ action: {
661
+ command: `unforgit promote ${memory.id}`,
662
+ description: "Promote to shared visibility"
663
+ }
664
+ });
665
+ }
666
+ const sorted = suggestions.sort((a, b) => {
667
+ const priorityOrder = { high: 0, medium: 1, low: 2 };
668
+ if (priorityOrder[a.priority] !== priorityOrder[b.priority]) {
669
+ return priorityOrder[a.priority] - priorityOrder[b.priority];
670
+ }
671
+ return b.confidence - a.confidence;
672
+ }).slice(0, maxSuggestions);
673
+ return {
674
+ suggestions: sorted,
675
+ stats: {
676
+ totalMemories: memories.length,
677
+ memoriesAnalyzed: memoryData.length,
678
+ suggestionsGenerated: sorted.length
679
+ }
680
+ };
681
+ }
682
+ function findSimilarMemoryPairs(store, memoryData, orgId, repoId) {
683
+ const pairs = [];
684
+ const seen = /* @__PURE__ */ new Set();
685
+ for (const { memory } of memoryData.slice(0, 50)) {
686
+ try {
687
+ const similar = store.findSimilar({
688
+ orgId,
689
+ repoId,
690
+ memoryId: memory.id,
691
+ threshold: 0.6,
692
+ k: 3
693
+ });
694
+ for (const match of similar) {
695
+ const pairKey = [memory.id, match.id].sort().join("-");
696
+ if (seen.has(pairKey)) continue;
697
+ seen.add(pairKey);
698
+ pairs.push({
699
+ id1: memory.id,
700
+ id2: match.id,
701
+ similarity: match.score
702
+ });
703
+ }
704
+ } catch {
705
+ continue;
706
+ }
707
+ }
708
+ return pairs.sort((a, b) => b.similarity - a.similarity);
709
+ }
710
+ function persistReviewableSuggestions(store, orgId, repoId, suggestions, options = {}) {
711
+ const existingPending = store.listCurationSuggestions({
712
+ orgId,
713
+ repoId,
714
+ status: ["pending"],
715
+ limit: 500
716
+ });
717
+ const existingKeys = new Set(
718
+ existingPending.map(
719
+ (suggestion) => reviewableSuggestionKey(suggestion.type, suggestion.memoryIds)
720
+ )
721
+ );
722
+ let created = 0;
723
+ let skippedExisting = 0;
724
+ for (const suggestion of suggestions) {
725
+ const key = reviewableSuggestionKey(suggestion.type, suggestion.memoryIds);
726
+ if (existingKeys.has(key)) {
727
+ skippedExisting++;
728
+ continue;
729
+ }
730
+ store.createCurationSuggestion({
731
+ orgId,
732
+ repoId,
733
+ type: suggestion.type,
734
+ priority: suggestion.priority,
735
+ memoryIds: suggestion.memoryIds,
736
+ reason: suggestion.reason,
737
+ confidence: suggestion.confidence,
738
+ createdBy: options.createdBy,
739
+ payload: {
740
+ sourceSuggestionId: suggestion.id,
741
+ ...suggestion.action ? { action: suggestion.action } : {}
742
+ }
743
+ });
744
+ existingKeys.add(key);
745
+ created++;
746
+ }
747
+ return { created, skippedExisting };
748
+ }
749
+ function reviewableSuggestionKey(type, memoryIds) {
750
+ return `${type}:${[...memoryIds].sort().join(",")}`;
751
+ }
752
+ function formatSuggestion(suggestion) {
753
+ const priorityEmoji = {
754
+ high: "\u{1F534}",
755
+ medium: "\u{1F7E1}",
756
+ low: "\u{1F7E2}"
757
+ };
758
+ const lines = [
759
+ `${priorityEmoji[suggestion.priority]} [${suggestion.type}] ${suggestion.reason}`,
760
+ ` Confidence: ${Math.round(suggestion.confidence * 100)}%`,
761
+ ` Memories: ${suggestion.memoryIds.map((id) => id.slice(0, 8)).join(", ")}`
762
+ ];
763
+ if (suggestion.action) {
764
+ lines.push(` Action: ${suggestion.action.command}`);
765
+ }
766
+ return lines.join("\n");
767
+ }
768
+ function findConsolidationCandidates(store, orgId, repoId, options = {}) {
769
+ const {
770
+ threshold = 0.4,
771
+ minGroupSize = 2,
772
+ maxGroups = 10,
773
+ types,
774
+ excludeConsolidations = true
775
+ } = options;
776
+ const memories = store.list({
777
+ orgId,
778
+ repoId,
779
+ status: ["active"],
780
+ types,
781
+ limit: 1e3
782
+ });
783
+ const filteredMemories = excludeConsolidations ? memories.filter((m) => !m.isConsolidation) : memories;
784
+ if (filteredMemories.length < 2) {
785
+ return {
786
+ candidates: [],
787
+ totalMemoriesScanned: filteredMemories.length,
788
+ totalCandidateGroups: 0
789
+ };
790
+ }
791
+ const similarityScores = /* @__PURE__ */ new Map();
792
+ const memoryMap = new Map(filteredMemories.map((m) => [m.id, m]));
793
+ for (const memory of filteredMemories) {
794
+ try {
795
+ const similar = store.findSimilar({
796
+ orgId,
797
+ repoId,
798
+ memoryId: memory.id,
799
+ threshold,
800
+ k: 10
801
+ });
802
+ for (const sim of similar) {
803
+ const targetMemory = memoryMap.get(sim.id);
804
+ if (!targetMemory) continue;
805
+ if (excludeConsolidations && targetMemory.isConsolidation) continue;
806
+ if (!similarityScores.has(memory.id)) {
807
+ similarityScores.set(memory.id, /* @__PURE__ */ new Map());
808
+ }
809
+ similarityScores.get(memory.id).set(sim.id, sim.score);
810
+ }
811
+ } catch {
812
+ continue;
813
+ }
814
+ }
815
+ const used = /* @__PURE__ */ new Set();
816
+ const groups = [];
817
+ const sortedMemories = [...filteredMemories].sort((a, b) => {
818
+ const aCount = similarityScores.get(a.id)?.size ?? 0;
819
+ const bCount = similarityScores.get(b.id)?.size ?? 0;
820
+ return bCount - aCount;
821
+ });
822
+ for (const seed of sortedMemories) {
823
+ if (used.has(seed.id)) continue;
824
+ const seedSimilar = similarityScores.get(seed.id);
825
+ if (!seedSimilar || seedSimilar.size === 0) continue;
826
+ const group = [seed.id];
827
+ let totalScore = 0;
828
+ let scoreCount = 0;
829
+ const candidates2 = Array.from(seedSimilar.entries()).filter(([id]) => !used.has(id)).sort((a, b) => b[1] - a[1]);
830
+ for (const [candidateId, score] of candidates2) {
831
+ if (group.length >= 5) break;
832
+ let isCompatible = true;
833
+ for (const memberId of group) {
834
+ if (memberId === seed.id) continue;
835
+ const memberSimilar = similarityScores.get(memberId);
836
+ const reverseScore = memberSimilar?.get(candidateId);
837
+ const candidateSimilar = similarityScores.get(candidateId);
838
+ const forwardScore = candidateSimilar?.get(memberId);
839
+ const pairScore = Math.max(reverseScore ?? 0, forwardScore ?? 0);
840
+ if (pairScore < threshold * 0.8) {
841
+ isCompatible = false;
842
+ break;
843
+ }
844
+ }
845
+ if (isCompatible) {
846
+ group.push(candidateId);
847
+ totalScore += score;
848
+ scoreCount++;
849
+ }
850
+ }
851
+ if (group.length >= minGroupSize) {
852
+ for (const id of group) {
853
+ used.add(id);
854
+ }
855
+ groups.push({
856
+ ids: group,
857
+ avgScore: scoreCount > 0 ? totalScore / scoreCount : threshold
858
+ });
859
+ }
860
+ }
861
+ const candidates = [];
862
+ for (const group of groups) {
863
+ const groupMemories = group.ids.map((id) => memoryMap.get(id)).filter((m) => m !== void 0);
864
+ if (groupMemories.length < minGroupSize) continue;
865
+ const allTags = /* @__PURE__ */ new Set();
866
+ for (const m of groupMemories) {
867
+ for (const tag of m.tags) {
868
+ allTags.add(tag);
869
+ }
870
+ }
871
+ const typeCount = {};
872
+ for (const m of groupMemories) {
873
+ typeCount[m.memoryType] = (typeCount[m.memoryType] || 0) + 1;
874
+ }
875
+ const dominantType = Object.entries(typeCount).sort(
876
+ (a, b) => b[1] - a[1]
877
+ )[0]?.[0];
878
+ candidates.push({
879
+ memories: groupMemories.sort(
880
+ (a, b) => b.createdAt.getTime() - a.createdAt.getTime()
881
+ ),
882
+ reason: `${groupMemories.length} similar ${dominantType ?? "mixed"} memories with avg similarity ${group.avgScore.toFixed(2)}`,
883
+ suggestedTags: Array.from(allTags),
884
+ averageScore: group.avgScore
885
+ });
886
+ }
887
+ candidates.sort((a, b) => {
888
+ if (b.memories.length !== a.memories.length) {
889
+ return b.memories.length - a.memories.length;
890
+ }
891
+ return b.averageScore - a.averageScore;
892
+ });
893
+ return {
894
+ candidates: candidates.slice(0, maxGroups),
895
+ totalMemoriesScanned: filteredMemories.length,
896
+ totalCandidateGroups: candidates.length
897
+ };
898
+ }
899
+ async function executeConsolidation(store, candidate, orgId, repoId, options = {}) {
900
+ const { apiKey, model, preserveOriginals = true } = options;
901
+ const input = memoriesToConsolidationInput(candidate.memories);
902
+ const llmResult = await generateConsolidatedText(input, { apiKey, model });
903
+ const sourceIds = candidate.memories.map((m) => m.id);
904
+ const result = store.consolidateMemories({
905
+ orgId,
906
+ repoId,
907
+ sourceIds,
908
+ consolidatedText: llmResult.text,
909
+ memoryType: llmResult.suggestedType,
910
+ tags: llmResult.suggestedTags,
911
+ preserveOriginals
912
+ });
913
+ return {
914
+ consolidatedId: result.consolidatedId,
915
+ sourceIds,
916
+ generatedText: llmResult.text,
917
+ suggestedTags: llmResult.suggestedTags,
918
+ memoryType: llmResult.suggestedType
919
+ };
920
+ }
921
+ function formatCandidatePreview(candidate) {
922
+ const lines = [];
923
+ lines.push(`Group: ${candidate.reason}`);
924
+ lines.push(`Tags: ${candidate.suggestedTags.join(", ") || "none"}`);
925
+ lines.push("Memories:");
926
+ for (const mem of candidate.memories) {
927
+ const preview2 = mem.text.length > 80 ? mem.text.slice(0, 80) + "..." : mem.text;
928
+ lines.push(` - [${mem.memoryType}] ${mem.id.slice(0, 8)}: ${preview2}`);
929
+ }
930
+ return lines.join("\n");
931
+ }
932
+ var AUTO_LINK_STOP_WORDS = /* @__PURE__ */ new Set([
933
+ "the",
934
+ "a",
935
+ "an",
936
+ "is",
937
+ "are",
938
+ "was",
939
+ "were",
940
+ "be",
941
+ "been",
942
+ "being",
943
+ "have",
944
+ "has",
945
+ "had",
946
+ "do",
947
+ "does",
948
+ "did",
949
+ "will",
950
+ "would",
951
+ "could",
952
+ "should",
953
+ "may",
954
+ "might",
955
+ "must",
956
+ "shall",
957
+ "can",
958
+ "to",
959
+ "of",
960
+ "in",
961
+ "for",
962
+ "on",
963
+ "with",
964
+ "at",
965
+ "by",
966
+ "from",
967
+ "as",
968
+ "into",
969
+ "through",
970
+ "during",
971
+ "before",
972
+ "after",
973
+ "above",
974
+ "below",
975
+ "between",
976
+ "under",
977
+ "again",
978
+ "further",
979
+ "then",
980
+ "once",
981
+ "here",
982
+ "there",
983
+ "when",
984
+ "where",
985
+ "why",
986
+ "how",
987
+ "all",
988
+ "each",
989
+ "few",
990
+ "more",
991
+ "most",
992
+ "other",
993
+ "some",
994
+ "such",
995
+ "no",
996
+ "nor",
997
+ "not",
998
+ "only",
999
+ "own",
1000
+ "same",
1001
+ "so",
1002
+ "than",
1003
+ "too",
1004
+ "very",
1005
+ "just",
1006
+ "and",
1007
+ "but",
1008
+ "if",
1009
+ "or",
1010
+ "because",
1011
+ "until",
1012
+ "while",
1013
+ "this",
1014
+ "that",
1015
+ "these",
1016
+ "those",
1017
+ "it",
1018
+ "its"
1019
+ ]);
1020
+ function buildAutoLinkQuery(text, maxTerms = 10) {
1021
+ const terms = text.toLowerCase().replace(/[_-]/g, " ").replace(/[^\w\s]/g, " ").split(/\s+/).filter((word) => word.length > 2).filter((word) => !AUTO_LINK_STOP_WORDS.has(word)).filter((word) => word !== "or" && word !== "and");
1022
+ const uniqueTerms = [...new Set(terms)].slice(0, maxTerms);
1023
+ if (uniqueTerms.length === 0) {
1024
+ return void 0;
1025
+ }
1026
+ return uniqueTerms.join(" ");
1027
+ }
1028
+ function getNotifications(store, orgId, repoId) {
1029
+ const notifications = [];
1030
+ const now = /* @__PURE__ */ new Date();
1031
+ const syncSummary = store.getSyncSummary(orgId, repoId);
1032
+ if (syncSummary.conflicts > 0) {
1033
+ notifications.push({
1034
+ id: "conflicts-pending",
1035
+ type: "conflicts_pending",
1036
+ priority: "high",
1037
+ title: "Sync Conflicts",
1038
+ message: `You have ${syncSummary.conflicts} unresolved sync conflict(s) that need attention.`,
1039
+ action: {
1040
+ command: "unforgit status",
1041
+ description: "View conflicts"
1042
+ },
1043
+ createdAt: now
1044
+ });
1045
+ }
1046
+ const embeddingStats = store.getEmbeddingStats(orgId, repoId);
1047
+ if (embeddingStats.withoutEmbedding > 10) {
1048
+ notifications.push({
1049
+ id: "embeddings-missing",
1050
+ type: "embeddings_missing",
1051
+ priority: "medium",
1052
+ title: "Missing Embeddings",
1053
+ message: `${embeddingStats.withoutEmbedding} memories lack embeddings. Semantic search quality is reduced.`,
1054
+ action: {
1055
+ command: "unforgit embeddings backfill",
1056
+ description: "Generate missing embeddings"
1057
+ },
1058
+ createdAt: now
1059
+ });
1060
+ }
1061
+ const suggestions = generateSuggestions(store, orgId, repoId, { maxSuggestions: 10 });
1062
+ const highPrioritySuggestions = suggestions.suggestions.filter(
1063
+ (s) => s.priority === "high"
1064
+ ).length;
1065
+ if (highPrioritySuggestions > 0) {
1066
+ notifications.push({
1067
+ id: "suggestions-high-priority",
1068
+ type: "pending_suggestions",
1069
+ priority: "medium",
1070
+ title: "Curation Suggestions",
1071
+ message: `${highPrioritySuggestions} high-priority curation suggestion(s) available.`,
1072
+ action: {
1073
+ command: "unforgit web",
1074
+ description: "Open curation dashboard"
1075
+ },
1076
+ createdAt: now
1077
+ });
1078
+ }
1079
+ if (syncSummary.pendingPush > 20) {
1080
+ notifications.push({
1081
+ id: "sync-stale",
1082
+ type: "sync_stale",
1083
+ priority: "low",
1084
+ title: "Pending Sync",
1085
+ message: `${syncSummary.pendingPush} memories waiting to be pushed to remote.`,
1086
+ action: {
1087
+ command: "unforgit push",
1088
+ description: "Push changes to remote"
1089
+ },
1090
+ createdAt: now
1091
+ });
1092
+ }
1093
+ const unusedMemories = store.getUnusedMemories(orgId, repoId, 90);
1094
+ if (unusedMemories.length > 10) {
1095
+ notifications.push({
1096
+ id: "maintenance-unused",
1097
+ type: "maintenance_needed",
1098
+ priority: "low",
1099
+ title: "Maintenance Recommended",
1100
+ message: `${unusedMemories.length} memories haven't been recalled in 90+ days. Consider reviewing or deprecating.`,
1101
+ action: {
1102
+ command: "unforgit web",
1103
+ description: "Open curation dashboard"
1104
+ },
1105
+ createdAt: now
1106
+ });
1107
+ }
1108
+ notifications.sort((a, b) => {
1109
+ const priorityOrder = { high: 0, medium: 1, low: 2 };
1110
+ return priorityOrder[a.priority] - priorityOrder[b.priority];
1111
+ });
1112
+ const summary = {
1113
+ total: notifications.length,
1114
+ high: notifications.filter((n) => n.priority === "high").length,
1115
+ medium: notifications.filter((n) => n.priority === "medium").length,
1116
+ low: notifications.filter((n) => n.priority === "low").length
1117
+ };
1118
+ return { notifications, summary };
1119
+ }
1120
+ function formatNotification(notification) {
1121
+ const priorityEmoji = {
1122
+ high: "\u{1F534}",
1123
+ medium: "\u{1F7E1}",
1124
+ low: "\u{1F7E2}"
1125
+ };
1126
+ const lines = [
1127
+ `${priorityEmoji[notification.priority]} ${notification.title}`,
1128
+ ` ${notification.message}`
1129
+ ];
1130
+ if (notification.action) {
1131
+ lines.push(` \u2192 ${notification.action.command}`);
1132
+ }
1133
+ return lines.join("\n");
1134
+ }
1135
+ function formatNotificationsSummary(result) {
1136
+ if (result.notifications.length === 0) {
1137
+ return "No notifications. Everything is up to date!";
1138
+ }
1139
+ const parts = [
1140
+ `${result.summary.total} notification(s):`,
1141
+ ` High: ${result.summary.high}`,
1142
+ ` Medium: ${result.summary.medium}`,
1143
+ ` Low: ${result.summary.low}`,
1144
+ "",
1145
+ ...result.notifications.map(formatNotification)
1146
+ ];
1147
+ return parts.join("\n");
1148
+ }
1149
+ function preview(text) {
1150
+ return text.length > 120 ? `${text.slice(0, 120)}...` : text;
1151
+ }
1152
+ function getExpiringCandidates(memories) {
1153
+ return memories.filter(
1154
+ (memory) => memory.memoryType === "episodic" && memory.status === "active" && memory.ttlSeconds !== void 0 && isMemoryExpired(memory)
1155
+ ).sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime()).map((memory) => ({
1156
+ id: memory.id,
1157
+ ttlSeconds: memory.ttlSeconds,
1158
+ reason: `Expired after ${memory.ttlSeconds} seconds without consolidation`,
1159
+ textPreview: preview(memory.text)
1160
+ }));
1161
+ }
1162
+ function getStrengthenedCandidates(memories, usageStats, lifecycle) {
1163
+ const config2 = resolveLifecycleConfig(lifecycle);
1164
+ const usageMap = new Map(usageStats.map((stat) => [stat.memoryId, stat]));
1165
+ return memories.filter((memory) => memory.memoryType === "episodic" && memory.status === "active").map((memory) => {
1166
+ const usage = usageMap.get(memory.id);
1167
+ if (!usage || usage.count < config2.maintenance.promoteRecallCount) {
1168
+ return void 0;
1169
+ }
1170
+ const isPinned = memory.tags.includes("pinned");
1171
+ const recommendedAction = usage.count >= config2.maintenance.pinRecallCount && !isPinned ? "pin" : "promote";
1172
+ return {
1173
+ id: memory.id,
1174
+ usageCount: usage.count,
1175
+ lastUsed: usage.lastUsed,
1176
+ recommendedAction,
1177
+ reason: recommendedAction === "pin" ? `Frequently reused episodic memory (${usage.count} recalls); consider pinning it` : `Frequently reused episodic memory (${usage.count} recalls); consider promoting it`,
1178
+ textPreview: preview(memory.text)
1179
+ };
1180
+ }).filter((candidate) => candidate !== void 0).sort((a, b) => b.usageCount - a.usageCount);
1181
+ }
1182
+ async function runLocalLifecycleMaintenance(store, orgId, repoId, options = {}) {
1183
+ const lifecycle = resolveLifecycleConfig(options.lifecycle);
1184
+ const dryRun = options.dryRun ?? lifecycle.maintenance.dryRunDefault;
1185
+ const activeMemories = store.list({
1186
+ orgId,
1187
+ repoId,
1188
+ status: ["active"],
1189
+ includeExpired: true,
1190
+ limit: 1e3
1191
+ });
1192
+ const usageStats = store.getUsageStats(orgId, repoId);
1193
+ const expiredCandidates = getExpiringCandidates(activeMemories);
1194
+ const strengthenedCandidates = getStrengthenedCandidates(
1195
+ activeMemories.filter((memory) => !isMemoryExpired(memory)),
1196
+ usageStats,
1197
+ lifecycle
1198
+ );
1199
+ const consolidationPreview = findConsolidationCandidates(store, orgId, repoId, {
1200
+ threshold: lifecycle.maintenance.consolidationThreshold,
1201
+ minGroupSize: lifecycle.maintenance.consolidationMinGroupSize,
1202
+ maxGroups: lifecycle.maintenance.consolidationMaxGroups,
1203
+ types: ["episodic"],
1204
+ excludeConsolidations: true
1205
+ });
1206
+ const warnings = [];
1207
+ const errors = [];
1208
+ const executedConsolidations = [];
1209
+ if (!dryRun) {
1210
+ store.expireExpiredMemories(orgId, repoId);
1211
+ if (consolidationPreview.candidates.length > 0) {
1212
+ if (!isOpenAIConfigured()) {
1213
+ warnings.push(
1214
+ "Skipping consolidation execution because OpenAI is not configured."
1215
+ );
1216
+ } else {
1217
+ for (const candidate of consolidationPreview.candidates) {
1218
+ try {
1219
+ const result = await executeConsolidation(store, candidate, orgId, repoId, {
1220
+ model: options.model,
1221
+ preserveOriginals: options.preserveOriginals
1222
+ });
1223
+ executedConsolidations.push(result);
1224
+ } catch (error) {
1225
+ errors.push(
1226
+ error instanceof Error ? error.message : String(error)
1227
+ );
1228
+ }
1229
+ }
1230
+ }
1231
+ }
1232
+ }
1233
+ return {
1234
+ dryRun,
1235
+ totalActiveMemories: activeMemories.length,
1236
+ expiredCandidates,
1237
+ expiredCount: dryRun ? expiredCandidates.length : expiredCandidates.length,
1238
+ strengthenedCandidates,
1239
+ consolidationCandidates: consolidationPreview.candidates,
1240
+ executedConsolidations,
1241
+ warnings,
1242
+ errors
1243
+ };
1244
+ }
1245
+ var MEMORY_TEMPLATES = {
1246
+ decision: {
1247
+ name: "Decision",
1248
+ description: "Technical or architectural decision",
1249
+ memoryType: "semantic",
1250
+ defaultTags: ["decision"],
1251
+ prefix: "Decision:",
1252
+ visibility: "repo"
1253
+ },
1254
+ adr: {
1255
+ name: "ADR",
1256
+ description: "Architecture Decision Record",
1257
+ memoryType: "semantic",
1258
+ defaultTags: ["adr", "architecture", "decision"],
1259
+ prefix: "ADR:",
1260
+ visibility: "repo"
1261
+ },
1262
+ gotcha: {
1263
+ name: "Gotcha",
1264
+ description: "Non-obvious issue or caveat discovered",
1265
+ memoryType: "episodic",
1266
+ defaultTags: ["gotcha", "warning"],
1267
+ prefix: "Gotcha:",
1268
+ visibility: "repo"
1269
+ },
1270
+ bug: {
1271
+ name: "Bug",
1272
+ description: "Bug found and fixed",
1273
+ memoryType: "episodic",
1274
+ defaultTags: ["bug", "fix"],
1275
+ prefix: "Bug:",
1276
+ visibility: "private"
1277
+ },
1278
+ playbook: {
1279
+ name: "Playbook",
1280
+ description: "Step-by-step procedure or workflow",
1281
+ memoryType: "procedural",
1282
+ defaultTags: ["playbook", "howto"],
1283
+ prefix: "Playbook:",
1284
+ visibility: "repo"
1285
+ },
1286
+ deploy: {
1287
+ name: "Deploy",
1288
+ description: "Deployment procedure or notes",
1289
+ memoryType: "procedural",
1290
+ defaultTags: ["deploy", "ops"],
1291
+ prefix: "Deploy:",
1292
+ visibility: "repo"
1293
+ },
1294
+ convention: {
1295
+ name: "Convention",
1296
+ description: "Coding convention or standard",
1297
+ memoryType: "semantic",
1298
+ defaultTags: ["convention", "standard"],
1299
+ prefix: "Convention:",
1300
+ visibility: "repo"
1301
+ },
1302
+ api: {
1303
+ name: "API",
1304
+ description: "API behavior or contract notes",
1305
+ memoryType: "semantic",
1306
+ defaultTags: ["api"],
1307
+ visibility: "repo"
1308
+ },
1309
+ workaround: {
1310
+ name: "Workaround",
1311
+ description: "Temporary workaround for an issue",
1312
+ memoryType: "episodic",
1313
+ defaultTags: ["workaround", "temporary"],
1314
+ prefix: "Workaround:",
1315
+ visibility: "private"
1316
+ },
1317
+ perf: {
1318
+ name: "Performance",
1319
+ description: "Performance finding or optimization",
1320
+ memoryType: "semantic",
1321
+ defaultTags: ["performance", "optimization"],
1322
+ prefix: "Perf:",
1323
+ visibility: "repo"
1324
+ },
1325
+ security: {
1326
+ name: "Security",
1327
+ description: "Security consideration or finding",
1328
+ memoryType: "semantic",
1329
+ defaultTags: ["security"],
1330
+ prefix: "Security:",
1331
+ visibility: "repo"
1332
+ }
1333
+ };
1334
+ function getTemplate(name) {
1335
+ return MEMORY_TEMPLATES[name.toLowerCase()];
1336
+ }
1337
+ function applyTemplate(template, text, additionalTags = []) {
1338
+ const finalText = template.prefix && !text.toLowerCase().startsWith(template.prefix.toLowerCase()) ? `${template.prefix} ${text}` : text;
1339
+ const tags = [.../* @__PURE__ */ new Set([...template.defaultTags, ...additionalTags])];
1340
+ return {
1341
+ text: finalText,
1342
+ memoryType: template.memoryType,
1343
+ tags,
1344
+ visibility: template.visibility
1345
+ };
1346
+ }
1347
+ function formatTemplateList() {
1348
+ const lines = ["Available templates:", ""];
1349
+ for (const [key, template] of Object.entries(MEMORY_TEMPLATES)) {
1350
+ lines.push(` ${key.padEnd(12)} - ${template.description}`);
1351
+ lines.push(` Type: ${template.memoryType}, Tags: ${template.defaultTags.join(", ")}`);
1352
+ }
1353
+ return lines.join("\n");
1354
+ }
1355
+
1356
+ // ../../packages/config/dist/index.js
1357
+ import fs from "fs";
1358
+ import path from "path";
1359
+ import { execSync } from "child_process";
1360
+ import { randomUUID } from "crypto";
1361
+ import YAML from "yaml";
1362
+ import { z } from "zod";
1363
+ var syncConfigSchema = z.object({
1364
+ enabled: z.boolean(),
1365
+ intervalMs: z.number().positive(),
1366
+ debounceMs: z.number().nonnegative(),
1367
+ autoResolveConflicts: z.enum([
1368
+ "last_write_wins",
1369
+ "local_wins",
1370
+ "remote_wins",
1371
+ "manual"
1372
+ ])
1373
+ });
1374
+ var embeddingConfigSchema = z.object({
1375
+ enabled: z.boolean(),
1376
+ model: z.string(),
1377
+ autoGenerate: z.boolean()
1378
+ });
1379
+ var lifecycleTtlConfigSchema = z.object({
1380
+ episodic: z.number().int().positive().optional(),
1381
+ semantic: z.number().int().positive().optional(),
1382
+ procedural: z.number().int().positive().optional()
1383
+ });
1384
+ var lifecycleUsageBoostSchema = z.object({
1385
+ enabled: z.boolean(),
1386
+ topKToRecord: z.number().int().positive(),
1387
+ minUsageCount: z.number().int().positive(),
1388
+ maxBoost: z.number().min(0).max(1),
1389
+ halfLifeDays: z.number().positive()
1390
+ });
1391
+ var lifecycleMaintenanceSchema = z.object({
1392
+ staleEpisodicDays: z.number().int().positive(),
1393
+ consolidationThreshold: z.number().min(0).max(1),
1394
+ consolidationMinGroupSize: z.number().int().min(2),
1395
+ consolidationMaxGroups: z.number().int().positive(),
1396
+ promoteRecallCount: z.number().int().positive(),
1397
+ pinRecallCount: z.number().int().positive(),
1398
+ dryRunDefault: z.boolean(),
1399
+ autoRunOnStore: z.boolean(),
1400
+ autoRunOnRecall: z.boolean(),
1401
+ debounceMs: z.number().int().positive()
1402
+ });
1403
+ var lifecycleConfigSchema = z.object({
1404
+ ttlSecondsByType: lifecycleTtlConfigSchema.optional(),
1405
+ usageBoost: lifecycleUsageBoostSchema.partial().optional(),
1406
+ maintenance: lifecycleMaintenanceSchema.partial().optional()
1407
+ });
1408
+ var remoteConfigSchema = z.object({
1409
+ url: z.string(),
1410
+ orgId: z.string(),
1411
+ repoId: z.string()
1412
+ });
1413
+ var appConfigSchema = z.object({
1414
+ configVersion: z.number().optional(),
1415
+ remote: remoteConfigSchema,
1416
+ defaults: z.object({
1417
+ visibility: z.enum(["private", "repo", "auto"]),
1418
+ memoryType: z.enum(["episodic", "semantic", "procedural"])
1419
+ }),
1420
+ sync: syncConfigSchema.optional(),
1421
+ embeddings: embeddingConfigSchema.optional(),
1422
+ lifecycle: lifecycleConfigSchema.optional(),
1423
+ remotes: z.record(z.string(), remoteConfigSchema).optional()
1424
+ });
1425
+ var VALID_MEMORY_TYPES = ["episodic", "semantic", "procedural"];
1426
+ function validateMemoryType(value) {
1427
+ return VALID_MEMORY_TYPES.includes(value);
1428
+ }
1429
+ function parseConfidence(value) {
1430
+ const n = parseFloat(value);
1431
+ if (Number.isNaN(n) || n < 0 || n > 1) {
1432
+ throw new Error("--confidence must be a number between 0 and 1");
1433
+ }
1434
+ return n;
1435
+ }
1436
+ function parseThreshold(value) {
1437
+ const n = parseFloat(value);
1438
+ if (Number.isNaN(n) || n < 0 || n > 1) {
1439
+ throw new Error("--threshold must be a number between 0 and 1");
1440
+ }
1441
+ return n;
1442
+ }
1443
+ function parseTtl(value) {
1444
+ const n = parseInt(value, 10);
1445
+ if (Number.isNaN(n) || n <= 0) {
1446
+ throw new Error("--ttl must be a positive integer (seconds)");
1447
+ }
1448
+ return n;
1449
+ }
1450
+ function parsePositiveInt(value, name) {
1451
+ const n = parseInt(value, 10);
1452
+ if (Number.isNaN(n) || n <= 0) {
1453
+ throw new Error(`--${name} must be a positive integer`);
1454
+ }
1455
+ return n;
1456
+ }
1457
+ var DATA_DIR = ".unforgit";
1458
+ var CONFIG_FILE = "unforgit.yaml";
1459
+ var DB_FILE = "local.db";
1460
+ function writeConfigYaml(configPath, value) {
1461
+ const dir = path.dirname(configPath);
1462
+ fs.mkdirSync(dir, { recursive: true });
1463
+ const tmpPath = path.join(
1464
+ dir,
1465
+ `.${path.basename(configPath)}.${process.pid}.${randomUUID()}.tmp`
1466
+ );
1467
+ const fd = fs.openSync(
1468
+ tmpPath,
1469
+ fs.constants.O_CREAT | fs.constants.O_EXCL | fs.constants.O_WRONLY,
1470
+ 384
1471
+ );
1472
+ try {
1473
+ fs.writeFileSync(fd, YAML.stringify(value), "utf-8");
1474
+ fs.fsyncSync(fd);
1475
+ } catch (err) {
1476
+ try {
1477
+ fs.closeSync(fd);
1478
+ } catch {
1479
+ }
1480
+ fs.rmSync(tmpPath, { force: true });
1481
+ throw err;
1482
+ }
1483
+ fs.closeSync(fd);
1484
+ fs.renameSync(tmpPath, configPath);
1485
+ fs.chmodSync(configPath, 384);
1486
+ }
1487
+ function detectGitInfo(cwd = process.cwd()) {
1488
+ try {
1489
+ const remoteUrl = execSync("git remote get-url origin", {
1490
+ cwd,
1491
+ encoding: "utf-8",
1492
+ stdio: ["pipe", "pipe", "pipe"]
1493
+ }).trim();
1494
+ const match = remoteUrl.match(/[:/]([^/]+)\/([^/]+?)(?:\.git)?$/) ?? void 0;
1495
+ if (match) {
1496
+ return { orgId: match[1], repoId: match[2] };
1497
+ }
1498
+ } catch {
1499
+ }
1500
+ return { orgId: "", repoId: "" };
1501
+ }
1502
+ function getDataDir(cwd = process.cwd()) {
1503
+ return path.join(cwd, DATA_DIR);
1504
+ }
1505
+ function getDbPath(cwd = process.cwd()) {
1506
+ return path.join(getDataDir(cwd), DB_FILE);
1507
+ }
1508
+ function getConfigPath(cwd = process.cwd()) {
1509
+ return path.join(getDataDir(cwd), CONFIG_FILE);
1510
+ }
1511
+ function isInitialized(cwd = process.cwd()) {
1512
+ return fs.existsSync(getDataDir(cwd)) && fs.existsSync(getConfigPath(cwd));
1513
+ }
1514
+ function findRepoRoot(startDir = process.cwd()) {
1515
+ let dir = path.resolve(startDir);
1516
+ const root = path.parse(dir).root;
1517
+ while (dir !== root) {
1518
+ if (isInitialized(dir)) return dir;
1519
+ dir = path.dirname(dir);
1520
+ }
1521
+ return null;
1522
+ }
1523
+ var CURRENT_CONFIG_VERSION = 2;
1524
+ function migrateConfig(parsed, configPath) {
1525
+ const version = parsed.configVersion ?? 0;
1526
+ if (version === CURRENT_CONFIG_VERSION) return parsed;
1527
+ if (version === 0) {
1528
+ parsed.configVersion = CURRENT_CONFIG_VERSION;
1529
+ writeConfigYaml(configPath, parsed);
1530
+ }
1531
+ if (version === 1) {
1532
+ parsed.configVersion = CURRENT_CONFIG_VERSION;
1533
+ writeConfigYaml(configPath, parsed);
1534
+ }
1535
+ return parsed;
1536
+ }
1537
+ function warnDeprecatedKeys(parsed) {
1538
+ const deprecated = [];
1539
+ if (parsed.remote?.apiKey) {
1540
+ deprecated.push("remote.apiKey \u2192 use UNFORGIT_API_KEY env var instead");
1541
+ }
1542
+ if (parsed.openaiApiKey) {
1543
+ deprecated.push("openaiApiKey \u2192 use OPENAI_API_KEY env var instead");
1544
+ }
1545
+ if (deprecated.length > 0) {
1546
+ console.error(
1547
+ `[unforgit] Deprecated keys found in unforgit.yaml (ignored):
1548
+ ${deprecated.map((d) => ` - ${d}`).join("\n")}
1549
+ Remove them from your config. Secrets should be set via environment variables.
1550
+ `
1551
+ );
1552
+ }
1553
+ }
1554
+ function loadConfig(cwd = process.cwd()) {
1555
+ const configPath = getConfigPath(cwd);
1556
+ if (!fs.existsSync(configPath)) {
1557
+ throw new Error(
1558
+ "Unforgit not initialized. Run 'unforgit init' first."
1559
+ );
1560
+ }
1561
+ const raw = fs.readFileSync(configPath, "utf-8");
1562
+ const parsed = YAML.parse(raw) ?? {};
1563
+ const migrated = migrateConfig(parsed, configPath);
1564
+ warnDeprecatedKeys(migrated);
1565
+ const result = appConfigSchema.safeParse(migrated);
1566
+ if (!result.success) {
1567
+ const issues = result.error.issues.map((i) => ` - ${i.path.join(".")}: ${i.message}`).join("\n");
1568
+ throw new Error(
1569
+ `Invalid unforgit.yaml configuration:
1570
+ ${issues}
1571
+
1572
+ Fix the config at ${configPath} or re-run 'unforgit init'.`
1573
+ );
1574
+ }
1575
+ const defaults = defaultConfig();
1576
+ const { openaiApiKey: _oai, ...cleanMigrated } = migrated;
1577
+ if (cleanMigrated.remote && typeof cleanMigrated.remote === "object") {
1578
+ const { apiKey: _ak, ...cleanRemote } = cleanMigrated.remote;
1579
+ cleanMigrated.remote = cleanRemote;
1580
+ }
1581
+ return {
1582
+ ...defaults,
1583
+ ...cleanMigrated,
1584
+ ...result.data,
1585
+ remote: {
1586
+ ...defaults.remote,
1587
+ ...result.data.remote
1588
+ },
1589
+ defaults: {
1590
+ ...defaults.defaults,
1591
+ ...result.data.defaults
1592
+ },
1593
+ sync: {
1594
+ ...defaults.sync,
1595
+ ...result.data.sync ?? {}
1596
+ },
1597
+ embeddings: {
1598
+ ...defaults.embeddings,
1599
+ ...result.data.embeddings ?? {}
1600
+ },
1601
+ lifecycle: resolveLifecycleConfig(result.data.lifecycle)
1602
+ };
1603
+ }
1604
+ function saveConfig(config2, cwd = process.cwd()) {
1605
+ const configPath = getConfigPath(cwd);
1606
+ writeConfigYaml(configPath, config2);
1607
+ }
1608
+ function defaultConfig() {
1609
+ return {
1610
+ configVersion: CURRENT_CONFIG_VERSION,
1611
+ remote: {
1612
+ url: "http://localhost:3737",
1613
+ orgId: "",
1614
+ repoId: ""
1615
+ },
1616
+ defaults: {
1617
+ visibility: "auto",
1618
+ memoryType: "episodic"
1619
+ },
1620
+ sync: {
1621
+ enabled: true,
1622
+ intervalMs: 6e4,
1623
+ debounceMs: 5e3,
1624
+ autoResolveConflicts: "last_write_wins"
1625
+ },
1626
+ embeddings: {
1627
+ enabled: true,
1628
+ model: "text-embedding-3-small",
1629
+ autoGenerate: true
1630
+ },
1631
+ lifecycle: resolveLifecycleConfig()
1632
+ };
1633
+ }
1634
+ var DEFAULT_TIMEOUT_MS = 3e4;
1635
+ var MAX_RETRIES = 3;
1636
+ var INITIAL_BACKOFF_MS = 1e3;
1637
+ function isTransientError(status) {
1638
+ return status >= 500 || status === 429;
1639
+ }
1640
+ var RemoteClient = class {
1641
+ constructor(baseUrl, apiKey, options) {
1642
+ this.baseUrl = baseUrl;
1643
+ this.apiKey = apiKey || process.env.UNFORGIT_API_KEY;
1644
+ this.timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
1645
+ }
1646
+ apiKey;
1647
+ timeoutMs;
1648
+ getHeaders() {
1649
+ const headers = {
1650
+ "Content-Type": "application/json"
1651
+ };
1652
+ if (this.apiKey) {
1653
+ headers["Authorization"] = `Bearer ${this.apiKey}`;
1654
+ }
1655
+ return headers;
1656
+ }
1657
+ handleError(res, operation, errorText) {
1658
+ if (res.status === 401) {
1659
+ throw new Error(
1660
+ `Authentication failed for ${operation}: Invalid or missing API key. Set the UNFORGIT_API_KEY environment variable.`
1661
+ );
1662
+ }
1663
+ if (res.status === 404 && operation === "resetAll") {
1664
+ throw new Error(
1665
+ "Remote resetAll failed (404): the configured server does not support /v1/memories/reset. Rebuild or restart the remote API so it is running a version that includes the reset endpoint."
1666
+ );
1667
+ }
1668
+ throw new Error(`Remote ${operation} failed (${res.status}): ${errorText}`);
1669
+ }
1670
+ async fetchWithTimeout(url, init) {
1671
+ const controller = new AbortController();
1672
+ const timer = setTimeout(() => controller.abort(), this.timeoutMs);
1673
+ try {
1674
+ return await fetch(url, { ...init, signal: controller.signal });
1675
+ } catch (err) {
1676
+ if (err instanceof DOMException && err.name === "AbortError") {
1677
+ throw new Error(`Request timed out after ${this.timeoutMs}ms`);
1678
+ }
1679
+ throw err;
1680
+ } finally {
1681
+ clearTimeout(timer);
1682
+ }
1683
+ }
1684
+ async fetchWithRetry(url, init, operation) {
1685
+ let lastError;
1686
+ for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
1687
+ try {
1688
+ const res = await this.fetchWithTimeout(url, init);
1689
+ if (res.ok || !isTransientError(res.status)) {
1690
+ return res;
1691
+ }
1692
+ lastError = new Error(
1693
+ `Remote ${operation} failed (${res.status}): ${await res.text()}`
1694
+ );
1695
+ } catch (err) {
1696
+ lastError = err instanceof Error ? err : new Error(String(err));
1697
+ const isFatalAbort = lastError.message.includes("timed out") && attempt === MAX_RETRIES - 1;
1698
+ if (isFatalAbort) throw lastError;
1699
+ }
1700
+ if (attempt < MAX_RETRIES - 1) {
1701
+ const backoff = INITIAL_BACKOFF_MS * Math.pow(2, attempt);
1702
+ await new Promise((resolve) => setTimeout(resolve, backoff));
1703
+ }
1704
+ }
1705
+ throw lastError ?? new Error(`Remote ${operation} failed after ${MAX_RETRIES} retries`);
1706
+ }
1707
+ async store(input) {
1708
+ const res = await this.fetchWithRetry(
1709
+ `${this.baseUrl}/v1/memory`,
1710
+ { method: "POST", headers: this.getHeaders(), body: JSON.stringify(input) },
1711
+ "store"
1712
+ );
1713
+ if (!res.ok) {
1714
+ this.handleError(res, "store", await res.text());
1715
+ }
1716
+ return res.json();
1717
+ }
1718
+ async recall(query) {
1719
+ const res = await this.fetchWithRetry(
1720
+ `${this.baseUrl}/v1/recall`,
1721
+ { method: "POST", headers: this.getHeaders(), body: JSON.stringify(query) },
1722
+ "recall"
1723
+ );
1724
+ if (!res.ok) {
1725
+ this.handleError(res, "recall", await res.text());
1726
+ }
1727
+ return res.json();
1728
+ }
1729
+ async deprecate(id, reason) {
1730
+ const res = await this.fetchWithRetry(
1731
+ `${this.baseUrl}/v1/memory/${id}/deprecate`,
1732
+ { method: "POST", headers: this.getHeaders(), body: JSON.stringify({ reason }) },
1733
+ "deprecate"
1734
+ );
1735
+ if (!res.ok) {
1736
+ this.handleError(res, "deprecate", await res.text());
1737
+ }
1738
+ return res.json();
1739
+ }
1740
+ async supersede(oldId, newId) {
1741
+ const res = await this.fetchWithRetry(
1742
+ `${this.baseUrl}/v1/memory/${oldId}/supersede`,
1743
+ { method: "POST", headers: this.getHeaders(), body: JSON.stringify({ newId }) },
1744
+ "supersede"
1745
+ );
1746
+ if (!res.ok) {
1747
+ this.handleError(res, "supersede", await res.text());
1748
+ }
1749
+ return res.json();
1750
+ }
1751
+ async link(sourceId, targetId, linkType, metadata) {
1752
+ const res = await this.fetchWithRetry(
1753
+ `${this.baseUrl}/v1/memory/${sourceId}/link`,
1754
+ {
1755
+ method: "POST",
1756
+ headers: this.getHeaders(),
1757
+ body: JSON.stringify({ targetId, linkType, metadata })
1758
+ },
1759
+ "link"
1760
+ );
1761
+ if (!res.ok) {
1762
+ this.handleError(res, "link", await res.text());
1763
+ }
1764
+ return res.json();
1765
+ }
1766
+ async unlink(sourceId, targetId, linkType) {
1767
+ const res = await this.fetchWithRetry(
1768
+ `${this.baseUrl}/v1/memory/${sourceId}/link`,
1769
+ {
1770
+ method: "DELETE",
1771
+ headers: this.getHeaders(),
1772
+ body: JSON.stringify({ targetId, linkType })
1773
+ },
1774
+ "unlink"
1775
+ );
1776
+ if (!res.ok) {
1777
+ this.handleError(res, "unlink", await res.text());
1778
+ }
1779
+ return res.json();
1780
+ }
1781
+ async getLinks(memoryId, linkType) {
1782
+ const params = new URLSearchParams();
1783
+ if (linkType) params.set("linkType", linkType);
1784
+ const qs = params.toString();
1785
+ const url = `${this.baseUrl}/v1/memory/${memoryId}/links${qs ? `?${qs}` : ""}`;
1786
+ const res = await this.fetchWithRetry(url, { headers: this.getHeaders() }, "getLinks");
1787
+ if (!res.ok) {
1788
+ this.handleError(res, "getLinks", await res.text());
1789
+ }
1790
+ return res.json();
1791
+ }
1792
+ async consolidate(body) {
1793
+ const res = await this.fetchWithRetry(
1794
+ `${this.baseUrl}/v1/consolidate`,
1795
+ { method: "POST", headers: this.getHeaders(), body: JSON.stringify(body) },
1796
+ "consolidate"
1797
+ );
1798
+ if (!res.ok) {
1799
+ this.handleError(res, "consolidate", await res.text());
1800
+ }
1801
+ return res.json();
1802
+ }
1803
+ async delete(id, deletedBy, hardDelete) {
1804
+ const res = await this.fetchWithRetry(
1805
+ `${this.baseUrl}/v1/memory/${id}`,
1806
+ {
1807
+ method: "DELETE",
1808
+ headers: this.getHeaders(),
1809
+ body: JSON.stringify({ deletedBy, hardDelete })
1810
+ },
1811
+ "delete"
1812
+ );
1813
+ if (!res.ok) {
1814
+ this.handleError(res, "delete", await res.text());
1815
+ }
1816
+ return res.json();
1817
+ }
1818
+ async restore(id) {
1819
+ const res = await this.fetchWithRetry(
1820
+ `${this.baseUrl}/v1/memory/${id}/restore`,
1821
+ { method: "POST", headers: this.getHeaders() },
1822
+ "restore"
1823
+ );
1824
+ if (!res.ok) {
1825
+ this.handleError(res, "restore", await res.text());
1826
+ }
1827
+ return res.json();
1828
+ }
1829
+ async resetAll(orgId, repoId) {
1830
+ const res = await this.fetchWithRetry(
1831
+ `${this.baseUrl}/v1/memories/reset`,
1832
+ {
1833
+ method: "POST",
1834
+ headers: this.getHeaders(),
1835
+ body: JSON.stringify({ orgId, repoId })
1836
+ },
1837
+ "resetAll"
1838
+ );
1839
+ if (!res.ok) {
1840
+ this.handleError(res, "resetAll", await res.text());
1841
+ }
1842
+ return res.json();
1843
+ }
1844
+ async runLifecycle(body) {
1845
+ const res = await this.fetchWithRetry(
1846
+ `${this.baseUrl}/v1/lifecycle/run`,
1847
+ {
1848
+ method: "POST",
1849
+ headers: this.getHeaders(),
1850
+ body: JSON.stringify(body)
1851
+ },
1852
+ "runLifecycle"
1853
+ );
1854
+ if (!res.ok) {
1855
+ this.handleError(res, "runLifecycle", await res.text());
1856
+ }
1857
+ return res.json();
1858
+ }
1859
+ async createApiKey(name, orgId) {
1860
+ const res = await this.fetchWithRetry(
1861
+ `${this.baseUrl}/v1/api-keys`,
1862
+ {
1863
+ method: "POST",
1864
+ headers: this.getHeaders(),
1865
+ body: JSON.stringify({ name, orgId })
1866
+ },
1867
+ "createApiKey"
1868
+ );
1869
+ if (!res.ok) {
1870
+ this.handleError(res, "createApiKey", await res.text());
1871
+ }
1872
+ return res.json();
1873
+ }
1874
+ async listApiKeys(orgId) {
1875
+ const params = new URLSearchParams();
1876
+ if (orgId) params.set("orgId", orgId);
1877
+ const qs = params.toString();
1878
+ const url = `${this.baseUrl}/v1/api-keys${qs ? `?${qs}` : ""}`;
1879
+ const res = await this.fetchWithRetry(url, { headers: this.getHeaders() }, "listApiKeys");
1880
+ if (!res.ok) {
1881
+ this.handleError(res, "listApiKeys", await res.text());
1882
+ }
1883
+ return res.json();
1884
+ }
1885
+ async revokeApiKey(id) {
1886
+ const res = await this.fetchWithRetry(
1887
+ `${this.baseUrl}/v1/api-keys/${id}`,
1888
+ { method: "DELETE", headers: this.getHeaders() },
1889
+ "revokeApiKey"
1890
+ );
1891
+ if (!res.ok) {
1892
+ if (res.status === 404) {
1893
+ throw new Error(`API key '${id}' not found.`);
1894
+ }
1895
+ this.handleError(res, "revokeApiKey", await res.text());
1896
+ }
1897
+ }
1898
+ };
1899
+
1900
+ // ../../packages/db/dist/index.js
1901
+ import Database from "better-sqlite3";
1902
+ import { v4 as uuid } from "uuid";
1903
+ import path2 from "path";
1904
+ import fs2 from "fs";
1905
+ import * as path22 from "path";
1906
+ import { fileURLToPath } from "url";
1907
+ import * as runtime from "@prisma/client/runtime/client";
1908
+ import * as runtime2 from "@prisma/client/runtime/client";
1909
+ import { PrismaPg } from "@prisma/adapter-pg";
1910
+ var SCHEMA_SQL = `
1911
+ CREATE TABLE IF NOT EXISTS memories (
1912
+ id TEXT PRIMARY KEY,
1913
+ org_id TEXT NOT NULL,
1914
+ repo_id TEXT NOT NULL,
1915
+ scope_type TEXT NOT NULL DEFAULT 'repo',
1916
+ memory_type TEXT NOT NULL CHECK(memory_type IN ('episodic','semantic','procedural')),
1917
+ visibility TEXT NOT NULL DEFAULT 'private' CHECK(visibility IN ('private','repo')),
1918
+ status TEXT NOT NULL DEFAULT 'active' CHECK(status IN ('active','deprecated','superseded','deleted')),
1919
+ text TEXT NOT NULL,
1920
+ summary TEXT,
1921
+ tags TEXT NOT NULL DEFAULT '[]',
1922
+ source_refs TEXT,
1923
+ confidence REAL,
1924
+ ttl_seconds INTEGER,
1925
+ supersedes_id TEXT,
1926
+ is_consolidation INTEGER NOT NULL DEFAULT 0,
1927
+ consolidation_version INTEGER,
1928
+ author_id TEXT,
1929
+ author_name TEXT,
1930
+ version INTEGER NOT NULL DEFAULT 1,
1931
+ deleted_at TEXT,
1932
+ deleted_by TEXT,
1933
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
1934
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
1935
+ );
1936
+
1937
+ CREATE TABLE IF NOT EXISTS tombstones (
1938
+ id TEXT PRIMARY KEY,
1939
+ memory_id TEXT NOT NULL UNIQUE,
1940
+ org_id TEXT NOT NULL,
1941
+ repo_id TEXT NOT NULL,
1942
+ deleted_at TEXT NOT NULL,
1943
+ deleted_by TEXT,
1944
+ synced_at TEXT,
1945
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
1946
+ );
1947
+
1948
+ CREATE INDEX IF NOT EXISTS idx_tombstones_sync ON tombstones(org_id, repo_id, synced_at);
1949
+
1950
+ CREATE VIRTUAL TABLE IF NOT EXISTS memories_fts USING fts5(
1951
+ text, summary, content=memories, content_rowid=rowid
1952
+ );
1953
+
1954
+ CREATE TRIGGER IF NOT EXISTS memories_ai AFTER INSERT ON memories BEGIN
1955
+ INSERT INTO memories_fts(rowid, text, summary)
1956
+ VALUES (new.rowid, new.text, new.summary);
1957
+ END;
1958
+
1959
+ CREATE TRIGGER IF NOT EXISTS memories_ad AFTER DELETE ON memories BEGIN
1960
+ INSERT INTO memories_fts(memories_fts, rowid, text, summary)
1961
+ VALUES ('delete', old.rowid, old.text, old.summary);
1962
+ END;
1963
+
1964
+ CREATE TRIGGER IF NOT EXISTS memories_au AFTER UPDATE ON memories BEGIN
1965
+ INSERT INTO memories_fts(memories_fts, rowid, text, summary)
1966
+ VALUES ('delete', old.rowid, old.text, old.summary);
1967
+ INSERT INTO memories_fts(rowid, text, summary)
1968
+ VALUES (new.rowid, new.text, new.summary);
1969
+ END;
1970
+
1971
+ CREATE TABLE IF NOT EXISTS memory_links (
1972
+ id TEXT PRIMARY KEY,
1973
+ source_id TEXT NOT NULL REFERENCES memories(id) ON DELETE CASCADE,
1974
+ target_id TEXT NOT NULL REFERENCES memories(id) ON DELETE CASCADE,
1975
+ link_type TEXT NOT NULL CHECK(link_type IN ('related_to','derived_from','contradicts','depends_on')),
1976
+ metadata TEXT,
1977
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
1978
+ UNIQUE(source_id, target_id, link_type)
1979
+ );
1980
+
1981
+ CREATE TABLE IF NOT EXISTS sync_state (
1982
+ memory_id TEXT PRIMARY KEY,
1983
+ local_version INTEGER NOT NULL,
1984
+ remote_version INTEGER,
1985
+ last_pushed_at TEXT,
1986
+ last_pulled_at TEXT,
1987
+ sync_status TEXT NOT NULL DEFAULT 'pending_push' CHECK(sync_status IN ('synced','pending_push','pending_pull','conflict'))
1988
+ );
1989
+
1990
+ CREATE INDEX IF NOT EXISTS idx_sync_state_status ON sync_state(sync_status);
1991
+
1992
+ CREATE TABLE IF NOT EXISTS synced_links (
1993
+ link_id TEXT PRIMARY KEY,
1994
+ synced_at TEXT NOT NULL
1995
+ );
1996
+
1997
+ CREATE TABLE IF NOT EXISTS memory_embeddings (
1998
+ memory_id TEXT PRIMARY KEY REFERENCES memories(id) ON DELETE CASCADE,
1999
+ embedding BLOB NOT NULL,
2000
+ model TEXT NOT NULL,
2001
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
2002
+ );
2003
+
2004
+ CREATE TABLE IF NOT EXISTS memory_usage (
2005
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
2006
+ memory_id TEXT NOT NULL,
2007
+ recalled_at TEXT NOT NULL DEFAULT (datetime('now')),
2008
+ query TEXT,
2009
+ session_id TEXT
2010
+ );
2011
+
2012
+ CREATE INDEX IF NOT EXISTS idx_memory_usage_memory ON memory_usage(memory_id);
2013
+ CREATE INDEX IF NOT EXISTS idx_memory_usage_recalled ON memory_usage(recalled_at);
2014
+
2015
+ CREATE TABLE IF NOT EXISTS curation_suggestions (
2016
+ id TEXT PRIMARY KEY,
2017
+ org_id TEXT NOT NULL,
2018
+ repo_id TEXT NOT NULL,
2019
+ type TEXT NOT NULL CHECK(type IN ('consolidate','deprecate','delete','add_tags','add_links','review','promote','generate_embedding')),
2020
+ priority TEXT NOT NULL CHECK(priority IN ('high','medium','low')),
2021
+ status TEXT NOT NULL DEFAULT 'pending' CHECK(status IN ('pending','approved','rejected','applied')),
2022
+ memory_ids TEXT NOT NULL DEFAULT '[]',
2023
+ reason TEXT NOT NULL,
2024
+ confidence REAL NOT NULL,
2025
+ payload TEXT,
2026
+ created_by TEXT,
2027
+ reviewed_by TEXT,
2028
+ review_note TEXT,
2029
+ reviewed_at TEXT,
2030
+ applied_at TEXT,
2031
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
2032
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
2033
+ );
2034
+ CREATE INDEX IF NOT EXISTS idx_curation_suggestions_repo_status ON curation_suggestions(org_id, repo_id, status, created_at);
2035
+ `;
2036
+ function rowToLink(row) {
2037
+ return {
2038
+ id: row.id,
2039
+ sourceId: row.source_id,
2040
+ targetId: row.target_id,
2041
+ linkType: row.link_type,
2042
+ metadata: row.metadata ? JSON.parse(row.metadata) : void 0,
2043
+ createdAt: new Date(row.created_at)
2044
+ };
2045
+ }
2046
+ function rowToMemory(row) {
2047
+ return {
2048
+ id: row.id,
2049
+ orgId: row.org_id,
2050
+ repoId: row.repo_id,
2051
+ scopeType: row.scope_type ?? "repo",
2052
+ memoryType: row.memory_type,
2053
+ visibility: row.visibility,
2054
+ status: row.status,
2055
+ text: row.text,
2056
+ summary: row.summary ?? void 0,
2057
+ tags: JSON.parse(row.tags ?? "[]"),
2058
+ sourceRefs: row.source_refs ? JSON.parse(row.source_refs) : void 0,
2059
+ confidence: row.confidence ?? void 0,
2060
+ ttlSeconds: row.ttl_seconds ?? void 0,
2061
+ supersedesId: row.supersedes_id ?? void 0,
2062
+ isConsolidation: row.is_consolidation === 1,
2063
+ consolidationVersion: row.consolidation_version ?? void 0,
2064
+ authorId: row.author_id ?? void 0,
2065
+ authorName: row.author_name ?? void 0,
2066
+ version: row.version ?? 1,
2067
+ deletedAt: row.deleted_at ? new Date(row.deleted_at) : void 0,
2068
+ deletedBy: row.deleted_by ?? void 0,
2069
+ createdAt: new Date(row.created_at),
2070
+ updatedAt: new Date(row.updated_at)
2071
+ };
2072
+ }
2073
+ function rowToCurationSuggestion(row) {
2074
+ return {
2075
+ id: row.id,
2076
+ orgId: row.org_id,
2077
+ repoId: row.repo_id,
2078
+ type: row.type,
2079
+ priority: row.priority,
2080
+ status: row.status,
2081
+ memoryIds: JSON.parse(row.memory_ids ?? "[]"),
2082
+ reason: row.reason,
2083
+ confidence: row.confidence,
2084
+ payload: row.payload ? JSON.parse(row.payload) : void 0,
2085
+ createdBy: row.created_by ?? void 0,
2086
+ reviewedBy: row.reviewed_by ?? void 0,
2087
+ reviewNote: row.review_note ?? void 0,
2088
+ reviewedAt: row.reviewed_at ? new Date(row.reviewed_at) : void 0,
2089
+ appliedAt: row.applied_at ? new Date(row.applied_at) : void 0,
2090
+ createdAt: new Date(row.created_at),
2091
+ updatedAt: new Date(row.updated_at)
2092
+ };
2093
+ }
2094
+ function rowToTombstone(row) {
2095
+ return {
2096
+ id: row.id,
2097
+ memoryId: row.memory_id,
2098
+ orgId: row.org_id,
2099
+ repoId: row.repo_id,
2100
+ deletedAt: new Date(row.deleted_at),
2101
+ deletedBy: row.deleted_by ?? void 0,
2102
+ syncedAt: row.synced_at ? new Date(row.synced_at) : void 0
2103
+ };
2104
+ }
2105
+ function nonExpiredMemoryClause(alias) {
2106
+ const prefix = alias ? `${alias}.` : "";
2107
+ return `(${prefix}status != 'active' OR ${prefix}ttl_seconds IS NULL OR datetime(${prefix}created_at, '+' || ${prefix}ttl_seconds || ' seconds') >= datetime('now'))`;
2108
+ }
2109
+ var LocalStore = class {
2110
+ db;
2111
+ constructor(dbPath) {
2112
+ const dir = path2.dirname(dbPath);
2113
+ if (!fs2.existsSync(dir)) {
2114
+ fs2.mkdirSync(dir, { recursive: true });
2115
+ }
2116
+ this.db = new Database(dbPath);
2117
+ this.db.pragma("journal_mode = WAL");
2118
+ this.db.pragma("foreign_keys = ON");
2119
+ this.db.exec(SCHEMA_SQL);
2120
+ this.migrateSchema();
2121
+ }
2122
+ migrateSchema() {
2123
+ const columns = this.db.prepare("PRAGMA table_info(memories)").all();
2124
+ const columnNames = columns.map((c) => c.name);
2125
+ if (!columnNames.includes("is_consolidation")) {
2126
+ this.db.exec(
2127
+ "ALTER TABLE memories ADD COLUMN is_consolidation INTEGER NOT NULL DEFAULT 0"
2128
+ );
2129
+ }
2130
+ if (!columnNames.includes("consolidation_version")) {
2131
+ this.db.exec(
2132
+ "ALTER TABLE memories ADD COLUMN consolidation_version INTEGER"
2133
+ );
2134
+ }
2135
+ if (!columnNames.includes("author_id")) {
2136
+ this.db.exec("ALTER TABLE memories ADD COLUMN author_id TEXT");
2137
+ }
2138
+ if (!columnNames.includes("author_name")) {
2139
+ this.db.exec("ALTER TABLE memories ADD COLUMN author_name TEXT");
2140
+ }
2141
+ if (!columnNames.includes("version")) {
2142
+ this.db.exec("ALTER TABLE memories ADD COLUMN version INTEGER NOT NULL DEFAULT 1");
2143
+ }
2144
+ if (!columnNames.includes("deleted_at")) {
2145
+ this.db.exec("ALTER TABLE memories ADD COLUMN deleted_at TEXT");
2146
+ }
2147
+ if (!columnNames.includes("deleted_by")) {
2148
+ this.db.exec("ALTER TABLE memories ADD COLUMN deleted_by TEXT");
2149
+ }
2150
+ const tables = this.db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='tombstones'").all();
2151
+ if (tables.length === 0) {
2152
+ this.db.exec(`
2153
+ CREATE TABLE IF NOT EXISTS tombstones (
2154
+ id TEXT PRIMARY KEY,
2155
+ memory_id TEXT NOT NULL UNIQUE,
2156
+ org_id TEXT NOT NULL,
2157
+ repo_id TEXT NOT NULL,
2158
+ deleted_at TEXT NOT NULL,
2159
+ deleted_by TEXT,
2160
+ synced_at TEXT,
2161
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
2162
+ );
2163
+ CREATE INDEX IF NOT EXISTS idx_tombstones_sync ON tombstones(org_id, repo_id, synced_at);
2164
+ `);
2165
+ }
2166
+ const syncTables = this.db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='sync_state'").all();
2167
+ if (syncTables.length === 0) {
2168
+ this.db.exec(`
2169
+ CREATE TABLE IF NOT EXISTS sync_state (
2170
+ memory_id TEXT PRIMARY KEY,
2171
+ local_version INTEGER NOT NULL,
2172
+ remote_version INTEGER,
2173
+ last_pushed_at TEXT,
2174
+ last_pulled_at TEXT,
2175
+ sync_status TEXT NOT NULL DEFAULT 'pending_push' CHECK(sync_status IN ('synced','pending_push','pending_pull','conflict'))
2176
+ );
2177
+ CREATE INDEX IF NOT EXISTS idx_sync_state_status ON sync_state(sync_status);
2178
+ `);
2179
+ }
2180
+ const embeddingTables = this.db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='memory_embeddings'").all();
2181
+ if (embeddingTables.length === 0) {
2182
+ this.db.exec(`
2183
+ CREATE TABLE IF NOT EXISTS memory_embeddings (
2184
+ memory_id TEXT PRIMARY KEY REFERENCES memories(id) ON DELETE CASCADE,
2185
+ embedding BLOB NOT NULL,
2186
+ model TEXT NOT NULL,
2187
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
2188
+ );
2189
+ `);
2190
+ }
2191
+ const usageTables = this.db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='memory_usage'").all();
2192
+ if (usageTables.length === 0) {
2193
+ this.db.exec(`
2194
+ CREATE TABLE IF NOT EXISTS memory_usage (
2195
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
2196
+ memory_id TEXT NOT NULL,
2197
+ recalled_at TEXT NOT NULL DEFAULT (datetime('now')),
2198
+ query TEXT,
2199
+ session_id TEXT
2200
+ );
2201
+ CREATE INDEX IF NOT EXISTS idx_memory_usage_memory ON memory_usage(memory_id);
2202
+ CREATE INDEX IF NOT EXISTS idx_memory_usage_recalled ON memory_usage(recalled_at);
2203
+ `);
2204
+ }
2205
+ const curationSuggestionTables = this.db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='curation_suggestions'").all();
2206
+ if (curationSuggestionTables.length === 0) {
2207
+ this.db.exec(`
2208
+ CREATE TABLE IF NOT EXISTS curation_suggestions (
2209
+ id TEXT PRIMARY KEY,
2210
+ org_id TEXT NOT NULL,
2211
+ repo_id TEXT NOT NULL,
2212
+ type TEXT NOT NULL CHECK(type IN ('consolidate','deprecate','delete','add_tags','add_links','review','promote','generate_embedding')),
2213
+ priority TEXT NOT NULL CHECK(priority IN ('high','medium','low')),
2214
+ status TEXT NOT NULL DEFAULT 'pending' CHECK(status IN ('pending','approved','rejected','applied')),
2215
+ memory_ids TEXT NOT NULL DEFAULT '[]',
2216
+ reason TEXT NOT NULL,
2217
+ confidence REAL NOT NULL,
2218
+ payload TEXT,
2219
+ created_by TEXT,
2220
+ reviewed_by TEXT,
2221
+ review_note TEXT,
2222
+ reviewed_at TEXT,
2223
+ applied_at TEXT,
2224
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
2225
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
2226
+ );
2227
+ CREATE INDEX IF NOT EXISTS idx_curation_suggestions_repo_status ON curation_suggestions(org_id, repo_id, status, created_at);
2228
+ `);
2229
+ }
2230
+ }
2231
+ store(input) {
2232
+ const resolvedInput = applyLifecycleDefaults(input);
2233
+ const id = uuid();
2234
+ const now = (/* @__PURE__ */ new Date()).toISOString();
2235
+ const normalizedOrgId = resolvedInput.orgId.toLowerCase();
2236
+ const normalizedRepoId = resolvedInput.repoId.toLowerCase();
2237
+ const visibility = resolvedInput.visibility === "auto" || !resolvedInput.visibility ? "private" : resolvedInput.visibility;
2238
+ this.db.prepare(
2239
+ `INSERT INTO memories
2240
+ (id, org_id, repo_id, scope_type, memory_type, visibility, status, text, summary, tags, source_refs, confidence, ttl_seconds, author_id, author_name, created_at, updated_at)
2241
+ VALUES (?, ?, ?, 'repo', ?, ?, 'active', ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
2242
+ ).run(
2243
+ id,
2244
+ normalizedOrgId,
2245
+ normalizedRepoId,
2246
+ resolvedInput.memoryType,
2247
+ visibility,
2248
+ resolvedInput.text,
2249
+ resolvedInput.summary ?? null,
2250
+ JSON.stringify(resolvedInput.tags ?? []),
2251
+ resolvedInput.sourceRefs ? JSON.stringify(resolvedInput.sourceRefs) : null,
2252
+ resolvedInput.confidence ?? null,
2253
+ resolvedInput.ttlSeconds ?? null,
2254
+ resolvedInput.authorId ?? null,
2255
+ resolvedInput.authorName ?? null,
2256
+ now,
2257
+ now
2258
+ );
2259
+ this.setSyncState({
2260
+ memoryId: id,
2261
+ localVersion: 1,
2262
+ syncStatus: "pending_push"
2263
+ });
2264
+ return this.getById(id);
2265
+ }
2266
+ getById(id) {
2267
+ const row = this.db.prepare("SELECT * FROM memories WHERE id = ?").get(id);
2268
+ return row ? rowToMemory(row) : void 0;
2269
+ }
2270
+ recall(query) {
2271
+ const conditions = ["m.org_id = ?", "m.repo_id = ?"];
2272
+ const params = [query.orgId, query.repoId];
2273
+ if (!query.includeDeprecated) {
2274
+ conditions.push("m.status = 'active'");
2275
+ }
2276
+ if (!query.includeExpired) {
2277
+ conditions.push(nonExpiredMemoryClause("m"));
2278
+ }
2279
+ if (query.types && query.types.length > 0) {
2280
+ conditions.push(
2281
+ `m.memory_type IN (${query.types.map(() => "?").join(",")})`
2282
+ );
2283
+ params.push(...query.types);
2284
+ }
2285
+ if (query.timeRange?.from) {
2286
+ conditions.push("m.created_at >= ?");
2287
+ params.push(query.timeRange.from.toISOString());
2288
+ }
2289
+ if (query.timeRange?.to) {
2290
+ conditions.push("m.created_at <= ?");
2291
+ params.push(query.timeRange.to.toISOString());
2292
+ }
2293
+ const whereClause = conditions.join(" AND ");
2294
+ const k = query.k ?? 10;
2295
+ const rawQuery = query.query.replace(/[^\w\s]/g, " ").trim();
2296
+ const words = rawQuery.split(/\s+/).filter((w) => w.length > 0);
2297
+ const searchableWords = words.filter((w) => w.length >= 2);
2298
+ const ftsQuery = searchableWords.length > 0 ? `(${searchableWords.map((w) => `${w}*`).join(" OR ")})` : "";
2299
+ let sql;
2300
+ let finalParams;
2301
+ if (ftsQuery) {
2302
+ sql = `
2303
+ SELECT m.*, fts.rank AS fts_rank
2304
+ FROM memories_fts fts
2305
+ JOIN memories m ON m.rowid = fts.rowid
2306
+ WHERE fts.memories_fts MATCH ?
2307
+ AND ${whereClause}
2308
+ ORDER BY m.is_consolidation DESC, fts.rank
2309
+ LIMIT ?
2310
+ `;
2311
+ finalParams = [ftsQuery, ...params, k * 2];
2312
+ } else {
2313
+ sql = `
2314
+ SELECT m.*, 0 AS fts_rank
2315
+ FROM memories m
2316
+ WHERE ${whereClause}
2317
+ ORDER BY m.is_consolidation DESC, m.created_at DESC
2318
+ LIMIT ?
2319
+ `;
2320
+ finalParams = [...params, k * 2];
2321
+ }
2322
+ let rows = this.db.prepare(sql).all(...finalParams);
2323
+ if (rows.length === 0 && searchableWords.length > 0) {
2324
+ const likeConditions = searchableWords.slice(0, 5).map(() => "(m.text LIKE ? OR m.summary LIKE ?)").join(" OR ");
2325
+ const likeParams = [];
2326
+ for (const word of searchableWords.slice(0, 5)) {
2327
+ likeParams.push(`%${word}%`, `%${word}%`);
2328
+ }
2329
+ const fallbackSql = `
2330
+ SELECT m.*, 0 AS fts_rank
2331
+ FROM memories m
2332
+ WHERE ${whereClause}
2333
+ AND (${likeConditions})
2334
+ ORDER BY m.is_consolidation DESC, m.created_at DESC
2335
+ LIMIT ?
2336
+ `;
2337
+ rows = this.db.prepare(fallbackSql).all(...params, ...likeParams, k * 2);
2338
+ }
2339
+ const usageStats = this.getUsageStats(query.orgId, query.repoId);
2340
+ const usageMap = new Map(usageStats.map((stat) => [stat.memoryId, stat]));
2341
+ let results = rows.map((row) => {
2342
+ const memory = rowToMemory(row);
2343
+ const textScore = ftsQuery ? Math.min(1, Math.abs(row.fts_rank) / 10) : 0.5;
2344
+ const consolidationBoost = memory.isConsolidation ? 0.1 : 0;
2345
+ const usage = usageMap.get(memory.id);
2346
+ const usageBoost = computeUsageBoost(
2347
+ usage?.count ?? 0,
2348
+ usage?.lastUsed
2349
+ );
2350
+ const result = {
2351
+ id: memory.id,
2352
+ memoryType: memory.memoryType,
2353
+ text: memory.text,
2354
+ summary: memory.summary,
2355
+ tags: memory.tags,
2356
+ sourceRefs: memory.sourceRefs,
2357
+ score: computeCompositeScore(
2358
+ textScore + consolidationBoost,
2359
+ memory.createdAt,
2360
+ memory.confidence,
2361
+ usageBoost
2362
+ ),
2363
+ source: "local",
2364
+ status: memory.status,
2365
+ supersedesId: memory.supersedesId,
2366
+ isConsolidation: memory.isConsolidation,
2367
+ consolidationVersion: memory.consolidationVersion
2368
+ };
2369
+ if (query.includeConsolidatedSources && memory.isConsolidation) {
2370
+ const sources = this.getConsolidatedSources(memory.id);
2371
+ result.sourceMemories = sources.map((src) => ({
2372
+ id: src.id,
2373
+ memoryType: src.memoryType,
2374
+ text: src.text,
2375
+ summary: src.summary,
2376
+ tags: src.tags,
2377
+ sourceRefs: src.sourceRefs,
2378
+ score: 0,
2379
+ source: "local"
2380
+ }));
2381
+ }
2382
+ return result;
2383
+ });
2384
+ if (query.tags && query.tags.length > 0) {
2385
+ results = results.filter((r) => {
2386
+ const memTags = r.tags;
2387
+ return query.tags.some((t) => memTags.includes(t));
2388
+ });
2389
+ }
2390
+ return results.sort((a, b) => b.score - a.score).slice(0, k);
2391
+ }
2392
+ list(query) {
2393
+ const conditions = ["org_id = ?", "repo_id = ?"];
2394
+ const params = [query.orgId, query.repoId];
2395
+ if (!query.includeExpired) {
2396
+ conditions.push(nonExpiredMemoryClause());
2397
+ }
2398
+ if (query.types && query.types.length > 0) {
2399
+ conditions.push(
2400
+ `memory_type IN (${query.types.map(() => "?").join(",")})`
2401
+ );
2402
+ params.push(...query.types);
2403
+ }
2404
+ if (query.status && query.status.length > 0) {
2405
+ conditions.push(
2406
+ `status IN (${query.status.map(() => "?").join(",")})`
2407
+ );
2408
+ params.push(...query.status);
2409
+ }
2410
+ if (query.visibility && query.visibility.length > 0) {
2411
+ conditions.push(
2412
+ `visibility IN (${query.visibility.map(() => "?").join(",")})`
2413
+ );
2414
+ params.push(...query.visibility);
2415
+ }
2416
+ if (query.search) {
2417
+ const rawSearch = query.search.replace(/[^\w\s]/g, " ").trim();
2418
+ const searchWords = rawSearch.split(/\s+/).filter((w) => w.length >= 2);
2419
+ const ftsSearch = searchWords.length > 0 ? `(${searchWords.map((w) => `${w}*`).join(" OR ")})` : "";
2420
+ if (ftsSearch) {
2421
+ conditions.push(
2422
+ "rowid IN (SELECT rowid FROM memories_fts WHERE memories_fts MATCH ?)"
2423
+ );
2424
+ params.push(ftsSearch);
2425
+ }
2426
+ }
2427
+ const sortCol = query.sortBy === "updatedAt" ? "updated_at" : query.sortBy === "confidence" ? "confidence" : "created_at";
2428
+ const sortDir = query.sortOrder === "asc" ? "ASC" : "DESC";
2429
+ const limit = query.limit ?? 50;
2430
+ const offset = query.offset ?? 0;
2431
+ const sql = `
2432
+ SELECT * FROM memories
2433
+ WHERE ${conditions.join(" AND ")}
2434
+ ORDER BY ${sortCol} ${sortDir}
2435
+ LIMIT ? OFFSET ?
2436
+ `;
2437
+ params.push(limit, offset);
2438
+ const rows = this.db.prepare(sql).all(...params);
2439
+ return rows.map(rowToMemory);
2440
+ }
2441
+ count(query) {
2442
+ const conditions = ["org_id = ?", "repo_id = ?"];
2443
+ const params = [query.orgId, query.repoId];
2444
+ if (!query.includeExpired) {
2445
+ conditions.push(nonExpiredMemoryClause());
2446
+ }
2447
+ if (query.types && query.types.length > 0) {
2448
+ conditions.push(
2449
+ `memory_type IN (${query.types.map(() => "?").join(",")})`
2450
+ );
2451
+ params.push(...query.types);
2452
+ }
2453
+ if (query.status && query.status.length > 0) {
2454
+ conditions.push(
2455
+ `status IN (${query.status.map(() => "?").join(",")})`
2456
+ );
2457
+ params.push(...query.status);
2458
+ }
2459
+ if (query.visibility && query.visibility.length > 0) {
2460
+ conditions.push(
2461
+ `visibility IN (${query.visibility.map(() => "?").join(",")})`
2462
+ );
2463
+ params.push(...query.visibility);
2464
+ }
2465
+ if (query.search) {
2466
+ const rawSearch = query.search.replace(/[^\w\s]/g, " ").trim();
2467
+ const searchWords = rawSearch.split(/\s+/).filter((w) => w.length >= 2);
2468
+ const ftsSearch = searchWords.length > 0 ? `(${searchWords.map((w) => `${w}*`).join(" OR ")})` : "";
2469
+ if (ftsSearch) {
2470
+ conditions.push(
2471
+ "rowid IN (SELECT rowid FROM memories_fts WHERE memories_fts MATCH ?)"
2472
+ );
2473
+ params.push(ftsSearch);
2474
+ }
2475
+ }
2476
+ const sql = `SELECT COUNT(*) as cnt FROM memories WHERE ${conditions.join(" AND ")}`;
2477
+ const row = this.db.prepare(sql).get(...params);
2478
+ return row.cnt;
2479
+ }
2480
+ stats(orgId, repoId) {
2481
+ const rows = this.db.prepare(
2482
+ `SELECT memory_type, status, visibility, COUNT(*) as cnt
2483
+ FROM memories WHERE org_id = ? AND repo_id = ?
2484
+ GROUP BY memory_type, status, visibility`
2485
+ ).all(orgId, repoId);
2486
+ const stats = {
2487
+ total: 0,
2488
+ byType: { episodic: 0, semantic: 0, procedural: 0 },
2489
+ byStatus: { active: 0, deprecated: 0, superseded: 0, deleted: 0 },
2490
+ byVisibility: { private: 0, repo: 0 }
2491
+ };
2492
+ for (const row of rows) {
2493
+ stats.total += row.cnt;
2494
+ if (row.memory_type in stats.byType) {
2495
+ stats.byType[row.memory_type] += row.cnt;
2496
+ }
2497
+ if (row.status in stats.byStatus) {
2498
+ stats.byStatus[row.status] += row.cnt;
2499
+ }
2500
+ if (row.visibility in stats.byVisibility) {
2501
+ stats.byVisibility[row.visibility] += row.cnt;
2502
+ }
2503
+ }
2504
+ return stats;
2505
+ }
2506
+ deprecate(id, reason) {
2507
+ const now = (/* @__PURE__ */ new Date()).toISOString();
2508
+ const result = this.db.prepare(
2509
+ "UPDATE memories SET status = 'deprecated', updated_at = ? WHERE id = ?"
2510
+ ).run(now, id);
2511
+ if (reason && result.changes > 0) {
2512
+ const mem = this.getById(id);
2513
+ if (mem) {
2514
+ const refs = mem.sourceRefs ?? {};
2515
+ refs.deprecation_reason = reason;
2516
+ this.db.prepare("UPDATE memories SET source_refs = ? WHERE id = ?").run(JSON.stringify(refs), id);
2517
+ }
2518
+ }
2519
+ return result.changes > 0;
2520
+ }
2521
+ supersede(oldId, newId) {
2522
+ const now = (/* @__PURE__ */ new Date()).toISOString();
2523
+ const result = this.db.prepare(
2524
+ "UPDATE memories SET status = 'superseded', supersedes_id = ?, updated_at = ? WHERE id = ?"
2525
+ ).run(newId, now, oldId);
2526
+ return result.changes > 0;
2527
+ }
2528
+ updateVisibility(id, visibility) {
2529
+ const now = (/* @__PURE__ */ new Date()).toISOString();
2530
+ const result = this.db.prepare(
2531
+ "UPDATE memories SET visibility = ?, updated_at = ? WHERE id = ?"
2532
+ ).run(visibility, now, id);
2533
+ return result.changes > 0;
2534
+ }
2535
+ expireExpiredMemories(orgId, repoId, deletedBy = "system:ttl-expiry") {
2536
+ const conditions = [
2537
+ "status = 'active'",
2538
+ "ttl_seconds IS NOT NULL",
2539
+ "datetime(created_at, '+' || ttl_seconds || ' seconds') < datetime('now')"
2540
+ ];
2541
+ const params = [];
2542
+ if (orgId) {
2543
+ conditions.push("org_id = ?");
2544
+ params.push(orgId);
2545
+ }
2546
+ if (repoId) {
2547
+ conditions.push("repo_id = ?");
2548
+ params.push(repoId);
2549
+ }
2550
+ const rows = this.db.prepare(
2551
+ `SELECT id FROM memories WHERE ${conditions.join(" AND ")}`
2552
+ ).all(...params);
2553
+ let expired = 0;
2554
+ for (const row of rows) {
2555
+ if (this.softDelete({ id: row.id, deletedBy })) {
2556
+ expired += 1;
2557
+ }
2558
+ }
2559
+ return expired;
2560
+ }
2561
+ purgeExpired() {
2562
+ return this.expireExpiredMemories();
2563
+ }
2564
+ link(input) {
2565
+ const id = uuid();
2566
+ const now = (/* @__PURE__ */ new Date()).toISOString();
2567
+ this.db.prepare(
2568
+ `INSERT INTO memory_links (id, source_id, target_id, link_type, metadata, created_at)
2569
+ VALUES (?, ?, ?, ?, ?, ?)`
2570
+ ).run(
2571
+ id,
2572
+ input.sourceId,
2573
+ input.targetId,
2574
+ input.linkType,
2575
+ input.metadata ? JSON.stringify(input.metadata) : null,
2576
+ now
2577
+ );
2578
+ return this.getLinkById(id);
2579
+ }
2580
+ unlink(sourceId, targetId, linkType) {
2581
+ const result = this.db.prepare(
2582
+ "DELETE FROM memory_links WHERE source_id = ? AND target_id = ? AND link_type = ?"
2583
+ ).run(sourceId, targetId, linkType);
2584
+ return result.changes > 0;
2585
+ }
2586
+ getLinks(query) {
2587
+ const conditions = [
2588
+ "(source_id = ? OR target_id = ?)"
2589
+ ];
2590
+ const params = [query.memoryId, query.memoryId];
2591
+ if (query.linkType) {
2592
+ conditions.push("link_type = ?");
2593
+ params.push(query.linkType);
2594
+ }
2595
+ const sql = `SELECT * FROM memory_links WHERE ${conditions.join(" AND ")} ORDER BY created_at DESC`;
2596
+ const rows = this.db.prepare(sql).all(...params);
2597
+ return rows.map(rowToLink);
2598
+ }
2599
+ getLinkedMemories(memoryId, linkType) {
2600
+ const conditions = [
2601
+ "(l.source_id = ? OR l.target_id = ?)"
2602
+ ];
2603
+ const params = [memoryId, memoryId];
2604
+ if (linkType) {
2605
+ conditions.push("l.link_type = ?");
2606
+ params.push(linkType);
2607
+ }
2608
+ const sql = `
2609
+ SELECT m.* FROM memories m
2610
+ JOIN memory_links l ON (
2611
+ (l.source_id = ? AND l.target_id = m.id) OR
2612
+ (l.target_id = ? AND l.source_id = m.id)
2613
+ )
2614
+ ${linkType ? "WHERE l.link_type = ?" : ""}
2615
+ ORDER BY m.created_at DESC
2616
+ `;
2617
+ const linkedParams = linkType ? [memoryId, memoryId, linkType] : [memoryId, memoryId];
2618
+ const rows = this.db.prepare(sql).all(...linkedParams);
2619
+ return rows.map(rowToMemory);
2620
+ }
2621
+ getLinkById(id) {
2622
+ const row = this.db.prepare("SELECT * FROM memory_links WHERE id = ?").get(id);
2623
+ return row ? rowToLink(row) : void 0;
2624
+ }
2625
+ consolidateMemories(input) {
2626
+ const { sourceIds, consolidatedText, memoryType, tags, preserveOriginals = true } = input;
2627
+ const orgId = input.orgId.toLowerCase();
2628
+ const repoId = input.repoId.toLowerCase();
2629
+ if (sourceIds.length < 2) {
2630
+ throw new Error("At least 2 source memories are required for consolidation");
2631
+ }
2632
+ const sourceMemories = sourceIds.map((id2) => this.getById(id2)).filter((m) => m !== void 0);
2633
+ if (sourceMemories.length !== sourceIds.length) {
2634
+ const foundIds = sourceMemories.map((m) => m.id);
2635
+ const missingIds = sourceIds.filter((id2) => !foundIds.includes(id2));
2636
+ throw new Error(`Source memories not found: ${missingIds.join(", ")}`);
2637
+ }
2638
+ const inferredType = memoryType ?? this.inferMemoryType(sourceMemories);
2639
+ const mergedTags = tags ?? this.mergeTags(sourceMemories);
2640
+ const inheritedVisibility = sourceMemories.some((m) => m.visibility === "repo") ? "repo" : "private";
2641
+ const id = uuid();
2642
+ const now = (/* @__PURE__ */ new Date()).toISOString();
2643
+ const version = 1;
2644
+ this.db.prepare(
2645
+ `INSERT INTO memories
2646
+ (id, org_id, repo_id, scope_type, memory_type, visibility, status, text, summary, tags, source_refs, confidence, is_consolidation, consolidation_version, created_at, updated_at)
2647
+ VALUES (?, ?, ?, 'repo', ?, ?, 'active', ?, ?, ?, ?, ?, 1, ?, ?, ?)`
2648
+ ).run(
2649
+ id,
2650
+ orgId,
2651
+ repoId,
2652
+ inferredType,
2653
+ inheritedVisibility,
2654
+ consolidatedText,
2655
+ null,
2656
+ JSON.stringify(mergedTags),
2657
+ JSON.stringify({ consolidated_from: sourceIds }),
2658
+ null,
2659
+ version,
2660
+ now,
2661
+ now
2662
+ );
2663
+ for (const sourceId of sourceIds) {
2664
+ this.link({
2665
+ sourceId: id,
2666
+ targetId: sourceId,
2667
+ linkType: "derived_from",
2668
+ metadata: { consolidation: true }
2669
+ });
2670
+ }
2671
+ if (preserveOriginals) {
2672
+ for (const sourceId of sourceIds) {
2673
+ this.supersede(sourceId, id);
2674
+ }
2675
+ }
2676
+ if (inheritedVisibility === "repo") {
2677
+ this.setSyncState({
2678
+ memoryId: id,
2679
+ localVersion: version,
2680
+ syncStatus: "pending_push"
2681
+ });
2682
+ }
2683
+ return {
2684
+ consolidatedId: id,
2685
+ version,
2686
+ sourcesPreserved: sourceIds.length,
2687
+ sourceIds
2688
+ };
2689
+ }
2690
+ reconsolidate(input) {
2691
+ const { existingConsolidationId, additionalSourceIds = [], newText, tags } = input;
2692
+ const orgId = input.orgId.toLowerCase();
2693
+ const repoId = input.repoId.toLowerCase();
2694
+ const existing = this.getById(existingConsolidationId);
2695
+ if (!existing) {
2696
+ throw new Error(`Consolidation not found: ${existingConsolidationId}`);
2697
+ }
2698
+ if (!existing.isConsolidation) {
2699
+ throw new Error(`Memory ${existingConsolidationId} is not a consolidation`);
2700
+ }
2701
+ const existingLinks = this.getLinks({ memoryId: existingConsolidationId, linkType: "derived_from" });
2702
+ const existingSourceIds = existingLinks.filter((l) => l.sourceId === existingConsolidationId).map((l) => l.targetId);
2703
+ const allSourceIds = [.../* @__PURE__ */ new Set([...existingSourceIds, ...additionalSourceIds])];
2704
+ for (const id2 of additionalSourceIds) {
2705
+ const mem = this.getById(id2);
2706
+ if (!mem) {
2707
+ throw new Error(`Additional source memory not found: ${id2}`);
2708
+ }
2709
+ }
2710
+ const newVersion = (existing.consolidationVersion ?? 1) + 1;
2711
+ const mergedTags = tags ?? existing.tags;
2712
+ const inheritedVisibility = existing.visibility;
2713
+ const id = uuid();
2714
+ const now = (/* @__PURE__ */ new Date()).toISOString();
2715
+ this.db.prepare(
2716
+ `INSERT INTO memories
2717
+ (id, org_id, repo_id, scope_type, memory_type, visibility, status, text, summary, tags, source_refs, confidence, is_consolidation, consolidation_version, created_at, updated_at)
2718
+ VALUES (?, ?, ?, 'repo', ?, ?, 'active', ?, ?, ?, ?, ?, 1, ?, ?, ?)`
2719
+ ).run(
2720
+ id,
2721
+ orgId,
2722
+ repoId,
2723
+ existing.memoryType,
2724
+ inheritedVisibility,
2725
+ newText,
2726
+ null,
2727
+ JSON.stringify(mergedTags),
2728
+ JSON.stringify({
2729
+ consolidated_from: allSourceIds,
2730
+ previous_consolidation: existingConsolidationId
2731
+ }),
2732
+ null,
2733
+ newVersion,
2734
+ now,
2735
+ now
2736
+ );
2737
+ this.link({
2738
+ sourceId: id,
2739
+ targetId: existingConsolidationId,
2740
+ linkType: "derived_from",
2741
+ metadata: { reconsolidation: true, previous_version: existing.consolidationVersion ?? 1 }
2742
+ });
2743
+ for (const sourceId of additionalSourceIds) {
2744
+ this.link({
2745
+ sourceId: id,
2746
+ targetId: sourceId,
2747
+ linkType: "derived_from",
2748
+ metadata: { consolidation: true }
2749
+ });
2750
+ this.supersede(sourceId, id);
2751
+ }
2752
+ this.supersede(existingConsolidationId, id);
2753
+ if (inheritedVisibility === "repo") {
2754
+ this.setSyncState({
2755
+ memoryId: id,
2756
+ localVersion: newVersion,
2757
+ syncStatus: "pending_push"
2758
+ });
2759
+ }
2760
+ return {
2761
+ consolidatedId: id,
2762
+ version: newVersion,
2763
+ sourcesPreserved: allSourceIds.length,
2764
+ sourceIds: allSourceIds
2765
+ };
2766
+ }
2767
+ findSimilar(query) {
2768
+ const { orgId, repoId, memoryId, threshold = 0.3, k = 10 } = query;
2769
+ const memory = this.getById(memoryId);
2770
+ if (!memory) {
2771
+ throw new Error(`Memory not found: ${memoryId}`);
2772
+ }
2773
+ const results = this.recall({
2774
+ orgId,
2775
+ repoId,
2776
+ query: memory.text,
2777
+ k: k + 1
2778
+ });
2779
+ return results.filter((r) => r.id !== memoryId && r.score >= threshold).slice(0, k);
2780
+ }
2781
+ getConsolidationHistory(memoryId) {
2782
+ const memory = this.getById(memoryId);
2783
+ if (!memory) {
2784
+ return [];
2785
+ }
2786
+ const history = [];
2787
+ if (memory.isConsolidation) {
2788
+ const sourceLinks = this.getLinks({ memoryId, linkType: "derived_from" });
2789
+ for (const link of sourceLinks) {
2790
+ const targetId = link.sourceId === memoryId ? link.targetId : link.sourceId;
2791
+ const target = this.getById(targetId);
2792
+ if (target) {
2793
+ history.push(target);
2794
+ if (target.isConsolidation) {
2795
+ history.push(...this.getConsolidationHistory(targetId));
2796
+ }
2797
+ }
2798
+ }
2799
+ }
2800
+ return history;
2801
+ }
2802
+ getConsolidatedSources(consolidationId) {
2803
+ const memory = this.getById(consolidationId);
2804
+ if (!memory || !memory.isConsolidation) {
2805
+ return [];
2806
+ }
2807
+ const sourceLinks = this.getLinks({ memoryId: consolidationId, linkType: "derived_from" });
2808
+ const sources = [];
2809
+ for (const link of sourceLinks) {
2810
+ if (link.sourceId === consolidationId) {
2811
+ const source = this.getById(link.targetId);
2812
+ if (source && !source.isConsolidation) {
2813
+ sources.push(source);
2814
+ }
2815
+ }
2816
+ }
2817
+ return sources;
2818
+ }
2819
+ inferMemoryType(memories) {
2820
+ const typeCounts = { episodic: 0, semantic: 0, procedural: 0 };
2821
+ for (const m of memories) {
2822
+ typeCounts[m.memoryType]++;
2823
+ }
2824
+ if (typeCounts.procedural > 0) return "procedural";
2825
+ if (typeCounts.semantic >= typeCounts.episodic) return "semantic";
2826
+ return "episodic";
2827
+ }
2828
+ mergeTags(memories) {
2829
+ const tagSet = /* @__PURE__ */ new Set();
2830
+ for (const m of memories) {
2831
+ for (const tag of m.tags) {
2832
+ tagSet.add(tag);
2833
+ }
2834
+ }
2835
+ return Array.from(tagSet);
2836
+ }
2837
+ softDelete(input) {
2838
+ const memory = this.getById(input.id);
2839
+ if (!memory) return false;
2840
+ const now = (/* @__PURE__ */ new Date()).toISOString();
2841
+ const newVersion = (memory.version ?? 1) + 1;
2842
+ const result = this.db.transaction(() => {
2843
+ this.db.prepare(
2844
+ `UPDATE memories
2845
+ SET status = 'deleted', deleted_at = ?, deleted_by = ?, version = ?, updated_at = ?
2846
+ WHERE id = ?`
2847
+ ).run(now, input.deletedBy ?? null, newVersion, now, input.id);
2848
+ this.db.prepare(
2849
+ `INSERT OR REPLACE INTO tombstones (id, memory_id, org_id, repo_id, deleted_at, deleted_by, created_at)
2850
+ VALUES (?, ?, ?, ?, ?, ?, ?)`
2851
+ ).run(
2852
+ uuid(),
2853
+ input.id,
2854
+ memory.orgId,
2855
+ memory.repoId,
2856
+ now,
2857
+ input.deletedBy ?? null,
2858
+ now
2859
+ );
2860
+ return true;
2861
+ })();
2862
+ return result;
2863
+ }
2864
+ hardDelete(id) {
2865
+ const result = this.db.prepare("DELETE FROM memories WHERE id = ?").run(id);
2866
+ return result.changes > 0;
2867
+ }
2868
+ restore(id) {
2869
+ const now = (/* @__PURE__ */ new Date()).toISOString();
2870
+ const result = this.db.transaction(() => {
2871
+ const updateResult = this.db.prepare(
2872
+ `UPDATE memories
2873
+ SET status = 'active', deleted_at = NULL, deleted_by = NULL, version = version + 1, updated_at = ?
2874
+ WHERE id = ? AND status = 'deleted'`
2875
+ ).run(now, id);
2876
+ if (updateResult.changes > 0) {
2877
+ this.db.prepare("DELETE FROM tombstones WHERE memory_id = ?").run(id);
2878
+ }
2879
+ return updateResult.changes > 0;
2880
+ })();
2881
+ return result;
2882
+ }
2883
+ getTombstones(orgId, repoId, sinceSyncedAt) {
2884
+ let sql = "SELECT * FROM tombstones WHERE org_id = ? AND repo_id = ?";
2885
+ const params = [orgId, repoId];
2886
+ if (sinceSyncedAt) {
2887
+ sql += " AND (synced_at IS NULL OR synced_at > ?)";
2888
+ params.push(sinceSyncedAt.toISOString());
2889
+ } else {
2890
+ sql += " AND synced_at IS NULL";
2891
+ }
2892
+ sql += " ORDER BY deleted_at ASC";
2893
+ const rows = this.db.prepare(sql).all(...params);
2894
+ return rows.map(rowToTombstone);
2895
+ }
2896
+ getUnsyncedTombstones(orgId, repoId) {
2897
+ const rows = this.db.prepare(
2898
+ "SELECT * FROM tombstones WHERE org_id = ? AND repo_id = ? AND synced_at IS NULL ORDER BY deleted_at ASC"
2899
+ ).all(orgId, repoId);
2900
+ return rows.map(rowToTombstone);
2901
+ }
2902
+ markTombstoneSynced(memoryId) {
2903
+ const now = (/* @__PURE__ */ new Date()).toISOString();
2904
+ const result = this.db.prepare("UPDATE tombstones SET synced_at = ? WHERE memory_id = ?").run(now, memoryId);
2905
+ return result.changes > 0;
2906
+ }
2907
+ applyTombstone(tombstone) {
2908
+ const memory = this.getById(tombstone.memoryId);
2909
+ if (!memory) {
2910
+ this.db.prepare(
2911
+ `INSERT OR REPLACE INTO tombstones (id, memory_id, org_id, repo_id, deleted_at, deleted_by, synced_at, created_at)
2912
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)`
2913
+ ).run(
2914
+ tombstone.id,
2915
+ tombstone.memoryId,
2916
+ tombstone.orgId,
2917
+ tombstone.repoId,
2918
+ tombstone.deletedAt.toISOString(),
2919
+ tombstone.deletedBy ?? null,
2920
+ (/* @__PURE__ */ new Date()).toISOString(),
2921
+ (/* @__PURE__ */ new Date()).toISOString()
2922
+ );
2923
+ return true;
2924
+ }
2925
+ return this.softDelete({
2926
+ id: tombstone.memoryId,
2927
+ deletedBy: tombstone.deletedBy
2928
+ });
2929
+ }
2930
+ incrementVersion(id) {
2931
+ const now = (/* @__PURE__ */ new Date()).toISOString();
2932
+ this.db.prepare("UPDATE memories SET version = version + 1, updated_at = ? WHERE id = ?").run(now, id);
2933
+ const row = this.db.prepare("SELECT version FROM memories WHERE id = ?").get(id);
2934
+ return row?.version ?? 1;
2935
+ }
2936
+ getModifiedSince(orgId, repoId, since) {
2937
+ const rows = this.db.prepare(
2938
+ `SELECT * FROM memories
2939
+ WHERE org_id = ? AND repo_id = ? AND updated_at > ?
2940
+ ORDER BY updated_at ASC`
2941
+ ).all(orgId, repoId, since.toISOString());
2942
+ return rows.map(rowToMemory);
2943
+ }
2944
+ upsertFromRemote(memory) {
2945
+ const existing = this.getById(memory.id);
2946
+ const now = (/* @__PURE__ */ new Date()).toISOString();
2947
+ const normalizedOrgId = memory.orgId.toLowerCase();
2948
+ const normalizedRepoId = memory.repoId.toLowerCase();
2949
+ if (!existing) {
2950
+ this.db.prepare(
2951
+ `INSERT INTO memories
2952
+ (id, org_id, repo_id, scope_type, memory_type, visibility, status, text, summary, tags, source_refs, confidence, ttl_seconds, supersedes_id, is_consolidation, consolidation_version, author_id, author_name, version, deleted_at, deleted_by, created_at, updated_at)
2953
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
2954
+ ).run(
2955
+ memory.id,
2956
+ normalizedOrgId,
2957
+ normalizedRepoId,
2958
+ memory.scopeType ?? "repo",
2959
+ memory.memoryType,
2960
+ memory.visibility,
2961
+ memory.status,
2962
+ memory.text,
2963
+ memory.summary ?? null,
2964
+ JSON.stringify(memory.tags ?? []),
2965
+ memory.sourceRefs ? JSON.stringify(memory.sourceRefs) : null,
2966
+ memory.confidence ?? null,
2967
+ memory.ttlSeconds ?? null,
2968
+ memory.supersedesId ?? null,
2969
+ memory.isConsolidation ? 1 : 0,
2970
+ memory.consolidationVersion ?? null,
2971
+ memory.authorId ?? null,
2972
+ memory.authorName ?? null,
2973
+ memory.version ?? 1,
2974
+ memory.deletedAt?.toISOString() ?? null,
2975
+ memory.deletedBy ?? null,
2976
+ memory.createdAt.toISOString(),
2977
+ now
2978
+ );
2979
+ return { action: "created", conflict: false };
2980
+ }
2981
+ const remoteVersion = memory.version ?? 1;
2982
+ const localVersion = existing.version ?? 1;
2983
+ if (remoteVersion <= localVersion) {
2984
+ if (memory.updatedAt <= existing.updatedAt) {
2985
+ return { action: "skipped", conflict: false };
2986
+ }
2987
+ }
2988
+ const hasConflict = localVersion !== remoteVersion && existing.updatedAt > memory.updatedAt;
2989
+ this.db.prepare(
2990
+ `UPDATE memories SET
2991
+ memory_type = ?, visibility = ?, status = ?, text = ?, summary = ?, tags = ?,
2992
+ source_refs = ?, confidence = ?, ttl_seconds = ?, supersedes_id = ?,
2993
+ is_consolidation = ?, consolidation_version = ?, author_id = ?, author_name = ?,
2994
+ version = ?, deleted_at = ?, deleted_by = ?, updated_at = ?
2995
+ WHERE id = ?`
2996
+ ).run(
2997
+ memory.memoryType,
2998
+ memory.visibility,
2999
+ memory.status,
3000
+ memory.text,
3001
+ memory.summary ?? null,
3002
+ JSON.stringify(memory.tags ?? []),
3003
+ memory.sourceRefs ? JSON.stringify(memory.sourceRefs) : null,
3004
+ memory.confidence ?? null,
3005
+ memory.ttlSeconds ?? null,
3006
+ memory.supersedesId ?? null,
3007
+ memory.isConsolidation ? 1 : 0,
3008
+ memory.consolidationVersion ?? null,
3009
+ memory.authorId ?? null,
3010
+ memory.authorName ?? null,
3011
+ Math.max(remoteVersion, localVersion) + 1,
3012
+ memory.deletedAt?.toISOString() ?? null,
3013
+ memory.deletedBy ?? null,
3014
+ now,
3015
+ memory.id
3016
+ );
3017
+ return { action: "updated", conflict: hasConflict };
3018
+ }
3019
+ getSyncState(memoryId) {
3020
+ const row = this.db.prepare("SELECT * FROM sync_state WHERE memory_id = ?").get(memoryId);
3021
+ return row ? this.rowToSyncState(row) : void 0;
3022
+ }
3023
+ getAllSyncStates() {
3024
+ const rows = this.db.prepare("SELECT * FROM sync_state").all();
3025
+ return rows.map((row) => this.rowToSyncState(row));
3026
+ }
3027
+ getSyncStatesByStatus(status) {
3028
+ const rows = this.db.prepare("SELECT * FROM sync_state WHERE sync_status = ?").all(status);
3029
+ return rows.map((row) => this.rowToSyncState(row));
3030
+ }
3031
+ getPendingPush() {
3032
+ const rows = this.db.prepare(`
3033
+ SELECT m.*, s.local_version as sync_local_version, s.remote_version as sync_remote_version,
3034
+ s.last_pushed_at, s.last_pulled_at, s.sync_status
3035
+ FROM memories m
3036
+ JOIN sync_state s ON m.id = s.memory_id
3037
+ WHERE s.sync_status = 'pending_push'
3038
+ ORDER BY m.updated_at ASC
3039
+ `).all();
3040
+ return rows.map((row) => ({
3041
+ memory: rowToMemory(row),
3042
+ syncState: {
3043
+ memoryId: row.id,
3044
+ localVersion: row.sync_local_version,
3045
+ remoteVersion: row.sync_remote_version,
3046
+ lastPushedAt: row.last_pushed_at ? new Date(row.last_pushed_at) : void 0,
3047
+ lastPulledAt: row.last_pulled_at ? new Date(row.last_pulled_at) : void 0,
3048
+ syncStatus: row.sync_status
3049
+ }
3050
+ }));
3051
+ }
3052
+ getConflicts() {
3053
+ const rows = this.db.prepare(`
3054
+ SELECT m.*, s.local_version as sync_local_version, s.remote_version as sync_remote_version,
3055
+ s.last_pushed_at, s.last_pulled_at, s.sync_status
3056
+ FROM memories m
3057
+ JOIN sync_state s ON m.id = s.memory_id
3058
+ WHERE s.sync_status = 'conflict'
3059
+ ORDER BY m.updated_at ASC
3060
+ `).all();
3061
+ return rows.map((row) => ({
3062
+ memory: rowToMemory(row),
3063
+ syncState: {
3064
+ memoryId: row.id,
3065
+ localVersion: row.sync_local_version,
3066
+ remoteVersion: row.sync_remote_version,
3067
+ lastPushedAt: row.last_pushed_at ? new Date(row.last_pushed_at) : void 0,
3068
+ lastPulledAt: row.last_pulled_at ? new Date(row.last_pulled_at) : void 0,
3069
+ syncStatus: row.sync_status
3070
+ }
3071
+ }));
3072
+ }
3073
+ setSyncState(state) {
3074
+ this.db.prepare(`
3075
+ INSERT OR REPLACE INTO sync_state (memory_id, local_version, remote_version, last_pushed_at, last_pulled_at, sync_status)
3076
+ VALUES (?, ?, ?, ?, ?, ?)
3077
+ `).run(
3078
+ state.memoryId,
3079
+ state.localVersion,
3080
+ state.remoteVersion ?? null,
3081
+ state.lastPushedAt?.toISOString() ?? null,
3082
+ state.lastPulledAt?.toISOString() ?? null,
3083
+ state.syncStatus
3084
+ );
3085
+ }
3086
+ markAsPushed(memoryId, remoteVersion) {
3087
+ const now = (/* @__PURE__ */ new Date()).toISOString();
3088
+ this.db.prepare(`
3089
+ UPDATE sync_state
3090
+ SET sync_status = 'synced', remote_version = ?, last_pushed_at = ?
3091
+ WHERE memory_id = ?
3092
+ `).run(remoteVersion, now, memoryId);
3093
+ }
3094
+ markAsPulled(memoryId, localVersion) {
3095
+ const now = (/* @__PURE__ */ new Date()).toISOString();
3096
+ this.db.prepare(`
3097
+ UPDATE sync_state
3098
+ SET sync_status = 'synced', local_version = ?, last_pulled_at = ?
3099
+ WHERE memory_id = ?
3100
+ `).run(localVersion, now, memoryId);
3101
+ }
3102
+ markAsConflict(memoryId, remoteVersion) {
3103
+ this.db.prepare(`
3104
+ UPDATE sync_state
3105
+ SET sync_status = 'conflict', remote_version = ?
3106
+ WHERE memory_id = ?
3107
+ `).run(remoteVersion, memoryId);
3108
+ }
3109
+ getUntrackedMemories(orgId, repoId) {
3110
+ const rows = this.db.prepare(`
3111
+ SELECT m.* FROM memories m
3112
+ LEFT JOIN sync_state s ON m.id = s.memory_id
3113
+ WHERE m.org_id = ? AND m.repo_id = ? AND s.memory_id IS NULL
3114
+ ORDER BY m.created_at ASC
3115
+ `).all(orgId, repoId);
3116
+ return rows.map(rowToMemory);
3117
+ }
3118
+ initSyncStateForMemory(memoryId) {
3119
+ const memory = this.getById(memoryId);
3120
+ if (!memory) return;
3121
+ const existing = this.getSyncState(memoryId);
3122
+ if (existing) return;
3123
+ this.setSyncState({
3124
+ memoryId,
3125
+ localVersion: memory.version,
3126
+ syncStatus: "pending_push"
3127
+ });
3128
+ }
3129
+ getSyncSummary(orgId, repoId) {
3130
+ const row = this.db.prepare(`
3131
+ SELECT
3132
+ SUM(CASE WHEN s.sync_status = 'synced' THEN 1 ELSE 0 END) as synced,
3133
+ SUM(CASE WHEN s.sync_status = 'pending_push' THEN 1 ELSE 0 END) as pending_push,
3134
+ SUM(CASE WHEN s.sync_status = 'pending_pull' THEN 1 ELSE 0 END) as pending_pull,
3135
+ SUM(CASE WHEN s.sync_status = 'conflict' THEN 1 ELSE 0 END) as conflicts
3136
+ FROM sync_state s
3137
+ JOIN memories m ON s.memory_id = m.id
3138
+ WHERE m.org_id = ? AND m.repo_id = ?
3139
+ `).get(orgId, repoId);
3140
+ return {
3141
+ synced: row.synced ?? 0,
3142
+ pendingPush: row.pending_push ?? 0,
3143
+ pendingPull: row.pending_pull ?? 0,
3144
+ conflicts: row.conflicts ?? 0
3145
+ };
3146
+ }
3147
+ rowToSyncState(row) {
3148
+ return {
3149
+ memoryId: row.memory_id,
3150
+ localVersion: row.local_version,
3151
+ remoteVersion: row.remote_version,
3152
+ lastPushedAt: row.last_pushed_at ? new Date(row.last_pushed_at) : void 0,
3153
+ lastPulledAt: row.last_pulled_at ? new Date(row.last_pulled_at) : void 0,
3154
+ syncStatus: row.sync_status
3155
+ };
3156
+ }
3157
+ getSupersededMemoriesToSync(orgId, repoId) {
3158
+ const rows = this.db.prepare(`
3159
+ SELECT m.*
3160
+ FROM memories m
3161
+ LEFT JOIN sync_state s ON s.memory_id = m.id
3162
+ WHERE m.org_id = ?
3163
+ AND m.repo_id = ?
3164
+ AND m.status = 'superseded'
3165
+ AND m.supersedes_id IS NOT NULL
3166
+ AND (
3167
+ s.memory_id IS NULL
3168
+ OR s.sync_status = 'pending_push'
3169
+ OR (s.sync_status = 'synced' AND (s.last_pushed_at IS NULL OR s.last_pushed_at < m.updated_at))
3170
+ )
3171
+ `).all(orgId, repoId);
3172
+ return rows.map((row) => ({
3173
+ memory: rowToMemory(row),
3174
+ newId: row.supersedes_id
3175
+ }));
3176
+ }
3177
+ getLinksToSync(orgId, repoId) {
3178
+ const rows = this.db.prepare(`
3179
+ SELECT l.*, ms.id as source_mem_id, mt.id as target_mem_id
3180
+ FROM memory_links l
3181
+ JOIN memories ms ON ms.id = l.source_id
3182
+ JOIN memories mt ON mt.id = l.target_id
3183
+ WHERE ms.org_id = ?
3184
+ AND ms.repo_id = ?
3185
+ AND l.id NOT IN (SELECT link_id FROM synced_links)
3186
+ `).all(orgId, repoId);
3187
+ return rows.map((row) => ({
3188
+ link: rowToLink(row),
3189
+ sourceMemoryId: row.source_mem_id,
3190
+ targetMemoryId: row.target_mem_id
3191
+ }));
3192
+ }
3193
+ markLinkSynced(linkId) {
3194
+ const now = (/* @__PURE__ */ new Date()).toISOString();
3195
+ this.db.prepare(`INSERT OR IGNORE INTO synced_links (link_id, synced_at) VALUES (?, ?)`).run(linkId, now);
3196
+ }
3197
+ markStatusSynced(memoryId) {
3198
+ const now = (/* @__PURE__ */ new Date()).toISOString();
3199
+ this.db.prepare(`UPDATE sync_state SET last_pushed_at = ? WHERE memory_id = ?`).run(now, memoryId);
3200
+ }
3201
+ unconsolidate(consolidationId) {
3202
+ const memory = this.getById(consolidationId);
3203
+ if (!memory) {
3204
+ throw new Error(`Memory not found: ${consolidationId}`);
3205
+ }
3206
+ if (!memory.isConsolidation) {
3207
+ throw new Error(`Memory ${consolidationId} is not a consolidation`);
3208
+ }
3209
+ const sourceLinks = this.getLinks({ memoryId: consolidationId, linkType: "derived_from" });
3210
+ const sourceIds = sourceLinks.filter((l) => l.sourceId === consolidationId).map((l) => l.targetId);
3211
+ const now = (/* @__PURE__ */ new Date()).toISOString();
3212
+ const restoredIds = [];
3213
+ let linksRemoved = 0;
3214
+ this.db.transaction(() => {
3215
+ for (const sourceId of sourceIds) {
3216
+ const source = this.getById(sourceId);
3217
+ if (source && source.status === "superseded" && source.supersedesId === consolidationId) {
3218
+ this.db.prepare(
3219
+ `UPDATE memories
3220
+ SET status = 'active', supersedes_id = NULL, version = version + 1, updated_at = ?
3221
+ WHERE id = ?`
3222
+ ).run(now, sourceId);
3223
+ restoredIds.push(sourceId);
3224
+ this.setSyncState({
3225
+ memoryId: sourceId,
3226
+ localVersion: (source.version ?? 1) + 1,
3227
+ syncStatus: "pending_push"
3228
+ });
3229
+ }
3230
+ }
3231
+ const deleteLinksResult = this.db.prepare(
3232
+ `DELETE FROM memory_links
3233
+ WHERE source_id = ? AND link_type = 'derived_from'`
3234
+ ).run(consolidationId);
3235
+ linksRemoved = deleteLinksResult.changes;
3236
+ const deleteTargetLinksResult = this.db.prepare(
3237
+ `DELETE FROM memory_links
3238
+ WHERE target_id = ?`
3239
+ ).run(consolidationId);
3240
+ linksRemoved += deleteTargetLinksResult.changes;
3241
+ this.db.prepare(
3242
+ `DELETE FROM synced_links
3243
+ WHERE link_id IN (
3244
+ SELECT id FROM memory_links WHERE source_id = ? OR target_id = ?
3245
+ )`
3246
+ ).run(consolidationId, consolidationId);
3247
+ this.softDelete({
3248
+ id: consolidationId,
3249
+ deletedBy: "unconsolidate"
3250
+ });
3251
+ })();
3252
+ return {
3253
+ restoredIds,
3254
+ consolidationDeleted: true,
3255
+ linksRemoved
3256
+ };
3257
+ }
3258
+ cleanupOrphanLinks() {
3259
+ const result = this.db.prepare(
3260
+ `DELETE FROM memory_links
3261
+ WHERE id IN (
3262
+ SELECT ml.id FROM memory_links ml
3263
+ LEFT JOIN memories ms ON ms.id = ml.source_id
3264
+ LEFT JOIN memories mt ON mt.id = ml.target_id
3265
+ WHERE ms.id IS NULL
3266
+ OR mt.id IS NULL
3267
+ OR ms.status = 'deleted'
3268
+ OR mt.status = 'deleted'
3269
+ )`
3270
+ ).run();
3271
+ this.db.prepare(
3272
+ `DELETE FROM synced_links
3273
+ WHERE link_id NOT IN (SELECT id FROM memory_links)`
3274
+ ).run();
3275
+ return result.changes;
3276
+ }
3277
+ async storeEmbedding(memoryId, embedding, model) {
3278
+ const now = (/* @__PURE__ */ new Date()).toISOString();
3279
+ const blob = serializeEmbedding(embedding);
3280
+ this.db.prepare(
3281
+ `INSERT OR REPLACE INTO memory_embeddings (memory_id, embedding, model, created_at)
3282
+ VALUES (?, ?, ?, ?)`
3283
+ ).run(memoryId, blob, model, now);
3284
+ }
3285
+ async generateAndStoreEmbedding(memoryId, text, config2) {
3286
+ try {
3287
+ const result = await generateEmbedding(text, config2);
3288
+ await this.storeEmbedding(memoryId, result.embedding, result.model);
3289
+ } catch (error) {
3290
+ console.error(`Failed to generate embedding for ${memoryId}:`, error);
3291
+ }
3292
+ }
3293
+ getEmbedding(memoryId) {
3294
+ const row = this.db.prepare("SELECT embedding FROM memory_embeddings WHERE memory_id = ?").get(memoryId);
3295
+ if (!row) return void 0;
3296
+ return deserializeEmbedding(row.embedding);
3297
+ }
3298
+ hasEmbedding(memoryId) {
3299
+ const row = this.db.prepare("SELECT 1 FROM memory_embeddings WHERE memory_id = ?").get(memoryId);
3300
+ return !!row;
3301
+ }
3302
+ getAllEmbeddings(orgId, repoId) {
3303
+ const rows = this.db.prepare(
3304
+ `SELECT e.memory_id, e.embedding FROM memory_embeddings e
3305
+ JOIN memories m ON e.memory_id = m.id
3306
+ WHERE m.org_id = ? AND m.repo_id = ? AND m.status = 'active'`
3307
+ ).all(orgId, repoId);
3308
+ return rows.map((row) => ({
3309
+ memoryId: row.memory_id,
3310
+ embedding: deserializeEmbedding(row.embedding)
3311
+ }));
3312
+ }
3313
+ getMemoriesWithoutEmbeddings(orgId, repoId) {
3314
+ const rows = this.db.prepare(
3315
+ `SELECT m.* FROM memories m
3316
+ LEFT JOIN memory_embeddings e ON m.id = e.memory_id
3317
+ WHERE m.org_id = ? AND m.repo_id = ? AND m.status = 'active' AND e.memory_id IS NULL`
3318
+ ).all(orgId, repoId);
3319
+ return rows.map(rowToMemory);
3320
+ }
3321
+ async recallWithEmbeddings(query, queryEmbedding) {
3322
+ const ftsResults = this.recall(query);
3323
+ if (!queryEmbedding) {
3324
+ return ftsResults;
3325
+ }
3326
+ const allEmbeddings = this.getAllEmbeddings(query.orgId, query.repoId);
3327
+ if (allEmbeddings.length === 0) {
3328
+ return ftsResults;
3329
+ }
3330
+ const embeddingScores = /* @__PURE__ */ new Map();
3331
+ for (const { memoryId, embedding } of allEmbeddings) {
3332
+ const similarity = cosineSimilarity(queryEmbedding, embedding);
3333
+ embeddingScores.set(memoryId, Math.max(0, similarity));
3334
+ }
3335
+ const ftsIds = new Set(ftsResults.map((r) => r.id));
3336
+ const k = query.k ?? 10;
3337
+ const usageStats = this.getUsageStats(query.orgId, query.repoId);
3338
+ const usageMap = new Map(usageStats.map((stat) => [stat.memoryId, stat]));
3339
+ const sortedByEmbedding = Array.from(embeddingScores.entries()).filter(([id]) => !ftsIds.has(id)).sort((a, b) => b[1] - a[1]).slice(0, k);
3340
+ const additionalMemories = [];
3341
+ for (const [memoryId, similarity] of sortedByEmbedding) {
3342
+ if (similarity < 0.3) continue;
3343
+ const memory = this.getById(memoryId);
3344
+ if (!memory || memory.status !== "active" || !query.includeExpired && memory.ttlSeconds && memory.createdAt.getTime() + memory.ttlSeconds * 1e3 <= Date.now()) {
3345
+ continue;
3346
+ }
3347
+ const usage = usageMap.get(memory.id);
3348
+ const usageBoost = computeUsageBoost(
3349
+ usage?.count ?? 0,
3350
+ usage?.lastUsed
3351
+ );
3352
+ additionalMemories.push({
3353
+ id: memory.id,
3354
+ memoryType: memory.memoryType,
3355
+ text: memory.text,
3356
+ summary: memory.summary,
3357
+ tags: memory.tags,
3358
+ sourceRefs: memory.sourceRefs,
3359
+ score: computeHybridScore(0, similarity, memory.createdAt, memory.confidence, usageBoost),
3360
+ source: "local",
3361
+ status: memory.status,
3362
+ supersedesId: memory.supersedesId,
3363
+ isConsolidation: memory.isConsolidation,
3364
+ consolidationVersion: memory.consolidationVersion
3365
+ });
3366
+ }
3367
+ const hybridResults = ftsResults.map((r) => {
3368
+ const embScore = embeddingScores.get(r.id) ?? 0;
3369
+ const memory = this.getById(r.id);
3370
+ if (!memory) return r;
3371
+ const usage = usageMap.get(r.id);
3372
+ const usageBoost = computeUsageBoost(
3373
+ usage?.count ?? 0,
3374
+ usage?.lastUsed
3375
+ );
3376
+ return {
3377
+ ...r,
3378
+ score: computeHybridScore(r.score, embScore, memory.createdAt, memory.confidence, usageBoost)
3379
+ };
3380
+ });
3381
+ const combined = [...hybridResults, ...additionalMemories];
3382
+ return combined.sort((a, b) => b.score - a.score).slice(0, k);
3383
+ }
3384
+ recordUsage(memoryId, query, sessionId) {
3385
+ this.db.prepare(
3386
+ `INSERT INTO memory_usage (memory_id, query, session_id) VALUES (?, ?, ?)`
3387
+ ).run(memoryId, query ?? null, sessionId ?? null);
3388
+ }
3389
+ recordUsageBatch(memoryIds, query, sessionId) {
3390
+ const stmt = this.db.prepare(
3391
+ `INSERT INTO memory_usage (memory_id, query, session_id) VALUES (?, ?, ?)`
3392
+ );
3393
+ const insertMany = this.db.transaction((ids) => {
3394
+ for (const id of ids) {
3395
+ stmt.run(id, query ?? null, sessionId ?? null);
3396
+ }
3397
+ });
3398
+ insertMany(memoryIds);
3399
+ }
3400
+ getUsageCount(memoryId) {
3401
+ const row = this.db.prepare("SELECT COUNT(*) as cnt FROM memory_usage WHERE memory_id = ?").get(memoryId);
3402
+ return row.cnt;
3403
+ }
3404
+ getUsageStats(orgId, repoId) {
3405
+ const rows = this.db.prepare(
3406
+ `SELECT u.memory_id, COUNT(*) as cnt, MAX(u.recalled_at) as last_used
3407
+ FROM memory_usage u
3408
+ JOIN memories m ON u.memory_id = m.id
3409
+ WHERE m.org_id = ? AND m.repo_id = ?
3410
+ GROUP BY u.memory_id
3411
+ ORDER BY cnt DESC`
3412
+ ).all(orgId, repoId);
3413
+ return rows.map((row) => ({
3414
+ memoryId: row.memory_id,
3415
+ count: row.cnt,
3416
+ lastUsed: new Date(row.last_used)
3417
+ }));
3418
+ }
3419
+ getTopUsedMemories(orgId, repoId, limit = 10) {
3420
+ const rows = this.db.prepare(
3421
+ `SELECT m.*, COUNT(u.id) as usage_count
3422
+ FROM memories m
3423
+ LEFT JOIN memory_usage u ON m.id = u.memory_id
3424
+ WHERE m.org_id = ? AND m.repo_id = ? AND m.status = 'active'
3425
+ GROUP BY m.id
3426
+ ORDER BY usage_count DESC
3427
+ LIMIT ?`
3428
+ ).all(orgId, repoId, limit);
3429
+ return rows.map((row) => ({
3430
+ memory: rowToMemory(row),
3431
+ usageCount: row.usage_count
3432
+ }));
3433
+ }
3434
+ getUnusedMemories(orgId, repoId, daysSinceCreation = 30) {
3435
+ const cutoff = /* @__PURE__ */ new Date();
3436
+ cutoff.setDate(cutoff.getDate() - daysSinceCreation);
3437
+ const rows = this.db.prepare(
3438
+ `SELECT m.* FROM memories m
3439
+ LEFT JOIN memory_usage u ON m.id = u.memory_id
3440
+ WHERE m.org_id = ?
3441
+ AND m.repo_id = ?
3442
+ AND m.status = 'active'
3443
+ AND m.created_at < ?
3444
+ AND u.id IS NULL`
3445
+ ).all(orgId, repoId, cutoff.toISOString());
3446
+ return rows.map(rowToMemory);
3447
+ }
3448
+ getEmbeddingStats(orgId, repoId) {
3449
+ const row = this.db.prepare(
3450
+ `SELECT
3451
+ COUNT(m.id) as total,
3452
+ COUNT(e.memory_id) as with_embedding
3453
+ FROM memories m
3454
+ LEFT JOIN memory_embeddings e ON m.id = e.memory_id
3455
+ WHERE m.org_id = ? AND m.repo_id = ? AND m.status = 'active'`
3456
+ ).get(orgId, repoId);
3457
+ return {
3458
+ total: row.total,
3459
+ withEmbedding: row.with_embedding,
3460
+ withoutEmbedding: row.total - row.with_embedding
3461
+ };
3462
+ }
3463
+ createCurationSuggestion(input) {
3464
+ const id = uuid();
3465
+ const now = (/* @__PURE__ */ new Date()).toISOString();
3466
+ const normalizedOrgId = input.orgId.toLowerCase();
3467
+ const normalizedRepoId = input.repoId.toLowerCase();
3468
+ this.db.prepare(
3469
+ `INSERT INTO curation_suggestions
3470
+ (id, org_id, repo_id, type, priority, status, memory_ids, reason, confidence, payload, created_by, created_at, updated_at)
3471
+ VALUES (?, ?, ?, ?, ?, 'pending', ?, ?, ?, ?, ?, ?, ?)`
3472
+ ).run(
3473
+ id,
3474
+ normalizedOrgId,
3475
+ normalizedRepoId,
3476
+ input.type,
3477
+ input.priority,
3478
+ JSON.stringify(input.memoryIds),
3479
+ input.reason,
3480
+ input.confidence,
3481
+ input.payload ? JSON.stringify(input.payload) : null,
3482
+ input.createdBy ?? null,
3483
+ now,
3484
+ now
3485
+ );
3486
+ return this.getCurationSuggestionById(id);
3487
+ }
3488
+ listCurationSuggestions(query) {
3489
+ const clauses = ["org_id = ?", "repo_id = ?"];
3490
+ const params = [query.orgId.toLowerCase(), query.repoId.toLowerCase()];
3491
+ if (query.status && query.status.length > 0) {
3492
+ clauses.push(`status IN (${query.status.map(() => "?").join(",")})`);
3493
+ params.push(...query.status);
3494
+ }
3495
+ if (query.types && query.types.length > 0) {
3496
+ clauses.push(`type IN (${query.types.map(() => "?").join(",")})`);
3497
+ params.push(...query.types);
3498
+ }
3499
+ const limit = Math.min(query.limit ?? 100, 500);
3500
+ const offset = query.offset ?? 0;
3501
+ params.push(limit, offset);
3502
+ const rows = this.db.prepare(
3503
+ `SELECT * FROM curation_suggestions
3504
+ WHERE ${clauses.join(" AND ")}
3505
+ ORDER BY created_at DESC
3506
+ LIMIT ? OFFSET ?`
3507
+ ).all(...params);
3508
+ return rows.map(rowToCurationSuggestion);
3509
+ }
3510
+ reviewCurationSuggestion(input) {
3511
+ const existing = this.getCurationSuggestionById(input.id);
3512
+ if (!existing) {
3513
+ throw new Error(`Curation suggestion not found: ${input.id}`);
3514
+ }
3515
+ const now = (/* @__PURE__ */ new Date()).toISOString();
3516
+ this.db.prepare(
3517
+ `UPDATE curation_suggestions
3518
+ SET status = ?, reviewed_by = ?, review_note = ?, reviewed_at = ?,
3519
+ applied_at = CASE WHEN ? = 'applied' THEN ? ELSE applied_at END,
3520
+ updated_at = ?
3521
+ WHERE id = ?`
3522
+ ).run(
3523
+ input.status,
3524
+ input.reviewedBy ?? null,
3525
+ input.reviewNote ?? null,
3526
+ now,
3527
+ input.status,
3528
+ now,
3529
+ now,
3530
+ input.id
3531
+ );
3532
+ return this.getCurationSuggestionById(input.id);
3533
+ }
3534
+ getCurationSuggestionById(id) {
3535
+ const row = this.db.prepare("SELECT * FROM curation_suggestions WHERE id = ?").get(id);
3536
+ return row ? rowToCurationSuggestion(row) : void 0;
3537
+ }
3538
+ resetAll() {
3539
+ const result = this.db.transaction(() => {
3540
+ const embeddingsDeleted = this.db.prepare("DELETE FROM memory_embeddings").run().changes;
3541
+ const linksDeleted = this.db.prepare("DELETE FROM memory_links").run().changes;
3542
+ this.db.prepare("DELETE FROM synced_links").run();
3543
+ this.db.prepare("DELETE FROM sync_state").run();
3544
+ this.db.prepare("DELETE FROM tombstones").run();
3545
+ this.db.prepare("DELETE FROM memory_usage").run();
3546
+ const memoriesDeleted = this.db.prepare("DELETE FROM memories").run().changes;
3547
+ this.db.exec("INSERT INTO memories_fts(memories_fts) VALUES('rebuild')");
3548
+ return { memoriesDeleted, linksDeleted, embeddingsDeleted };
3549
+ })();
3550
+ return result;
3551
+ }
3552
+ clearEmbeddings() {
3553
+ return this.db.prepare("DELETE FROM memory_embeddings").run().changes;
3554
+ }
3555
+ close() {
3556
+ this.db.close();
3557
+ }
3558
+ };
3559
+ var config = {
3560
+ "previewFeatures": [],
3561
+ "clientVersion": "7.8.0",
3562
+ "engineVersion": "3c6e192761c0362d496ed980de936e2f3cebcd3a",
3563
+ "activeProvider": "postgresql",
3564
+ "inlineSchema": 'datasource db {\n provider = "postgresql"\n}\n\ngenerator client {\n provider = "prisma-client"\n output = "../packages/db/src/generated/prisma"\n}\n\nmodel Memory {\n id String @id @default(uuid()) @db.Uuid\n orgId String @map("org_id")\n repoId String @map("repo_id")\n scopeType String @default("repo") @map("scope_type")\n memoryType String @map("memory_type")\n visibility String @default("repo")\n status String @default("active")\n text String\n summary String?\n tags String[]\n sourceRefs Json? @map("source_refs")\n confidence Float?\n ttlSeconds Int? @map("ttl_seconds")\n supersedesId String? @map("supersedes_id") @db.Uuid\n version Int @default(1)\n deletedAt DateTime? @map("deleted_at")\n deletedBy String? @map("deleted_by")\n createdAt DateTime @default(now()) @map("created_at")\n updatedAt DateTime @updatedAt @map("updated_at")\n\n supersedes Memory? @relation("Supersedes", fields: [supersedesId], references: [id])\n supersededBy Memory[] @relation("Supersedes")\n\n sourceLinks MemoryLink[] @relation("SourceLinks")\n targetLinks MemoryLink[] @relation("TargetLinks")\n embedding MemoryEmbedding?\n usages MemoryUsage[]\n\n @@index([orgId, repoId, memoryType, status])\n @@index([orgId, repoId, updatedAt])\n @@index([deletedAt])\n @@map("memories")\n}\n\nmodel MemoryEmbedding {\n memoryId String @id @map("memory_id") @db.Uuid\n embedding Bytes\n model String\n createdAt DateTime @default(now()) @map("created_at")\n\n memory Memory @relation(fields: [memoryId], references: [id], onDelete: Cascade)\n\n @@map("memory_embeddings")\n}\n\nmodel MemoryUsage {\n id Int @id @default(autoincrement())\n memoryId String @map("memory_id") @db.Uuid\n recalledAt DateTime @default(now()) @map("recalled_at")\n query String?\n sessionId String? @map("session_id")\n\n memory Memory @relation(fields: [memoryId], references: [id], onDelete: Cascade)\n\n @@index([memoryId])\n @@index([recalledAt])\n @@map("memory_usage")\n}\n\nmodel MemoryLink {\n id String @id @default(uuid()) @db.Uuid\n sourceId String @map("source_id") @db.Uuid\n targetId String @map("target_id") @db.Uuid\n linkType String @map("link_type")\n metadata Json?\n createdAt DateTime @default(now()) @map("created_at")\n\n source Memory @relation("SourceLinks", fields: [sourceId], references: [id], onDelete: Cascade)\n target Memory @relation("TargetLinks", fields: [targetId], references: [id], onDelete: Cascade)\n\n @@unique([sourceId, targetId, linkType])\n @@map("memory_links")\n}\n\nmodel Tombstone {\n id String @id @default(uuid()) @db.Uuid\n memoryId String @map("memory_id") @db.Uuid\n orgId String @map("org_id")\n repoId String @map("repo_id")\n deletedAt DateTime @map("deleted_at")\n deletedBy String? @map("deleted_by")\n syncedAt DateTime? @map("synced_at")\n createdAt DateTime @default(now()) @map("created_at")\n\n @@unique([memoryId])\n @@index([orgId, repoId, syncedAt])\n @@map("tombstones")\n}\n\nmodel ApiKey {\n id String @id @default(uuid()) @db.Uuid\n key String @unique\n name String\n label String?\n orgId String @map("org_id")\n repoId String? @map("repo_id")\n userId String? @map("user_id") @db.Uuid\n createdBy String? @map("created_by") @db.Uuid\n isActive Boolean @default(true) @map("is_active")\n createdAt DateTime @default(now()) @map("created_at")\n lastUsedAt DateTime? @map("last_used_at")\n\n user User? @relation(fields: [userId], references: [id])\n logs ApiKeyLog[]\n\n @@index([key])\n @@index([orgId])\n @@index([userId])\n @@map("api_keys")\n}\n\nmodel ApiKeyLog {\n id String @id @default(uuid()) @db.Uuid\n apiKeyId String @map("api_key_id") @db.Uuid\n operation String\n memoryId String? @map("memory_id") @db.Uuid\n orgId String @map("org_id")\n repoId String @map("repo_id")\n query String?\n metadata Json?\n createdAt DateTime @default(now()) @map("created_at")\n\n apiKey ApiKey @relation(fields: [apiKeyId], references: [id], onDelete: Cascade)\n\n @@index([apiKeyId])\n @@index([createdAt])\n @@index([memoryId])\n @@index([orgId, repoId])\n @@map("api_key_logs")\n}\n\nmodel User {\n id String @id @default(uuid()) @db.Uuid\n githubId Int @unique @map("github_id")\n githubLogin String @map("github_login")\n name String?\n email String?\n avatarUrl String? @map("avatar_url")\n isAdmin Boolean @default(false) @map("is_admin")\n createdAt DateTime @default(now()) @map("created_at")\n updatedAt DateTime @updatedAt @map("updated_at")\n\n apiKeys ApiKey[]\n repoAccess UserRepoAccess[]\n\n @@map("users")\n}\n\nmodel UserRepoAccess {\n id String @id @default(uuid()) @db.Uuid\n userId String @map("user_id") @db.Uuid\n orgId String @map("org_id")\n repoId String @map("repo_id")\n permission String\n grantedAt DateTime @default(now()) @map("granted_at")\n grantedBy String? @map("granted_by") @db.Uuid\n\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n\n @@unique([userId, orgId, repoId])\n @@index([orgId, repoId])\n @@map("user_repo_access")\n}\n',
3565
+ "runtimeDataModel": {
3566
+ "models": {},
3567
+ "enums": {},
3568
+ "types": {}
3569
+ },
3570
+ "parameterizationSchema": {
3571
+ "strings": [],
3572
+ "graph": ""
3573
+ }
3574
+ };
3575
+ config.runtimeDataModel = JSON.parse('{"models":{"Memory":{"fields":[{"name":"id","kind":"scalar","type":"String"},{"name":"orgId","kind":"scalar","type":"String","dbName":"org_id"},{"name":"repoId","kind":"scalar","type":"String","dbName":"repo_id"},{"name":"scopeType","kind":"scalar","type":"String","dbName":"scope_type"},{"name":"memoryType","kind":"scalar","type":"String","dbName":"memory_type"},{"name":"visibility","kind":"scalar","type":"String"},{"name":"status","kind":"scalar","type":"String"},{"name":"text","kind":"scalar","type":"String"},{"name":"summary","kind":"scalar","type":"String"},{"name":"tags","kind":"scalar","type":"String"},{"name":"sourceRefs","kind":"scalar","type":"Json","dbName":"source_refs"},{"name":"confidence","kind":"scalar","type":"Float"},{"name":"ttlSeconds","kind":"scalar","type":"Int","dbName":"ttl_seconds"},{"name":"supersedesId","kind":"scalar","type":"String","dbName":"supersedes_id"},{"name":"version","kind":"scalar","type":"Int"},{"name":"deletedAt","kind":"scalar","type":"DateTime","dbName":"deleted_at"},{"name":"deletedBy","kind":"scalar","type":"String","dbName":"deleted_by"},{"name":"createdAt","kind":"scalar","type":"DateTime","dbName":"created_at"},{"name":"updatedAt","kind":"scalar","type":"DateTime","dbName":"updated_at"},{"name":"supersedes","kind":"object","type":"Memory","relationName":"Supersedes"},{"name":"supersededBy","kind":"object","type":"Memory","relationName":"Supersedes"},{"name":"sourceLinks","kind":"object","type":"MemoryLink","relationName":"SourceLinks"},{"name":"targetLinks","kind":"object","type":"MemoryLink","relationName":"TargetLinks"},{"name":"embedding","kind":"object","type":"MemoryEmbedding","relationName":"MemoryToMemoryEmbedding"},{"name":"usages","kind":"object","type":"MemoryUsage","relationName":"MemoryToMemoryUsage"}],"dbName":"memories"},"MemoryEmbedding":{"fields":[{"name":"memoryId","kind":"scalar","type":"String","dbName":"memory_id"},{"name":"embedding","kind":"scalar","type":"Bytes"},{"name":"model","kind":"scalar","type":"String"},{"name":"createdAt","kind":"scalar","type":"DateTime","dbName":"created_at"},{"name":"memory","kind":"object","type":"Memory","relationName":"MemoryToMemoryEmbedding"}],"dbName":"memory_embeddings"},"MemoryUsage":{"fields":[{"name":"id","kind":"scalar","type":"Int"},{"name":"memoryId","kind":"scalar","type":"String","dbName":"memory_id"},{"name":"recalledAt","kind":"scalar","type":"DateTime","dbName":"recalled_at"},{"name":"query","kind":"scalar","type":"String"},{"name":"sessionId","kind":"scalar","type":"String","dbName":"session_id"},{"name":"memory","kind":"object","type":"Memory","relationName":"MemoryToMemoryUsage"}],"dbName":"memory_usage"},"MemoryLink":{"fields":[{"name":"id","kind":"scalar","type":"String"},{"name":"sourceId","kind":"scalar","type":"String","dbName":"source_id"},{"name":"targetId","kind":"scalar","type":"String","dbName":"target_id"},{"name":"linkType","kind":"scalar","type":"String","dbName":"link_type"},{"name":"metadata","kind":"scalar","type":"Json"},{"name":"createdAt","kind":"scalar","type":"DateTime","dbName":"created_at"},{"name":"source","kind":"object","type":"Memory","relationName":"SourceLinks"},{"name":"target","kind":"object","type":"Memory","relationName":"TargetLinks"}],"dbName":"memory_links"},"Tombstone":{"fields":[{"name":"id","kind":"scalar","type":"String"},{"name":"memoryId","kind":"scalar","type":"String","dbName":"memory_id"},{"name":"orgId","kind":"scalar","type":"String","dbName":"org_id"},{"name":"repoId","kind":"scalar","type":"String","dbName":"repo_id"},{"name":"deletedAt","kind":"scalar","type":"DateTime","dbName":"deleted_at"},{"name":"deletedBy","kind":"scalar","type":"String","dbName":"deleted_by"},{"name":"syncedAt","kind":"scalar","type":"DateTime","dbName":"synced_at"},{"name":"createdAt","kind":"scalar","type":"DateTime","dbName":"created_at"}],"dbName":"tombstones"},"ApiKey":{"fields":[{"name":"id","kind":"scalar","type":"String"},{"name":"key","kind":"scalar","type":"String"},{"name":"name","kind":"scalar","type":"String"},{"name":"label","kind":"scalar","type":"String"},{"name":"orgId","kind":"scalar","type":"String","dbName":"org_id"},{"name":"repoId","kind":"scalar","type":"String","dbName":"repo_id"},{"name":"userId","kind":"scalar","type":"String","dbName":"user_id"},{"name":"createdBy","kind":"scalar","type":"String","dbName":"created_by"},{"name":"isActive","kind":"scalar","type":"Boolean","dbName":"is_active"},{"name":"createdAt","kind":"scalar","type":"DateTime","dbName":"created_at"},{"name":"lastUsedAt","kind":"scalar","type":"DateTime","dbName":"last_used_at"},{"name":"user","kind":"object","type":"User","relationName":"ApiKeyToUser"},{"name":"logs","kind":"object","type":"ApiKeyLog","relationName":"ApiKeyToApiKeyLog"}],"dbName":"api_keys"},"ApiKeyLog":{"fields":[{"name":"id","kind":"scalar","type":"String"},{"name":"apiKeyId","kind":"scalar","type":"String","dbName":"api_key_id"},{"name":"operation","kind":"scalar","type":"String"},{"name":"memoryId","kind":"scalar","type":"String","dbName":"memory_id"},{"name":"orgId","kind":"scalar","type":"String","dbName":"org_id"},{"name":"repoId","kind":"scalar","type":"String","dbName":"repo_id"},{"name":"query","kind":"scalar","type":"String"},{"name":"metadata","kind":"scalar","type":"Json"},{"name":"createdAt","kind":"scalar","type":"DateTime","dbName":"created_at"},{"name":"apiKey","kind":"object","type":"ApiKey","relationName":"ApiKeyToApiKeyLog"}],"dbName":"api_key_logs"},"User":{"fields":[{"name":"id","kind":"scalar","type":"String"},{"name":"githubId","kind":"scalar","type":"Int","dbName":"github_id"},{"name":"githubLogin","kind":"scalar","type":"String","dbName":"github_login"},{"name":"name","kind":"scalar","type":"String"},{"name":"email","kind":"scalar","type":"String"},{"name":"avatarUrl","kind":"scalar","type":"String","dbName":"avatar_url"},{"name":"isAdmin","kind":"scalar","type":"Boolean","dbName":"is_admin"},{"name":"createdAt","kind":"scalar","type":"DateTime","dbName":"created_at"},{"name":"updatedAt","kind":"scalar","type":"DateTime","dbName":"updated_at"},{"name":"apiKeys","kind":"object","type":"ApiKey","relationName":"ApiKeyToUser"},{"name":"repoAccess","kind":"object","type":"UserRepoAccess","relationName":"UserToUserRepoAccess"}],"dbName":"users"},"UserRepoAccess":{"fields":[{"name":"id","kind":"scalar","type":"String"},{"name":"userId","kind":"scalar","type":"String","dbName":"user_id"},{"name":"orgId","kind":"scalar","type":"String","dbName":"org_id"},{"name":"repoId","kind":"scalar","type":"String","dbName":"repo_id"},{"name":"permission","kind":"scalar","type":"String"},{"name":"grantedAt","kind":"scalar","type":"DateTime","dbName":"granted_at"},{"name":"grantedBy","kind":"scalar","type":"String","dbName":"granted_by"},{"name":"user","kind":"object","type":"User","relationName":"UserToUserRepoAccess"}],"dbName":"user_repo_access"}},"enums":{},"types":{}}');
3576
+ config.parameterizationSchema = {
3577
+ strings: JSON.parse('["where","supersedes","orderBy","cursor","supersededBy","source","target","sourceLinks","targetLinks","memory","embedding","usages","_count","Memory.findUnique","Memory.findUniqueOrThrow","Memory.findFirst","Memory.findFirstOrThrow","Memory.findMany","data","Memory.createOne","Memory.createMany","Memory.createManyAndReturn","Memory.updateOne","Memory.updateMany","Memory.updateManyAndReturn","create","update","Memory.upsertOne","Memory.deleteOne","Memory.deleteMany","having","_avg","_sum","_min","_max","Memory.groupBy","Memory.aggregate","MemoryEmbedding.findUnique","MemoryEmbedding.findUniqueOrThrow","MemoryEmbedding.findFirst","MemoryEmbedding.findFirstOrThrow","MemoryEmbedding.findMany","MemoryEmbedding.createOne","MemoryEmbedding.createMany","MemoryEmbedding.createManyAndReturn","MemoryEmbedding.updateOne","MemoryEmbedding.updateMany","MemoryEmbedding.updateManyAndReturn","MemoryEmbedding.upsertOne","MemoryEmbedding.deleteOne","MemoryEmbedding.deleteMany","MemoryEmbedding.groupBy","MemoryEmbedding.aggregate","MemoryUsage.findUnique","MemoryUsage.findUniqueOrThrow","MemoryUsage.findFirst","MemoryUsage.findFirstOrThrow","MemoryUsage.findMany","MemoryUsage.createOne","MemoryUsage.createMany","MemoryUsage.createManyAndReturn","MemoryUsage.updateOne","MemoryUsage.updateMany","MemoryUsage.updateManyAndReturn","MemoryUsage.upsertOne","MemoryUsage.deleteOne","MemoryUsage.deleteMany","MemoryUsage.groupBy","MemoryUsage.aggregate","MemoryLink.findUnique","MemoryLink.findUniqueOrThrow","MemoryLink.findFirst","MemoryLink.findFirstOrThrow","MemoryLink.findMany","MemoryLink.createOne","MemoryLink.createMany","MemoryLink.createManyAndReturn","MemoryLink.updateOne","MemoryLink.updateMany","MemoryLink.updateManyAndReturn","MemoryLink.upsertOne","MemoryLink.deleteOne","MemoryLink.deleteMany","MemoryLink.groupBy","MemoryLink.aggregate","Tombstone.findUnique","Tombstone.findUniqueOrThrow","Tombstone.findFirst","Tombstone.findFirstOrThrow","Tombstone.findMany","Tombstone.createOne","Tombstone.createMany","Tombstone.createManyAndReturn","Tombstone.updateOne","Tombstone.updateMany","Tombstone.updateManyAndReturn","Tombstone.upsertOne","Tombstone.deleteOne","Tombstone.deleteMany","Tombstone.groupBy","Tombstone.aggregate","apiKeys","user","repoAccess","apiKey","logs","ApiKey.findUnique","ApiKey.findUniqueOrThrow","ApiKey.findFirst","ApiKey.findFirstOrThrow","ApiKey.findMany","ApiKey.createOne","ApiKey.createMany","ApiKey.createManyAndReturn","ApiKey.updateOne","ApiKey.updateMany","ApiKey.updateManyAndReturn","ApiKey.upsertOne","ApiKey.deleteOne","ApiKey.deleteMany","ApiKey.groupBy","ApiKey.aggregate","ApiKeyLog.findUnique","ApiKeyLog.findUniqueOrThrow","ApiKeyLog.findFirst","ApiKeyLog.findFirstOrThrow","ApiKeyLog.findMany","ApiKeyLog.createOne","ApiKeyLog.createMany","ApiKeyLog.createManyAndReturn","ApiKeyLog.updateOne","ApiKeyLog.updateMany","ApiKeyLog.updateManyAndReturn","ApiKeyLog.upsertOne","ApiKeyLog.deleteOne","ApiKeyLog.deleteMany","ApiKeyLog.groupBy","ApiKeyLog.aggregate","User.findUnique","User.findUniqueOrThrow","User.findFirst","User.findFirstOrThrow","User.findMany","User.createOne","User.createMany","User.createManyAndReturn","User.updateOne","User.updateMany","User.updateManyAndReturn","User.upsertOne","User.deleteOne","User.deleteMany","User.groupBy","User.aggregate","UserRepoAccess.findUnique","UserRepoAccess.findUniqueOrThrow","UserRepoAccess.findFirst","UserRepoAccess.findFirstOrThrow","UserRepoAccess.findMany","UserRepoAccess.createOne","UserRepoAccess.createMany","UserRepoAccess.createManyAndReturn","UserRepoAccess.updateOne","UserRepoAccess.updateMany","UserRepoAccess.updateManyAndReturn","UserRepoAccess.upsertOne","UserRepoAccess.deleteOne","UserRepoAccess.deleteMany","UserRepoAccess.groupBy","UserRepoAccess.aggregate","AND","OR","NOT","id","userId","orgId","repoId","permission","grantedAt","grantedBy","equals","in","notIn","lt","lte","gt","gte","not","contains","startsWith","endsWith","githubId","githubLogin","name","email","avatarUrl","isAdmin","createdAt","updatedAt","every","some","none","apiKeyId","operation","memoryId","query","metadata","string_contains","string_starts_with","string_ends_with","array_starts_with","array_ends_with","array_contains","key","label","createdBy","isActive","lastUsedAt","userId_orgId_repoId","deletedAt","deletedBy","syncedAt","sourceId","targetId","linkType","recalledAt","sessionId","model","scopeType","memoryType","visibility","status","text","summary","tags","sourceRefs","confidence","ttlSeconds","supersedesId","version","has","hasEvery","hasSome","sourceId_targetId_linkType","is","isNot","connectOrCreate","upsert","createMany","set","disconnect","delete","connect","updateMany","deleteMany","increment","decrement","multiply","divide","push"]'),
3578
+ graph: "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-QEAIeYBAQD5AQAh5wEBAPkBACHoAQEA-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-gEAIc4BAACWAgAg3gEBAPgBACHfAQEA-AEAIeABAQD5AQAhAwAAAAcAIAIAAG0AMB4AAG4AIAMAAAAHACACAAAIADADAAAJACALqgEAAKwCADCrAQAAdAAQrAEAAKwCADCtAQEAAAABrwEBAI8CACGwAQEAjwIAIcUBQACSAgAhzAEBAAAAAdsBQACSAgAh3AEBAJACACHdAUAApwIAIQEAAABxACABAAAAcQAgC6oBAACsAgAwqwEAAHQAEKwBAACsAgAwrQEBAJ0CACGvAQEAjwIAIbABAQCPAgAhxQFAAJICACHMAQEAnQIAIdsBQACSAgAh3AEBAJACACHdAUAApwIAIQLcAQAAyAIAIN0BAADIAgAgAwAAAHQAIAIAAHUAMAMAAHEAIAMAAAB0ACACAAB1ADADAABxACADAAAAdAAgAgAAdQAwAwAAcQAgCK0BAQAAAAGvAQEAAAABsAEBAAAAAcUBQAAAAAHMAQEAAAAB2wFAAAAAAdwBAQAAAAHdAUAAAAABARIAAHkAIAitAQEAAAABrwEBAAAAAbABAQAAAAHFAUAAAAABzAEBAAAAAdsBQAAAAAHcAQEAAAAB3QFAAAAAAQESAAB7ADABEgAAewAwCK0BAQDMAgAhrwEBAMwCACGwAQEAzAIAIcUBQADNAgAhzAEBAMwCACHbAUAAzQIAIdwBAQDOAgAh3QFAAPACACECAAAAcQAgEgAAfgAgCK0BAQDMAgAhrwEBAMwCACGwAQEAzAIAIcUBQADNAgAhzAEBAMwCACHbAUAAzQIAIdwBAQDOAgAh3QFAAPACACECAAAAdAAgEgAAgAEAIAIAAAB0ACASAACAAQAgAwAAAHEAIBkAAHkAIBoAAH4AIAEAAABxACABAAAAdAAgBQwAAJIDACAhAACUAwAgIgAAkwMAINwBAADIAgAg3QEAAMgCACALqgEAAKsCADCrAQAAhwEAEKwBAACrAgAwrQEBAPgBACGvAQEA-QEAIbABAQD5AQAhxQFAAPoBACHMAQEA-AEAIdsBQAD6AQAh3AEBAIcCACHdAUAAmQIAIQMAAAB0ACACAACGAQAwHgAAhwEAIAMAAAB0ACACAAB1ADADAABxACAQZgAAqAIAIGkAAKkCACCqAQAApgIAMKsBAACOAQAQrAEAAKYCADCtAQEAAAABrgEBAJ4CACGvAQEAjwIAIbABAQCQAgAhwQEBAI8CACHFAUAAkgIAIdUBAQAAAAHWAQEAkAIAIdcBAQCeAgAh2AEgAJECACHZAUAApwIAIQEAAACKAQAgDmUAAJMCACBnAACUAgAgqgEAAI4CADCrAQAAjAEAEKwBAACOAgAwrQEBAJ0CACG_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-AEAIa8BAQD5AQAhsAEBAPkBACHFAUAA-gEAIcoBAQD4AQAhywEBAPkBACHMAQEA-wEAIc0BAQCHAgAhzgEAAJYCACADAAAAlwEAIAIAAMUBADAeAADGAQAgAwAAAJcBACACAACYAQAwAwAAmQEAIA5lAACTAgAgZwAAlAIAIKoBAACOAgAwqwEAAIwBABCsAQAAjgIAMK0BAQAAAAG_AQIAAAABwAEBAI8CACHBAQEAkAIAIcIBAQCQAgAhwwEBAJACACHEASAAkQIAIcUBQACSAgAhxgFAAJICACEBAAAAyQEAIAEAAADJAQAgBWUAAIMDACBnAACEAwAgwQEAAMgCACDCAQAAyAIAIMMBAADIAgAgAwAAAIwBACACAADMAQAwAwAAyQEAIAMAAACMAQAgAgAAzAEAMAMAAMkBACADAAAAjAEAIAIAAMwBADADAADJAQAgC2UAAIEDACBnAACCAwAgrQEBAAAAAb8BAgAAAAHAAQEAAAABwQEBAAAAAcIBAQAAAAHDAQEAAAABxAEgAAAAAcUBQAAAAAHGAUAAAAABARIAANABACAJrQEBAAAAAb8BAgAAAAHAAQEAAAABwQEBAAAAAcIBAQAAAAHDAQEAAAABxAEgAAAAAcUBQAAAAAHGAUAAAAABARIAANIBADABEgAA0gEAMAtlAADYAgAgZwAA2QIAIK0BAQDMAgAhvwECANYCACHAAQEAzAIAIcEBAQDOAgAhwgEBAM4CACHDAQEAzgIAIcQBIADXAgAhxQFAAM0CACHGAUAAzQIAIQIAAADJAQAgEgAA1QEAIAmtAQEAzAIAIb8BAgDWAgAhwAEBAMwCACHBAQEAzgIAIcIBAQDOAgAhwwEBAM4CACHEASAA1wIAIcUBQADNAgAhxgFAAM0CACECAAAAjAEAIBIAANcBACACAAAAjAEAIBIAANcBACADAAAAyQEAIBkAANABACAaAADVAQAgAQAAAMkBACABAAAAjAEAIAgMAADRAgAgHwAA0gIAICAAANUCACAhAADUAgAgIgAA0wIAIMEBAADIAgAgwgEAAMgCACDDAQAAyAIAIAyqAQAAhQIAMKsBAADeAQAQrAEAAIUCADCtAQEA-AEAIb8BAgCGAgAhwAEBAPkBACHBAQEAhwIAIcIBAQCHAgAhwwEBAIcCACHEASAAiAIAIcUBQAD6AQAhxgFAAPoBACEDAAAAjAEAIAIAAN0BADAeAADeAQAgAwAAAIwBACACAADMAQAwAwAAyQEAIAEAAACTAQAgAQAAAJMBACADAAAAkQEAIAIAAJIBADADAACTAQAgAwAAAJEBACACAACSAQAwAwAAkwEAIAMAAACRAQAgAgAAkgEAMAMAAJMBACAIZgAA0AIAIK0BAQAAAAGuAQEAAAABrwEBAAAAAbABAQAAAAGxAQEAAAABsgFAAAAAAbMBAQAAAAEBEgAA5gEAIAetAQEAAAABrgEBAAAAAa8BAQAAAAGwAQEAAAABsQEBAAAAAbIBQAAAAAGzAQEAAAABARIAAOgBADABEgAA6AEAMAhmAADPAgAgrQEBAMwCACGuAQEAzAIAIa8BAQDMAgAhsAEBAMwCACGxAQEAzAIAIbIBQADNAgAhswEBAM4CACECAAAAkwEAIBIAAOsBACAHrQEBAMwCACGuAQEAzAIAIa8BAQDMAgAhsAEBAMwCACGxAQEAzAIAIbIBQADNAgAhswEBAM4CACECAAAAkQEAIBIAAO0BACACAAAAkQEAIBIAAO0BACADAAAAkwEAIBkAAOYBACAaAADrAQAgAQAAAJMBACABAAAAkQEAIAQMAADJAgAgIQAAywIAICIAAMoCACCzAQAAyAIAIAqqAQAA9wEAMKsBAAD0AQAQrAEAAPcBADCtAQEA-AEAIa4BAQD4AQAhrwEBAPkBACGwAQEA-QEAIbEBAQD5AQAhsgFAAPoBACGzAQEA-wEAIQMAAACRAQAgAgAA8wEAMB4AAPQBACADAAAAkQEAIAIAAJIBADADAACTAQAgCqoBAAD3AQAwqwEAAPQBABCsAQAA9wEAMK0BAQD4AQAhrgEBAPgBACGvAQEA-QEAIbABAQD5AQAhsQEBAPkBACGyAUAA-gEAIbMBAQD7AQAhCwwAAIACACAhAACDAgAgIgAAgwIAILQBAQAAAAG1AQEAAAAEtgEBAAAABLcBAQAAAAG4AQEAAAABuQEBAAAAAboBAQAAAAG7AQEAhAIAIQ4MAACAAgAgIQAAgwIAICIAAIMCACC0AQEAAAABtQEBAAAABLYBAQAAAAS3AQEAAAABuAEBAAAAAbkBAQAAAAG6AQEAAAABuwEBAIICACG8AQEAAAABvQEBAAAAAb4BAQAAAAELDAAAgAIAICEAAIECACAiAACBAgAgtAFAAAAAAbUBQAAAAAS2AUAAAAAEtwFAAAAAAbgBQAAAAAG5AUAAAAABugFAAAAAAbsBQAD_AQAhCwwAAP0BACAhAAD-AQAgIgAA_gEAILQBAQAAAAG1AQEAAAAFtgEBAAAABbcBAQAAAAG4AQEAAAABuQEBAAAAAboBAQAAAAG7AQEA_AEAIQsMAAD9AQAgIQAA_gEAICIAAP4BACC0AQEAAAABtQEBAAAABbYBAQAAAAW3AQEAAAABuAEBAAAAAbkBAQAAAAG6AQEAAAABuwEBAPwBACEItAECAAAAAbUBAgAAAAW2AQIAAAAFtwECAAAAAbgBAgAAAAG5AQIAAAABugECAAAAAbsBAgD9AQAhC7QBAQAAAAG1AQEAAAAFtgEBAAAABbcBAQAAAAG4AQEAAAABuQEBAAAAAboBAQAAAAG7AQEA_gEAIbwBAQAAAAG9AQEAAAABvgEBAAAAAQsMAACAAgAgIQAAgQIAICIAAIECACC0AUAAAAABtQFAAAAABLYBQAAAAAS3AUAAAAABuAFAAAAAAbkBQAAAAAG6AUAAAAABuwFAAP8BACEItAECAAAAAbUBAgAAAAS2AQIAAAAEtwECAAAAAbgBAgAAAAG5AQIAAAABugECAAAAAbsBAgCAAgAhCLQBQAAAAAG1AUAAAAAEtgFAAAAABLcBQAAAAAG4AUAAAAABuQFAAAAAAboBQAAAAAG7AUAAgQIAIQ4MAACAAgAgIQAAgwIAICIAAIMCACC0AQEAAAABtQEBAAAABLYBAQAAAAS3AQEAAAABuAEBAAAAAbkBAQAAAAG6AQEAAAABuwEBAIICACG8AQEAAAABvQEBAAAAAb4BAQAAAAELtAEBAAAAAbUBAQAAAAS2AQEAAAAEtwEBAAAAAbgBAQAAAAG5AQEAAAABugEBAAAAAbsBAQCDAgAhvAEBAAAAAb0BAQAAAAG-AQEAAAABCwwAAIACACAhAACDAgAgIgAAgwIAILQBAQAAAAG1AQEAAAAEtgEBAAAABLcBAQAAAAG4AQEAAAABuQEBAAAAAboBAQAAAAG7AQEAhAIAIQyqAQAAhQIAMKsBAADeAQAQrAEAAIUCADCtAQEA-AEAIb8BAgCGAgAhwAEBAPkBACHBAQEAhwIAIcIBAQCHAgAhwwEBAIcCACHEASAAiAIAIcUBQAD6AQAhxgFAAPoBACENDAAAgAIAIB8AAI0CACAgAACAAgAgIQAAgAIAICIAAIACACC0AQIAAAABtQECAAAABLYBAgAAAAS3AQIAAAABuAECAAAAAbkBAgAAAAG6AQIAAAABuwECAIwCACEODAAA_QEAICEAAP4BACAiAAD-AQAgtAEBAAAAAbUBAQAAAAW2AQEAAAAFtwEBAAAAAbgBAQAAAAG5AQEAAAABugEBAAAAAbsBAQCLAgAhvAEBAAAAAb0BAQAAAAG-AQEAAAABBQwAAIACACAhAACKAgAgIgAAigIAILQBIAAAAAG7ASAAiQIAIQUMAACAAgAgIQAAigIAICIAAIoCACC0ASAAAAABuwEgAIkCACECtAEgAAAAAbsBIACKAgAhDgwAAP0BACAhAAD-AQAgIgAA_gEAILQBAQAAAAG1AQEAAAAFtgEBAAAABbcBAQAAAAG4AQEAAAABuQEBAAAAAboBAQAAAAG7AQEAiwIAIbwBAQAAAAG9AQEAAAABvgEBAAAAAQ0MAACAAgAgHwAAjQIAICAAAIACACAhAACAAgAgIgAAgAIAILQBAgAAAAG1AQIAAAAEtgECAAAABLcBAgAAAAG4AQIAAAABuQECAAAAAboBAgAAAAG7AQIAjAIAIQi0AQgAAAABtQEIAAAABLYBCAAAAAS3AQgAAAABuAEIAAAAAbkBCAAAAAG6AQgAAAABuwEIAI0CACEOZQAAkwIAIGcAAJQCACCqAQAAjgIAMKsBAACMAQAQrAEAAI4CADCtAQEAnQIAIb8BAgCqAgAhwAEBAI8CACHBAQEAkAIAIcIBAQCQAgAhwwEBAJACACHEASAAkQIAIcUBQACSAgAhxgFAAJICACELtAEBAAAAAbUBAQAAAAS2AQEAAAAEtwEBAAAAAbgBAQAAAAG5AQEAAAABugEBAAAAAbsBAQCDAgAhvAEBAAAAAb0BAQAAAAG-AQEAAAABC7QBAQAAAAG1AQEAAAAFtgEBAAAABbcBAQAAAAG4AQEAAAABuQEBAAAAAboBAQAAAAG7AQEA_gEAIbwBAQAAAAG9AQEAAAABvgEBAAAAAQK0ASAAAAABuwEgAIoCACEItAFAAAAAAbUBQAAAAAS2AUAAAAAEtwFAAAAAAbgBQAAAAAG5AUAAAAABugFAAAAAAbsBQACBAgAhA8cBAACOAQAgyAEAAI4BACDJAQAAjgEAIAPHAQAAkQEAIMgBAACRAQAgyQEAAJEBACAMqgEAAJUCADCrAQAAxgEAEKwBAACVAgAwrQEBAPgBACGvAQEA-QEAIbABAQD5AQAhxQFAAPoBACHKAQEA-AEAIcsBAQD5AQAhzAEBAPsBACHNAQEAhwIAIc4BAACWAgAgDwwAAP0BACAhAACXAgAgIgAAlwIAILQBgAAAAAG3AYAAAAABuAGAAAAAAbkBgAAAAAG6AYAAAAABuwGAAAAAAc8BAQAAAAHQAQEAAAAB0QEBAAAAAdIBgAAAAAHTAYAAAAAB1AGAAAAAAQy0AYAAAAABtwGAAAAAAbgBgAAAAAG5AYAAAAABugGAAAAAAbsBgAAAAAHPAQEAAAAB0AEBAAAAAdEBAQAAAAHSAYAAAAAB0wGAAAAAAdQBgAAAAAEOqgEAAJgCADCrAQAAsAEAEKwBAACYAgAwrQEBAPgBACGuAQEA-wEAIa8BAQD5AQAhsAEBAIcCACHBAQEA-QEAIcUBQAD6AQAh1QEBAPkBACHWAQEAhwIAIdcBAQD7AQAh2AEgAIgCACHZAUAAmQIAIQsMAAD9AQAgIQAAmwIAICIAAJsCACC0AUAAAAABtQFAAAAABbYBQAAAAAW3AUAAAAABuAFAAAAAAbkBQAAAAAG6AUAAAAABuwFAAJoCACELDAAA_QEAICEAAJsCACAiAACbAgAgtAFAAAAAAbUBQAAAAAW2AUAAAAAFtwFAAAAAAbgBQAAAAAG5AUAAAAABugFAAAAAAbsBQACaAgAhCLQBQAAAAAG1AUAAAAAFtgFAAAAABbcBQAAAAAG4AUAAAAABuQFAAAAAAboBQAAAAAG7AUAAmwIAIQ1oAACgAgAgqgEAAJwCADCrAQAAlwEAEKwBAACcAgAwrQEBAJ0CACGvAQEAjwIAIbABAQCPAgAhxQFAAJICACHKAQEAnQIAIcsBAQCPAgAhzAEBAJ4CACHNAQEAkAIAIc4BAACfAgAgCLQBAQAAAAG1AQEAAAAEtgEBAAAABLcBAQAAAAG4AQEAAAABuQEBAAAAAboBAQAAAAG7AQEAogIAIQi0AQEAAAABtQEBAAAABbYBAQAAAAW3AQEAAAABuAEBAAAAAbkBAQAAAAG6AQEAAAABuwEBAKECACEMtAGAAAAAAbcBgAAAAAG4AYAAAAABuQGAAAAAAboBgAAAAAG7AYAAAAABzwEBAAAAAdABAQAAAAHRAQEAAAAB0gGAAAAAAdMBgAAAAAHUAYAAAAABEmYAAKgCACBpAACpAgAgqgEAAKYCADCrAQAAjgEAEKwBAACmAgAwrQEBAJ0CACGuAQEAngIAIa8BAQCPAgAhsAEBAJACACHBAQEAjwIAIcUBQACSAgAh1QEBAI8CACHWAQEAkAIAIdcBAQCeAgAh2AEgAJECACHZAUAApwIAIfQBAACOAQAg9QEAAI4BACAItAEBAAAAAbUBAQAAAAW2AQEAAAAFtwEBAAAAAbgBAQAAAAG5AQEAAAABugEBAAAAAbsBAQChAgAhCLQBAQAAAAG1AQEAAAAEtgEBAAAABLcBAQAAAAG4AQEAAAABuQEBAAAAAboBAQAAAAG7AQEAogIAIQOuAQEAAAABrwEBAAAAAbABAQAAAAELZgAApQIAIKoBAACkAgAwqwEAAJEBABCsAQAApAIAMK0BAQCdAgAhrgEBAJ0CACGvAQEAjwIAIbABAQCPAgAhsQEBAI8CACGyAUAAkgIAIbMBAQCeAgAhEGUAAJMCACBnAACUAgAgqgEAAI4CADCrAQAAjAEAEKwBAACOAgAwrQEBAJ0CACG_AQIAqgIAIcABAQCPAgAhwQEBAJACACHCAQEAkAIAIcMBAQCQAgAhxAEgAJECACHFAUAAkgIAIcYBQACSAgAh9AEAAIwBACD1AQAAjAEAIBBmAACoAgAgaQAAqQIAIKoBAACmAgAwqwEAAI4BABCsAQAApgIAMK0BAQCdAgAhrgEBAJ4CACGvAQEAjwIAIbABAQCQAgAhwQEBAI8CACHFAUAAkgIAIdUBAQCPAgAh1gEBAJACACHXAQEAngIAIdgBIACRAgAh2QFAAKcCACEItAFAAAAAAbUBQAAAAAW2AUAAAAAFtwFAAAAAAbgBQAAAAAG5AUAAAAABugFAAAAAAbsBQACbAgAhEGUAAJMCACBnAACUAgAgqgEAAI4CADCrAQAAjAEAEKwBAACOAgAwrQEBAJ0CACG_AQIAqgIAIcABAQCPAgAhwQEBAJACACHCAQEAkAIAIcMBAQCQAgAhxAEgAJECACHFAUAAkgIAIcYBQACSAgAh9AEAAIwBACD1AQAAjAEAIAPHAQAAlwEAIMgBAACXAQAgyQEAAJcBACAItAECAAAAAbUBAgAAAAS2AQIAAAAEtwECAAAAAbgBAgAAAAG5AQIAAAABugECAAAAAbsBAgCAAgAhC6oBAACrAgAwqwEAAIcBABCsAQAAqwIAMK0BAQD4AQAhrwEBAPkBACGwAQEA-QEAIcUBQAD6AQAhzAEBAPgBACHbAUAA-gEAIdwBAQCHAgAh3QFAAJkCACELqgEAAKwCADCrAQAAdAAQrAEAAKwCADCtAQEAnQIAIa8BAQCPAgAhsAEBAI8CACHFAUAAkgIAIcwBAQCdAgAh2wFAAJICACHcAQEAkAIAId0BQACnAgAhCaoBAACtAgAwqwEAAG4AEKwBAACtAgAwrQEBAPgBACHFAUAA-gEAIc4BAACWAgAg3gEBAPgBACHfAQEA-AEAIeABAQD5AQAhCKoBAACuAgAwqwEAAFgAEKwBAACuAgAwrQECAIYCACHMAQEA-AEAIc0BAQCHAgAh4QFAAPoBACHiAQEAhwIAIQcKAAGwAgAhqgEAAK8CADCrAQAAQgAQrAEAAK8CADDFAUAA-gEAIcwBAQD4AQAh4wEBAPkBACEHDAAAgAIAICEAALICACAiAACyAgAgtAEAAQAAAbUBAAEAAAS2AQABAAAEuwEAAbECACEHDAAAgAIAICEAALICACAiAACyAgAgtAEAAQAAAbUBAAEAAAS2AQABAAAEuwEAAbECACEEtAEAAQAAAbUBAAEAAAS2AQABAAAEuwEAAbICACEICQAAtQIAIAoAAbQCACGqAQAAswIAMKsBAAAMABCsAQAAswIAMMUBQACSAgAhzAEBAJ0CACHjAQEAjwIAIQS0AQABAAABtQEAAQAABLYBAAEAAAS7AQABsgIAIR4BAADDAgAgBAAAxAIAIAcAAMUCACAIAADFAgAgCgAAxgIAIAsAAMcCACCqAQAAwAIAMKsBAAADABCsAQAAwAIAMK0BAQCdAgAhrwEBAI8CACGwAQEAjwIAIcUBQACSAgAhxgFAAJICACHbAUAApwIAIdwBAQCQAgAh5AEBAI8CACHlAQEAjwIAIeYBAQCPAgAh5wEBAI8CACHoAQEAjwIAIekBAQCQAgAh6gEAALcCACDrAQAAnwIAIOwBCADBAgAh7QECAMICACHuAQEAngIAIe8BAgCqAgAh9AEAAAMAIPUBAAADACAWqgEAALYCADCrAQAAKgAQrAEAALYCADCtAQEA-AEAIa8BAQD5AQAhsAEBAPkBACHFAUAA-gEAIcYBQAD6AQAh2wFAAJkCACHcAQEAhwIAIeQBAQD5AQAh5QEBAPkBACHmAQEA-QEAIecBAQD5AQAh6AEBAPkBACHpAQEAhwIAIeoBAAC3AgAg6wEAAJYCACDsAQgAuAIAIe0BAgC5AgAh7gEBAPsBACHvAQIAhgIAIQS0AQEAAAAF8AEBAAAAAfEBAQAAAATyAQEAAAAEDQwAAP0BACAfAAC7AgAgIAAAuwIAICEAALsCACAiAAC7AgAgtAEIAAAAAbUBCAAAAAW2AQgAAAAFtwEIAAAAAbgBCAAAAAG5AQgAAAABugEIAAAAAbsBCAC8AgAhDQwAAP0BACAfAAC7AgAgIAAA_QEAICEAAP0BACAiAAD9AQAgtAECAAAAAbUBAgAAAAW2AQIAAAAFtwECAAAAAbgBAgAAAAG5AQIAAAABugECAAAAAbsBAgC6AgAhDQwAAP0BACAfAAC7AgAgIAAA_QEAICEAAP0BACAiAAD9AQAgtAECAAAAAbUBAgAAAAW2AQIAAAAFtwECAAAAAbgBAgAAAAG5AQIAAAABugECAAAAAbsBAgC6AgAhCLQBCAAAAAG1AQgAAAAFtgEIAAAABbcBCAAAAAG4AQgAAAABuQEIAAAAAboBCAAAAAG7AQgAuwIAIQ0MAAD9AQAgHwAAuwIAICAAALsCACAhAAC7AgAgIgAAuwIAILQBCAAAAAG1AQgAAAAFtgEIAAAABbcBCAAAAAG4AQgAAAABuQEIAAAAAboBCAAAAAG7AQgAvAIAIQkJAAC1AgAgqgEAAL0CADCrAQAADgAQrAEAAL0CADCtAQIAqgIAIcwBAQCdAgAhzQEBAJACACHhAUAAkgIAIeIBAQCQAgAhA94BAQAAAAHfAQEAAAAB4AEBAAAAAQsFAAC1AgAgBgAAtQIAIKoBAAC_AgAwqwEAAAcAEKwBAAC_AgAwrQEBAJ0CACHFAUAAkgIAIc4BAACfAgAg3gEBAJ0CACHfAQEAnQIAIeABAQCPAgAhHAEAAMMCACAEAADEAgAgBwAAxQIAIAgAAMUCACAKAADGAgAgCwAAxwIAIKoBAADAAgAwqwEAAAMAEKwBAADAAgAwrQEBAJ0CACGvAQEAjwIAIbABAQCPAgAhxQFAAJICACHGAUAAkgIAIdsBQACnAgAh3AEBAJACACHkAQEAjwIAIeUBAQCPAgAh5gEBAI8CACHnAQEAjwIAIegBAQCPAgAh6QEBAJACACHqAQAAtwIAIOsBAACfAgAg7AEIAMECACHtAQIAwgIAIe4BAQCeAgAh7wECAKoCACEItAEIAAAAAbUBCAAAAAW2AQgAAAAFtwEIAAAAAbgBCAAAAAG5AQgAAAABugEIAAAAAbsBCAC7AgAhCLQBAgAAAAG1AQIAAAAFtgECAAAABbcBAgAAAAG4AQIAAAABuQECAAAAAboBAgAAAAG7AQIA_QEAIR4BAADDAgAgBAAAxAIAIAcAAMUCACAIAADFAgAgCgAAxgIAIAsAAMcCACCqAQAAwAIAMKsBAAADABCsAQAAwAIAMK0BAQCdAgAhrwEBAI8CACGwAQEAjwIAIcUBQACSAgAhxgFAAJICACHbAUAApwIAIdwBAQCQAgAh5AEBAI8CACHlAQEAjwIAIeYBAQCPAgAh5wEBAI8CACHoAQEAjwIAIekBAQCQAgAh6gEAALcCACDrAQAAnwIAIOwBCADBAgAh7QECAMICACHuAQEAngIAIe8BAgCqAgAh9AEAAAMAIPUBAAADACADxwEAAAMAIMgBAAADACDJAQAAAwAgA8cBAAAHACDIAQAABwAgyQEAAAcAIAoJAAC1AgAgCgABtAIAIaoBAACzAgAwqwEAAAwAEKwBAACzAgAwxQFAAJICACHMAQEAnQIAIeMBAQCPAgAh9AEAAAwAIPUBAAAMACADxwEAAA4AIMgBAAAOACDJAQAADgAgAAAAAAH5AQEAAAABAfkBQAAAAAEB-QEBAAAAAQUZAACfBAAgGgAAogQAIPYBAACgBAAg9wEAAKEEACD8AQAAyQEAIAMZAACfBAAg9gEAAKAEACD8AQAAyQEAIAAAAAAABfkBAgAAAAH_AQIAAAABgAICAAAAAYECAgAAAAGCAgIAAAABAfkBIAAAAAELGQAA5gIAMBoAAOsCADD2AQAA5wIAMPcBAADoAgAw-AEAAOkCACD5AQAA6gIAMPoBAADqAgAw-wEAAOoCADD8AQAA6gIAMP0BAADsAgAw_gEAAO0CADALGQAA2gIAMBoAAN8CADD2AQAA2wIAMPcBAADcAgAw-AEAAN0CACD5AQAA3gIAMPoBAADeAgAw-wEAAN4CADD8AQAA3gIAMP0BAADgAgAw_gEAAOECADAGrQEBAAAAAa8BAQAAAAGwAQEAAAABsQEBAAAAAbIBQAAAAAGzAQEAAAABAgAAAJMBACAZAADlAgAgAwAAAJMBACAZAADlAgAgGgAA5AIAIAESAACeBAAwDGYAAKUCACCqAQAApAIAMKsBAACRAQAQrAEAAKQCADCtAQEAAAABrgEBAJ0CACGvAQEAjwIAIbABAQCPAgAhsQEBAI8CACGyAUAAkgIAIbMBAQCeAgAh2gEAAKMCACACAAAAkwEAIBIAAOQCACACAAAA4gIAIBIAAOMCACAKqgEAAOECADCrAQAA4gIAEKwBAADhAgAwrQEBAJ0CACGuAQEAnQIAIa8BAQCPAgAhsAEBAI8CACGxAQEAjwIAIbIBQACSAgAhswEBAJ4CACEKqgEAAOECADCrAQAA4gIAEKwBAADhAgAwrQEBAJ0CACGuAQEAnQIAIa8BAQCPAgAhsAEBAI8CACGxAQEAjwIAIbIBQACSAgAhswEBAJ4CACEGrQEBAMwCACGvAQEAzAIAIbABAQDMAgAhsQEBAMwCACGyAUAAzQIAIbMBAQDOAgAhBq0BAQDMAgAhrwEBAMwCACGwAQEAzAIAIbEBAQDMAgAhsgFAAM0CACGzAQEAzgIAIQatAQEAAAABrwEBAAAAAbABAQAAAAGxAQEAAAABsgFAAAAAAbMBAQAAAAELaQAAgAMAIK0BAQAAAAGvAQEAAAABsAEBAAAAAcEBAQAAAAHFAUAAAAAB1QEBAAAAAdYBAQAAAAHXAQEAAAAB2AEgAAAAAdkBQAAAAAECAAAAigEAIBkAAP8CACADAAAAigEAIBkAAP8CACAaAADxAgAgARIAAJ0EADAQZgAAqAIAIGkAAKkCACCqAQAApgIAMKsBAACOAQAQrAEAAKYCADCtAQEAAAABrgEBAJ4CACGvAQEAjwIAIbABAQCQAgAhwQEBAI8CACHFAUAAkgIAIdUBAQAAAAHWAQEAkAIAIdcBAQCeAgAh2AEgAJECACHZAUAApwIAIQIAAACKAQAgEgAA8QIAIAIAAADuAgAgEgAA7wIAIA6qAQAA7QIAMKsBAADuAgAQrAEAAO0CADCtAQEAnQIAIa4BAQCeAgAhrwEBAI8CACGwAQEAkAIAIcEBAQCPAgAhxQFAAJICACHVAQEAjwIAIdYBAQCQAgAh1wEBAJ4CACHYASAAkQIAIdkBQACnAgAhDqoBAADtAgAwqwEAAO4CABCsAQAA7QIAMK0BAQCdAgAhrgEBAJ4CACGvAQEAjwIAIbABAQCQAgAhwQEBAI8CACHFAUAAkgIAIdUBAQCPAgAh1gEBAJACACHXAQEAngIAIdgBIACRAgAh2QFAAKcCACEKrQEBAMwCACGvAQEAzAIAIbABAQDOAgAhwQEBAMwCACHFAUAAzQIAIdUBAQDMAgAh1gEBAM4CACHXAQEAzgIAIdgBIADXAgAh2QFAAPACACEB-QFAAAAAAQtpAADyAgAgrQEBAMwCACGvAQEAzAIAIbABAQDOAgAhwQEBAMwCACHFAUAAzQIAIdUBAQDMAgAh1gEBAM4CACHXAQEAzgIAIdgBIADXAgAh2QFAAPACACELGQAA8wIAMBoAAPgCADD2AQAA9AIAMPcBAAD1AgAw-AEAAPYCACD5AQAA9wIAMPoBAAD3AgAw-wEAAPcCADD8AQAA9wIAMP0BAAD5AgAw_gEAAPoCADAIrQEBAAAAAa8BAQAAAAGwAQEAAAABxQFAAAAAAcsBAQAAAAHMAQEAAAABzQEBAAAAAc4BgAAAAAECAAAAmQEAIBkAAP4CACADAAAAmQEAIBkAAP4CACAaAAD9AgAgARIAAJwEADANaAAAoAIAIKoBAACcAgAwqwEAAJcBABCsAQAAnAIAMK0BAQAAAAGvAQEAjwIAIbABAQCPAgAhxQFAAJICACHKAQEAnQIAIcsBAQCPAgAhzAEBAJ4CACHNAQEAkAIAIc4BAACfAgAgAgAAAJkBACASAAD9AgAgAgAAAPsCACASAAD8AgAgDKoBAAD6AgAwqwEAAPsCABCsAQAA-gIAMK0BAQCdAgAhrwEBAI8CACGwAQEAjwIAIcUBQACSAgAhygEBAJ0CACHLAQEAjwIAIcwBAQCeAgAhzQEBAJACACHOAQAAnwIAIAyqAQAA-gIAMKsBAAD7AgAQrAEAAPoCADCtAQEAnQIAIa8BAQCPAgAhsAEBAI8CACHFAUAAkgIAIcoBAQCdAgAhywEBAI8CACHMAQEAngIAIc0BAQCQAgAhzgEAAJ8CACAIrQEBAMwCACGvAQEAzAIAIbABAQDMAgAhxQFAAM0CACHLAQEAzAIAIcwBAQDOAgAhzQEBAM4CACHOAYAAAAABCK0BAQDMAgAhrwEBAMwCACGwAQEAzAIAIcUBQADNAgAhywEBAMwCACHMAQEAzgIAIc0BAQDOAgAhzgGAAAAAAQitAQEAAAABrwEBAAAAAbABAQAAAAHFAUAAAAABywEBAAAAAcwBAQAAAAHNAQEAAAABzgGAAAAAAQtpAACAAwAgrQEBAAAAAa8BAQAAAAGwAQEAAAABwQEBAAAAAcUBQAAAAAHVAQEAAAAB1gEBAAAAAdcBAQAAAAHYASAAAAAB2QFAAAAAAQQZAADzAgAw9gEAAPQCADD4AQAA9gIAIPwBAAD3AgAwBBkAAOYCADD2AQAA5wIAMPgBAADpAgAg_AEAAOoCADAEGQAA2gIAMPYBAADbAgAw-AEAAN0CACD8AQAA3gIAMAAAAAAABRkAAJcEACAaAACaBAAg9gEAAJgEACD3AQAAmQQAIPwBAACKAQAgAxkAAJcEACD2AQAAmAQAIPwBAACKAQAgAAAABxkAAJIEACAaAACVBAAg9gEAAJMEACD3AQAAlAQAIPoBAACMAQAg-wEAAIwBACD8AQAAyQEAIAMZAACSBAAg9gEAAJMEACD8AQAAyQEAIAdmAACQAwAgaQAAkQMAIK4BAADIAgAgsAEAAMgCACDWAQAAyAIAINcBAADIAgAg2QEAAMgCACAFZQAAgwMAIGcAAIQDACDBAQAAyAIAIMIBAADIAgAgwwEAAMgCACAAAAAAAAAABRkAAIoEACAaAACQBAAg9gEAAIsEACD3AQAAjwQAIPwBAAABACAFGQAAiAQAIBoAAI0EACD2AQAAiQQAIPcBAACMBAAg_AEAAAEAIAMZAACKBAAg9gEAAIsEACD8AQAAAQAgAxkAAIgEACD2AQAAiQQAIPwBAAABACAAAAAAAAUZAACDBAAgGgAAhgQAIPYBAACEBAAg9wEAAIUEACD8AQAAAQAgAxkAAIMEACD2AQAAhAQAIPwBAAABACAAAAAB-QEAAQAAAQUZAAD-AwAgGgAAgQQAIPYBAAD_AwAg9wEAAIAEACD8AQAAAQAgAxkAAP4DACD2AQAA_wMAIPwBAAABACANAQAAqQMAIAQAAPEDACAHAADyAwAgCAAA8gMAIAoAAPMDACALAAD0AwAg2wEAAMgCACDcAQAAyAIAIOkBAADIAgAg6wEAAMgCACDsAQAAyAIAIO0BAADIAgAg7gEAAMgCACAAAAAAAAL5AQEAAAAEgwIBAAAABQX5AQgAAAAB_wEIAAAAAYACCAAAAAGBAggAAAABggIIAAAAAQX5AQIAAAAB_wECAAAAAYACAgAAAAGBAgIAAAABggICAAAAAQcZAAD1AwAgGgAA_AMAIPYBAAD2AwAg9wEAAPsDACD6AQAAAwAg-wEAAAMAIPwBAAABACALGQAA3gMAMBoAAOMDADD2AQAA3wMAMPcBAADgAwAw-AEAAOEDACD5AQAA4gMAMPoBAADiAwAw-wEAAOIDADD8AQAA4gMAMP0BAADkAwAw_gEAAOUDADALGQAA1QMAMBoAANkDADD2AQAA1gMAMPcBAADXAwAw-AEAANgDACD5AQAAzQMAMPoBAADNAwAw-wEAAM0DADD8AQAAzQMAMP0BAADaAwAw_gEAANADADALGQAAyQMAMBoAAM4DADD2AQAAygMAMPcBAADLAwAw-AEAAMwDACD5AQAAzQMAMPoBAADNAwAw-wEAAM0DADD8AQAAzQMAMP0BAADPAwAw_gEAANADADAHGQAAxAMAIBoAAMcDACD2AQAAxQMAIPcBAADGAwAg-gEAAAwAIPsBAAAMACD8AQAALQAgCxkAALgDADAaAAC9AwAw9gEAALkDADD3AQAAugMAMPgBAAC7AwAg-QEAALwDADD6AQAAvAMAMPsBAAC8AwAw_AEAALwDADD9AQAAvgMAMP4BAAC_AwAwBK0BAgAAAAHNAQEAAAAB4QFAAAAAAeIBAQAAAAECAAAAEAAgGQAAwwMAIAMAAAAQACAZAADDAwAgGgAAwgMAIAESAAD6AwAwCQkAALUCACCqAQAAvQIAMKsBAAAOABCsAQAAvQIAMK0BAgAAAAHMAQEAnQIAIc0BAQCQAgAh4QFAAJICACHiAQEAkAIAIQIAAAAQACASAADCAwAgAgAAAMADACASAADBAwAgCKoBAAC_AwAwqwEAAMADABCsAQAAvwMAMK0BAgCqAgAhzAEBAJ0CACHNAQEAkAIAIeEBQACSAgAh4gEBAJACACEIqgEAAL8DADCrAQAAwAMAEKwBAAC_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_AEAAM0DADAEGQAAyQMAMPYBAADKAwAw-AEAAMwDACD8AQAAzQMAMAMZAADEAwAg9gEAAMUDACD8AQAALQAgBBkAALgDADD2AQAAuQMAMPgBAAC7AwAg_AEAALwDADADGQAA9QMAIPYBAAD2AwAg_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_AQIA1gIAIcABAQDMAgAhwQEBAM4CACHCAQEAzgIAIcMBAQDOAgAhxAEgANcCACHFAUAAzQIAIcYBQADNAgAhDGYAAI4DACCtAQEAAAABrgEBAAAAAa8BAQAAAAGwAQEAAAABwQEBAAAAAcUBQAAAAAHVAQEAAAAB1gEBAAAAAdcBAQAAAAHYASAAAAAB2QFAAAAAAQIAAACKAQAgGQAAlwQAIAMAAACOAQAgGQAAlwQAIBoAAJsEACAOAAAAjgEAIBIAAJsEACBmAACNAwAgrQEBAMwCACGuAQEAzgIAIa8BAQDMAgAhsAEBAM4CACHBAQEAzAIAIcUBQADNAgAh1QEBAMwCACHWAQEAzgIAIdcBAQDOAgAh2AEgANcCACHZAUAA8AIAIQxmAACNAwAgrQEBAMwCACGuAQEAzgIAIa8BAQDMAgAhsAEBAM4CACHBAQEAzAIAIcUBQADNAgAh1QEBAMwCACHWAQEAzgIAIdcBAQDOAgAh2AEgANcCACHZAUAA8AIAIQitAQEAAAABrwEBAAAAAbABAQAAAAHFAUAAAAABywEBAAAAAcwBAQAAAAHNAQEAAAABzgGAAAAAAQqtAQEAAAABrwEBAAAAAbABAQAAAAHBAQEAAAABxQFAAAAAAdUBAQAAAAHWAQEAAAAB1wEBAAAAAdgBIAAAAAHZAUAAAAABBq0BAQAAAAGvAQEAAAABsAEBAAAAAbEBAQAAAAGyAUAAAAABswEBAAAAAQplAACBAwAgrQEBAAAAAb8BAgAAAAHAAQEAAAABwQEBAAAAAcIBAQAAAAHDAQEAAAABxAEgAAAAAcUBQAAAAAHGAUAAAAABAgAAAMkBACAZAACfBAAgAwAAAIwBACAZAACfBAAgGgAAowQAIAwAAACMAQAgEgAAowQAIGUAANgCACCtAQEAzAIAIb8BAgDWAgAhwAEBAMwCACHBAQEAzgIAIcIBAQDOAgAhwwEBAM4CACHEASAA1wIAIcUBQADNAgAhxgFAAM0CACEKZQAA2AIAIK0BAQDMAgAhvwECANYCACHAAQEAzAIAIcEBAQDOAgAhwgEBAM4CACHDAQEAzgIAIcQBIADXAgAhxQFAAM0CACHGAUAAzQIAIQcBBAEEBgEHCgIICwIKDQMLEQQMAAUCBQABBgABAQkAAQEJAAEEBBIABxMACBQACxUAAAEBHwEBASUBBQwACh8ACyAADCEADSIADgAAAAAABQwACh8ACyAADCEADSIADgEJAAEBCQABAwwAEyEAFCIAFQAAAAMMABMhABQiABUBCQABAQkAAQUMABofABsgABwhAB0iAB4AAAAAAAUMABofABsgABwhAB0iAB4CBQABBgABAgUAAQYAAQMMACMhACQiACUAAAADDAAjIQAkIgAlAAAAAwwAKyEALCIALQAAAAMMACshACwiAC0DDAA0Zo0BMGmaATMDDAAyZZABL2eUATEBZgAwAmWVAQBnlgEAAWgALwFpmwEAAWalATABZqsBMAMMADghADkiADoAAAADDAA4IQA5IgA6AWgALwFoAC8DDAA_IQBAIgBBAAAAAwwAPyEAQCIAQQAABQwARh8ARyAASCEASSIASgAAAAAABQwARh8ARyAASCEASSIASgFmADABZgAwAwwATyEAUCIAUQAAAAMMAE8hAFAiAFENAgEOFgEPFwEQGAERGQETGwEUHQYVHgcWIQEXIwYYJAgbJgEcJwEdKAYjKwkkLA8lLgMmLwMnMQMoMgMpMwMqNQMrNwYsOBAtOgMuPAYvPREwPgMxPwMyQAYzQxI0RBY1RQQ2RgQ3RwQ4SAQ5SQQ6SwQ7TQY8Thc9UAQ-UgY_UxhAVARBVQRCVgZDWRlEWh9FWwJGXAJHXQJIXgJJXwJKYQJLYwZMZCBNZgJOaAZPaSFQagJRawJSbAZTbyJUcCZVcidWcydXdidYdydZeCdaeidbfAZcfShdfydegQEGX4IBKWCDASdhhAEnYoUBBmOIASpkiQEuaosBL2ucAS9snQEvbZ4BL26fAS9voQEvcKMBBnGkATVypwEvc6kBBnSqATZ1rAEvdq0BL3euAQZ4sQE3ebIBO3qzATN7tAEzfLUBM322ATN-twEzf7kBM4ABuwEGgQG8ATyCAb4BM4MBwAEGhAHBAT2FAcIBM4YBwwEzhwHEAQaIAccBPokByAFCigHKATCLAcsBMIwBzQEwjQHOATCOAc8BMI8B0QEwkAHTAQaRAdQBQ5IB1gEwkwHYAQaUAdkBRJUB2gEwlgHbATCXAdwBBpgB3wFFmQHgAUuaAeEBMZsB4gExnAHjATGdAeQBMZ4B5QExnwHnATGgAekBBqEB6gFMogHsATGjAe4BBqQB7wFNpQHwATGmAfEBMacB8gEGqAH1AU6pAfYBUg"
3579
+ };
3580
+ async function decodeBase64AsWasm(wasmBase64) {
3581
+ const { Buffer: Buffer2 } = await import("buffer");
3582
+ const wasmArray = Buffer2.from(wasmBase64, "base64");
3583
+ return new WebAssembly.Module(wasmArray);
3584
+ }
3585
+ config.compilerWasm = {
3586
+ getRuntime: async () => await import("@prisma/client/runtime/query_compiler_fast_bg.postgresql.mjs"),
3587
+ getQueryCompilerWasmModule: async () => {
3588
+ const { wasm } = await import("@prisma/client/runtime/query_compiler_fast_bg.postgresql.wasm-base64.mjs");
3589
+ return await decodeBase64AsWasm(wasm);
3590
+ },
3591
+ importName: "./query_compiler_fast_bg.js"
3592
+ };
3593
+ function getPrismaClientClass() {
3594
+ return runtime.getPrismaClient(config);
3595
+ }
3596
+ var getExtensionContext = runtime2.Extensions.getExtensionContext;
3597
+ var NullTypes2 = {
3598
+ DbNull: runtime2.NullTypes.DbNull,
3599
+ JsonNull: runtime2.NullTypes.JsonNull,
3600
+ AnyNull: runtime2.NullTypes.AnyNull
3601
+ };
3602
+ var TransactionIsolationLevel = runtime2.makeStrictEnum({
3603
+ ReadUncommitted: "ReadUncommitted",
3604
+ ReadCommitted: "ReadCommitted",
3605
+ RepeatableRead: "RepeatableRead",
3606
+ Serializable: "Serializable"
3607
+ });
3608
+ var defineExtension = runtime2.Extensions.defineExtension;
3609
+ globalThis["__dirname"] = path22.dirname(fileURLToPath(import.meta.url));
3610
+ var PrismaClient = getPrismaClientClass();
3611
+
3612
+ export {
3613
+ __require,
3614
+ resolveLifecycleConfig,
3615
+ applyLifecycleDefaults,
3616
+ LifecycleScheduler,
3617
+ mergeAndRank,
3618
+ resolveVisibility,
3619
+ generateEmbedding,
3620
+ computeRepositoryHealth,
3621
+ generateSuggestions,
3622
+ persistReviewableSuggestions,
3623
+ formatSuggestion,
3624
+ findConsolidationCandidates,
3625
+ executeConsolidation,
3626
+ formatCandidatePreview,
3627
+ buildAutoLinkQuery,
3628
+ getNotifications,
3629
+ formatNotificationsSummary,
3630
+ runLocalLifecycleMaintenance,
3631
+ MEMORY_TEMPLATES,
3632
+ getTemplate,
3633
+ applyTemplate,
3634
+ formatTemplateList,
3635
+ validateMemoryType,
3636
+ parseConfidence,
3637
+ parseThreshold,
3638
+ parseTtl,
3639
+ parsePositiveInt,
3640
+ detectGitInfo,
3641
+ getDataDir,
3642
+ getDbPath,
3643
+ getConfigPath,
3644
+ isInitialized,
3645
+ findRepoRoot,
3646
+ loadConfig,
3647
+ saveConfig,
3648
+ defaultConfig,
3649
+ RemoteClient,
3650
+ LocalStore
3651
+ };
3652
+ //# sourceMappingURL=chunk-CKUDYQYP.js.map