@theokit/sdk-memory 0.3.3 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/dist/index.cjs +165 -344
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.js +52 -326
  5. package/dist/index.js.map +1 -1
  6. package/dist/internal/active-memory/active-memory.d.ts.map +1 -1
  7. package/dist/internal/dreaming/dreaming-diary.d.ts +6 -61
  8. package/dist/internal/dreaming/dreaming-diary.d.ts.map +1 -1
  9. package/dist/internal/index/index-db.d.ts +0 -7
  10. package/dist/internal/index/index-db.d.ts.map +1 -1
  11. package/dist/internal/index/index-manager.d.ts +9 -1
  12. package/dist/internal/index/index-manager.d.ts.map +1 -1
  13. package/dist/internal/index/lance-index.d.ts +3 -6
  14. package/dist/internal/index/lance-index.d.ts.map +1 -1
  15. package/dist/internal/index/migrate-sqlite-to-lance.d.ts +5 -0
  16. package/dist/internal/index/migrate-sqlite-to-lance.d.ts.map +1 -1
  17. package/dist/internal/store/markdown-store.d.ts +24 -32
  18. package/dist/internal/store/markdown-store.d.ts.map +1 -1
  19. package/dist/internal/store/session-loader.d.ts +3 -27
  20. package/dist/internal/store/session-loader.d.ts.map +1 -1
  21. package/dist/internal/store/session-summary-writer.d.ts +6 -53
  22. package/dist/internal/store/session-summary-writer.d.ts.map +1 -1
  23. package/dist/internal/store/transcript-store.d.ts +3 -45
  24. package/dist/internal/store/transcript-store.d.ts.map +1 -1
  25. package/dist/internal/store/wiki-loader.d.ts +3 -32
  26. package/dist/internal/store/wiki-loader.d.ts.map +1 -1
  27. package/dist/internal/tools.d.ts +3 -1
  28. package/dist/internal/tools.d.ts.map +1 -1
  29. package/package.json +3 -3
package/dist/index.cjs CHANGED
@@ -4,10 +4,11 @@ var promises = require('fs/promises');
4
4
  var path = require('path');
5
5
  var sdk = require('@theokit/sdk');
6
6
  var persistence = require('@theokit/sdk/persistence');
7
- var pathSafety = require('@theokit/sdk/path-safety');
7
+ var memoryStore = require('@theokit/sdk/internal/memory-store');
8
8
  var crypto = require('crypto');
9
9
  var memoryAdapters = require('@theokit/sdk/internal/memory-adapters');
10
10
  var errors = require('@theokit/sdk/errors');
11
+ var pathSafety = require('@theokit/sdk/path-safety');
11
12
  var fs = require('fs');
12
13
  var module$1 = require('module');
13
14
 
@@ -240,121 +241,17 @@ function createInMemoryMarkdownProvider() {
240
241
  }
241
242
  };
242
243
  }
243
- function redactSecrets(text, opts) {
244
- return sdk.Security.redact(text, opts);
245
- }
246
- function legacyMemoryJsonPath(cwd, config) {
247
- if (config.storePath !== void 0) {
248
- return path.resolve(cwd, config.storePath);
249
- }
250
- const namespace = pathSafety.sanitizeIdentifier(config.namespace ?? "default");
251
- const scope = pathSafety.sanitizeIdentifier(config.scope ?? "agent", { maxLen: 16 });
252
- const userId = pathSafety.sanitizeIdentifier(config.userId ?? "default");
253
- return pathSafety.safePathJoin(cwd, ".theokit", "memory", namespace, `${scope}-${userId}.json`);
254
- }
255
-
256
- // src/internal/store/markdown-store.ts
257
- var MEMORY_MD_HEADER = "# Memory\n\n> Auto-managed by @theokit/sdk. Edit freely \u2014 the SDK reads from here.\n";
258
- var FACTS_HEADING = "## Facts";
259
- function memoryDir(cwd) {
260
- return path.join(cwd, ".theokit", "memory");
261
- }
262
- function memoryMdPath(cwd) {
263
- return path.join(memoryDir(cwd), "MEMORY.md");
264
- }
265
- function notesDir(cwd) {
266
- return path.join(memoryDir(cwd), "notes");
267
- }
268
- async function readFactsFromMarkdown(cwd) {
269
- let raw;
270
- try {
271
- raw = await promises.readFile(memoryMdPath(cwd), "utf8");
272
- } catch {
273
- return [];
274
- }
275
- return parseFactsSection(raw);
276
- }
277
- function appendFactToMarkdown(cwd, fact) {
278
- return persistence.withCwdMutex(memoryDir(cwd), async () => {
279
- const path = memoryMdPath(cwd);
280
- let raw = "";
281
- try {
282
- raw = await promises.readFile(path, "utf8");
283
- } catch {
284
- raw = "";
285
- }
286
- const sanitized = redactSecrets(fact.text);
287
- const next = insertFactBullet(raw, sanitized);
288
- await promises.mkdir(memoryDir(cwd), { recursive: true });
289
- await persistence.replaceFileAtomic(path, next);
290
- });
291
- }
292
244
  async function listNotes(cwd) {
293
245
  let entries = [];
294
246
  try {
295
- entries = await promises.readdir(notesDir(cwd));
247
+ entries = await promises.readdir(memoryStore.notesDir(memoryStore.resolveMemoryRoot(cwd)));
296
248
  } catch {
297
249
  return [];
298
250
  }
299
- return entries.filter((name) => name.endsWith(".md")).map((name) => ({ slug: name.replace(/\.md$/, ""), path: path.join(notesDir(cwd), name) }));
300
- }
301
- function parseFactsSection(raw) {
302
- const idx = raw.indexOf(FACTS_HEADING);
303
- if (idx === -1) return [];
304
- const tail = raw.slice(idx + FACTS_HEADING.length);
305
- const nextHeading = tail.search(/\n#{1,2}\s/);
306
- const block = nextHeading === -1 ? tail : tail.slice(0, nextHeading);
307
- return block.split("\n").map((line) => line.trim()).filter((line) => line.startsWith("- ")).map((line) => ({ text: line.slice(2).trim() }));
308
- }
309
- function insertFactBullet(raw, fact) {
310
- const bullet = `- ${fact}`;
311
- if (raw.length === 0) {
312
- return `${MEMORY_MD_HEADER}
313
- ${FACTS_HEADING}
314
-
315
- ${bullet}
316
- `;
317
- }
318
- const idx = raw.indexOf(FACTS_HEADING);
319
- if (idx === -1) {
320
- const sep = raw.endsWith("\n") ? "" : "\n";
321
- return `${raw}${sep}
322
- ${FACTS_HEADING}
323
-
324
- ${bullet}
325
- `;
326
- }
327
- const after = idx + FACTS_HEADING.length;
328
- const nextHeading = raw.slice(after).search(/\n#{1,2}\s/);
329
- if (nextHeading === -1) {
330
- const trailing = raw.endsWith("\n") ? "" : "\n";
331
- return `${raw}${trailing}${bullet}
332
- `;
333
- }
334
- const insertAt = after + nextHeading;
335
- return `${raw.slice(0, insertAt)}
336
- ${bullet}${raw.slice(insertAt)}`;
337
- }
338
- async function readFacts(cwd, config) {
339
- if (!config.enabled) return [];
340
- return readFactsFromMarkdown(cwd);
341
- }
342
- async function appendFact(cwd, config, fact) {
343
- if (!config.enabled) return;
344
- await appendFactToMarkdown(cwd, fact);
345
- }
346
-
347
- // src/internal/store/transcript-store.ts
348
- async function persistActiveMemoryTranscript(cwd, transcript) {
349
- try {
350
- const dir = path.join(memoryDir(cwd), "transcripts", "active-memory");
351
- const file = path.join(dir, `${transcript.runId}.json`);
352
- await persistence.atomicWriteJson(file, transcript);
353
- } catch (cause) {
354
- const message = cause instanceof Error ? cause.message : String(cause);
355
- process.stderr.write(`[theokit-sdk] active-memory transcript persist failed: ${message}
356
- `);
357
- }
251
+ return entries.filter((name) => name.endsWith(".md")).map((name) => ({
252
+ slug: name.replace(/\.md$/, ""),
253
+ path: path.join(memoryStore.notesDir(memoryStore.resolveMemoryRoot(cwd)), name)
254
+ }));
358
255
  }
359
256
 
360
257
  // src/internal/active-memory/active-memory.ts
@@ -497,7 +394,7 @@ async function finalize(args, queryMode, result) {
497
394
  };
498
395
  args.cache?.set(args.userText, queryMode, result, tenantCtx);
499
396
  if (args.persistTranscripts === true && args.cwd !== void 0) {
500
- await persistActiveMemoryTranscript(args.cwd, {
397
+ await memoryStore.persistActiveMemoryTranscript(memoryStore.resolveMemoryRoot(args.cwd), {
501
398
  runId: args.runId ?? `run-${Date.now()}`,
502
399
  startedAtMs: Date.now() - result.durationMs,
503
400
  userText: args.userText,
@@ -951,6 +848,20 @@ var MEMORY_EMBEDDING_ADAPTERS = {
951
848
  jina: jinaMemoryEmbeddingProviderAdapter,
952
849
  gemini: geminiMemoryEmbeddingProviderAdapter
953
850
  };
851
+ function redactSecrets(text, opts) {
852
+ return sdk.Security.redact(text, opts);
853
+ }
854
+ function legacyMemoryJsonPath(cwd, config) {
855
+ if (config.storePath !== void 0) {
856
+ return path.resolve(cwd, config.storePath);
857
+ }
858
+ const namespace = pathSafety.sanitizeIdentifier(config.namespace ?? "default");
859
+ const scope = pathSafety.sanitizeIdentifier(config.scope ?? "agent", { maxLen: 16 });
860
+ const userId = pathSafety.sanitizeIdentifier(config.userId ?? "default");
861
+ return pathSafety.safePathJoin(cwd, ".theokit", "memory", namespace, `${scope}-${userId}.json`);
862
+ }
863
+
864
+ // src/internal/adapter-http-error.ts
954
865
  var RAW_MAX_BYTES = 2048;
955
866
  function parseRetryAfter(headers) {
956
867
  if (headers === void 0) return void 0;
@@ -1039,7 +950,7 @@ function mapOpenAiStatusToCode(status, body) {
1039
950
  function formatMessage(providerId, status, code) {
1040
951
  return `${providerId} API error: ${code} (HTTP ${status})`;
1041
952
  }
1042
- var FACTS_HEADING2 = "## Facts";
953
+ var FACTS_HEADING = "## Facts";
1043
954
  function createCategorizedMemory(options) {
1044
955
  const { root, categories } = options;
1045
956
  validateCategories(categories);
@@ -1113,7 +1024,7 @@ function header(category) {
1113
1024
  category: ${category}
1114
1025
  ---
1115
1026
 
1116
- ${FACTS_HEADING2}
1027
+ ${FACTS_HEADING}
1117
1028
  `;
1118
1029
  }
1119
1030
  async function readFileOrEmpty(path) {
@@ -1137,24 +1048,24 @@ function decodeFact(text) {
1137
1048
  );
1138
1049
  }
1139
1050
  function parseFactBullets(raw) {
1140
- const idx = raw.indexOf(FACTS_HEADING2);
1051
+ const idx = raw.indexOf(FACTS_HEADING);
1141
1052
  if (idx === -1) return [];
1142
- const tail = raw.slice(idx + FACTS_HEADING2.length);
1053
+ const tail = raw.slice(idx + FACTS_HEADING.length);
1143
1054
  const nextHeading = tail.search(/\n#{1,2}\s/);
1144
1055
  const block = nextHeading === -1 ? tail : tail.slice(0, nextHeading);
1145
1056
  return block.split("\n").map((line) => line.trim()).filter((line) => line.startsWith("- ")).map((line) => line.slice(2).trim());
1146
1057
  }
1147
1058
  function appendBullet(raw, text) {
1148
1059
  const bullet = `- ${text}`;
1149
- const idx = raw.indexOf(FACTS_HEADING2);
1060
+ const idx = raw.indexOf(FACTS_HEADING);
1150
1061
  if (idx === -1) {
1151
1062
  const sep = raw.endsWith("\n") ? "" : "\n";
1152
- return `${raw}${sep}${FACTS_HEADING2}
1063
+ return `${raw}${sep}${FACTS_HEADING}
1153
1064
 
1154
1065
  ${bullet}
1155
1066
  `;
1156
1067
  }
1157
- const after = idx + FACTS_HEADING2.length;
1068
+ const after = idx + FACTS_HEADING.length;
1158
1069
  const nextHeading = raw.slice(after).search(/\n#{1,2}\s/);
1159
1070
  if (nextHeading === -1) {
1160
1071
  const trailing = raw.endsWith("\n") ? "" : "\n";
@@ -1165,47 +1076,6 @@ ${bullet}
1165
1076
  return `${raw.slice(0, insertAt)}
1166
1077
  ${bullet}${raw.slice(insertAt)}`;
1167
1078
  }
1168
- function diaryPath(cwd) {
1169
- return path.join(memoryDir(cwd), "dream-diary.md");
1170
- }
1171
- function renderDiaryEntry(entry) {
1172
- const stamp = new Date(entry.timestampMs).toISOString();
1173
- const hash = entryHash(entry).slice(0, 8);
1174
- return [
1175
- `## ${stamp}`,
1176
- "",
1177
- `- entry-hash: ${hash}`,
1178
- `- facts before: ${entry.factsBefore}`,
1179
- `- facts after: ${entry.factsAfter}`,
1180
- `- duplicates removed: ${entry.duplicatesRemoved}`,
1181
- `- clusters created: ${entry.clustersCreated}`,
1182
- `- notes written: ${entry.notesWritten}`,
1183
- ""
1184
- ].join("\n");
1185
- }
1186
- async function appendDiaryEntry(cwd, entry) {
1187
- const path = diaryPath(cwd);
1188
- let raw = "";
1189
- try {
1190
- raw = await promises.readFile(path, "utf8");
1191
- } catch {
1192
- raw = "# Dream Diary\n\n";
1193
- }
1194
- const next = `${raw.endsWith("\n") ? raw : `${raw}
1195
- `}${renderDiaryEntry(entry)}`;
1196
- await persistence.replaceFileAtomic(path, next);
1197
- }
1198
- function entryHash(entry) {
1199
- return crypto.createHash("sha256").update(
1200
- [
1201
- entry.factsBefore,
1202
- entry.factsAfter,
1203
- entry.duplicatesRemoved,
1204
- entry.clustersCreated,
1205
- entry.notesWritten
1206
- ].join("|")
1207
- ).digest("hex");
1208
- }
1209
1079
 
1210
1080
  // src/internal/dreaming/dreaming-phases.ts
1211
1081
  var DEFAULT_DEDUP_THRESHOLD = 0.95;
@@ -1311,7 +1181,7 @@ async function runInner(options) {
1311
1181
  const now = options.now ?? Date.now;
1312
1182
  const timestampMs = now();
1313
1183
  try {
1314
- const facts = await readFactsFromMarkdown(options.cwd);
1184
+ const facts = await memoryStore.readFactsFromMarkdown(options.cwd);
1315
1185
  if (facts.length === 0) {
1316
1186
  return emptyResult("skipped");
1317
1187
  }
@@ -1327,7 +1197,7 @@ async function runInner(options) {
1327
1197
  notesWritten,
1328
1198
  diaryEntryHash: void 0
1329
1199
  };
1330
- await appendDiaryEntry(options.cwd, {
1200
+ await memoryStore.appendDiaryEntry(memoryStore.resolveMemoryRoot(options.cwd), {
1331
1201
  timestampMs,
1332
1202
  factsBefore: result.factsBefore,
1333
1203
  factsAfter: result.factsAfter,
@@ -1345,10 +1215,10 @@ async function runInner(options) {
1345
1215
  }
1346
1216
  async function writeConsolidatedNotes(cwd, clusters, timestampMs) {
1347
1217
  if (clusters.length === 0) return 0;
1348
- const notesDir2 = path.join(memoryDir(cwd), "notes");
1349
- await promises.mkdir(notesDir2, { recursive: true });
1218
+ const notesDir3 = path.join(memoryStore.resolveMemoryRoot(cwd), "notes");
1219
+ await promises.mkdir(notesDir3, { recursive: true });
1350
1220
  const isoSlug = new Date(timestampMs).toISOString().replace(/[^\dT]/g, "-");
1351
- const file = path.join(notesDir2, `dreamed-${isoSlug}.md`);
1221
+ const file = path.join(notesDir3, `dreamed-${isoSlug}.md`);
1352
1222
  const body = deepPhase(clusters, timestampMs);
1353
1223
  await persistence.replaceFileAtomic(file, body);
1354
1224
  return 1;
@@ -1418,9 +1288,6 @@ async function openMemoryDb(opts) {
1418
1288
  }
1419
1289
  });
1420
1290
  }
1421
- function defaultIndexPath(cwd) {
1422
- return path.join(cwd, ".theokit", "memory", ".index", "memory.sqlite");
1423
- }
1424
1291
  var HEADING_RE = /^(#{1,6})\s+(.+?)\s*$/;
1425
1292
  function chunkMarkdown(text, options = {}) {
1426
1293
  const maxChars = options.maxChars ?? 800;
@@ -1496,91 +1363,6 @@ function findWordBoundarySplit(text, maxChars) {
1496
1363
  }
1497
1364
  return maxChars;
1498
1365
  }
1499
- var MAX_TURN_CHARS = 2e3;
1500
- function sessionsDir(cwd) {
1501
- return path.join(memoryDir(cwd), "sessions");
1502
- }
1503
- function sessionSummaryPath(cwd, runId) {
1504
- return path.join(sessionsDir(cwd), `${sanitizeRunId2(runId)}.md`);
1505
- }
1506
- function sanitizeRunId2(runId) {
1507
- return runId.replace(/[^a-zA-Z0-9_-]/g, "_").slice(0, 128);
1508
- }
1509
- function truncate2(text) {
1510
- if (text.length <= MAX_TURN_CHARS) return text;
1511
- return `${text.slice(0, MAX_TURN_CHARS)}\u2026`;
1512
- }
1513
- async function writeSessionSummary(input) {
1514
- if (input.status !== "finished") return;
1515
- const path = sessionSummaryPath(input.cwd, input.runId);
1516
- await promises.mkdir(sessionsDir(input.cwd), { recursive: true });
1517
- const safeUser = redactSecrets(truncate2(input.userText));
1518
- const safeAssistant = redactSecrets(truncate2(input.assistantText));
1519
- const iso = new Date(input.at).toISOString();
1520
- const body = [
1521
- "---",
1522
- `runId: ${input.runId}`,
1523
- `agentId: ${input.agentId}`,
1524
- `at: ${iso}`,
1525
- `status: ${input.status}`,
1526
- "---",
1527
- "",
1528
- "## User",
1529
- "",
1530
- safeUser,
1531
- "",
1532
- "## Assistant",
1533
- "",
1534
- safeAssistant,
1535
- ""
1536
- ].join("\n");
1537
- await persistence.replaceFileAtomic(path, body);
1538
- }
1539
-
1540
- // src/internal/store/session-loader.ts
1541
- async function discoverSessionFiles(cwd) {
1542
- let entries;
1543
- try {
1544
- entries = await promises.readdir(sessionsDir(cwd));
1545
- } catch {
1546
- return [];
1547
- }
1548
- const root = memoryDir(cwd);
1549
- return entries.filter((entry) => entry.endsWith(".md")).map((entry) => {
1550
- const absolutePath = path.join(sessionsDir(cwd), entry);
1551
- return {
1552
- absolutePath,
1553
- relPath: relativeToRoot(root, absolutePath)
1554
- };
1555
- });
1556
- }
1557
- function relativeToRoot(root, absolutePath) {
1558
- if (absolutePath.startsWith(`${root}/`)) return absolutePath.slice(root.length + 1);
1559
- return absolutePath;
1560
- }
1561
- function wikiDir(cwd) {
1562
- return path.join(memoryDir(cwd), "wiki");
1563
- }
1564
- async function discoverWikiFiles(cwd) {
1565
- let entries;
1566
- try {
1567
- entries = await promises.readdir(wikiDir(cwd));
1568
- } catch {
1569
- return [];
1570
- }
1571
- const root = memoryDir(cwd);
1572
- return entries.filter((entry) => entry.endsWith(".md")).map((entry) => ({
1573
- absolutePath: path.join(wikiDir(cwd), entry),
1574
- relPath: path.join("wiki", entry)
1575
- })).map((file) => ({
1576
- absolutePath: file.absolutePath,
1577
- relPath: relativeToRoot2(root, file.absolutePath)
1578
- }));
1579
- }
1580
- function relativeToRoot2(root, absolutePath) {
1581
- if (absolutePath.startsWith(`${root}/`)) return absolutePath.slice(root.length + 1);
1582
- return absolutePath;
1583
- }
1584
1366
  function requireLance() {
1585
1367
  try {
1586
1368
  const r = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
@@ -1603,7 +1385,7 @@ var LanceIndex = class _LanceIndex {
1603
1385
  embeddingDim;
1604
1386
  static async open(opts) {
1605
1387
  const lance = requireLance();
1606
- const storagePath = opts.storagePath ?? path.join(opts.cwd, ".theokit", "memory", "lance");
1388
+ const storagePath = opts.storagePath ?? memoryStore.lanceStoragePath(opts.memoryRoot ?? memoryStore.resolveMemoryRoot(opts.cwd));
1607
1389
  fs.mkdirSync(storagePath, { recursive: true });
1608
1390
  const conn = await lance.connect(storagePath);
1609
1391
  const dim = opts.embedding.dimension;
@@ -1705,9 +1487,6 @@ function isLanceAvailable() {
1705
1487
  return false;
1706
1488
  }
1707
1489
  }
1708
- function lanceStoragePath(cwd) {
1709
- return path.join(cwd, ".theokit", "memory", "lance");
1710
- }
1711
1490
 
1712
1491
  // src/internal/index/memory-index.ts
1713
1492
  function parseSearchOptions(options = {}) {
@@ -1907,12 +1686,12 @@ async function embedMissingChunks(args) {
1907
1686
 
1908
1687
  // src/internal/index/index-manager.ts
1909
1688
  var IndexManager = class _IndexManager {
1910
- constructor(cwd, db, embedding) {
1911
- this.cwd = cwd;
1689
+ constructor(memoryRoot, db, embedding) {
1690
+ this.memoryRoot = memoryRoot;
1912
1691
  this.db = db;
1913
1692
  this.embedding = embedding;
1914
1693
  }
1915
- cwd;
1694
+ memoryRoot;
1916
1695
  db;
1917
1696
  embedding;
1918
1697
  lastSyncMs;
@@ -1925,9 +1704,10 @@ var IndexManager = class _IndexManager {
1925
1704
  }
1926
1705
  /** Internal SQLite-path open. Renamed from previous public `open`. */
1927
1706
  static async openSqliteInternal(opts) {
1928
- const filePath = opts.filePath ?? defaultIndexPath(opts.cwd);
1707
+ const memoryRoot = opts.memoryRoot ?? memoryStore.resolveMemoryRoot(opts.cwd);
1708
+ const filePath = opts.filePath ?? memoryStore.defaultIndexPath(memoryStore.projectMemoryDir(opts.cwd));
1929
1709
  const db = await openMemoryDb({ filePath });
1930
- const manager = new _IndexManager(opts.cwd, db, opts.embedding);
1710
+ const manager = new _IndexManager(memoryRoot, db, opts.embedding);
1931
1711
  if (opts.embedding !== void 0) await manager.initVectorBackend(opts.embedding);
1932
1712
  return manager;
1933
1713
  }
@@ -1948,7 +1728,7 @@ var IndexManager = class _IndexManager {
1948
1728
  }
1949
1729
  /** Walk the memory corpus + (re)index changed files. */
1950
1730
  async sync() {
1951
- const files = await collectMarkdownFiles(this.cwd);
1731
+ const files = await memoryStore.collectMarkdownFiles(this.memoryRoot);
1952
1732
  let filesUpdated = 0;
1953
1733
  let chunksWritten = 0;
1954
1734
  const existingByPath = this.loadFilesIndex();
@@ -2145,45 +1925,6 @@ function blendScores(hit, vectorScore, weights) {
2145
1925
  ...vectorScore > 0 ? { vectorScore } : {}
2146
1926
  };
2147
1927
  }
2148
- async function collectMarkdownFiles(cwd) {
2149
- const root = memoryDir(cwd);
2150
- const results = [];
2151
- try {
2152
- await promises.stat(memoryMdPath(cwd));
2153
- results.push({
2154
- absolutePath: memoryMdPath(cwd),
2155
- relPath: path.relative(root, memoryMdPath(cwd)),
2156
- source: "memory"
2157
- });
2158
- } catch {
2159
- }
2160
- try {
2161
- const entries = await promises.readdir(notesDir(cwd));
2162
- for (const entry of entries) {
2163
- if (!entry.endsWith(".md")) continue;
2164
- const abs = path.join(notesDir(cwd), entry);
2165
- results.push({ absolutePath: abs, relPath: path.relative(root, abs), source: "memory" });
2166
- }
2167
- } catch {
2168
- }
2169
- const wikiFiles = await discoverWikiFiles(cwd);
2170
- for (const wiki of wikiFiles) {
2171
- results.push({
2172
- absolutePath: wiki.absolutePath,
2173
- relPath: wiki.relPath,
2174
- source: "wiki"
2175
- });
2176
- }
2177
- const sessionFiles = await discoverSessionFiles(cwd);
2178
- for (const session of sessionFiles) {
2179
- results.push({
2180
- absolutePath: session.absolutePath,
2181
- relPath: session.relPath,
2182
- source: "sessions"
2183
- });
2184
- }
2185
- return results;
2186
- }
2187
1928
  function sha256(text) {
2188
1929
  return crypto.createHash("sha256").update(text).digest("hex");
2189
1930
  }
@@ -2191,30 +1932,14 @@ function truncateSnippet(text) {
2191
1932
  const max = 500;
2192
1933
  return text.length <= max ? text : `${text.slice(0, max)}\u2026`;
2193
1934
  }
2194
- async function readAllSqliteFacts(cwd) {
2195
- const dbPath = defaultIndexPath(cwd);
2196
- if (!fs.existsSync(dbPath)) return [];
2197
- const db = await openMemoryDb({ filePath: dbPath });
2198
- try {
2199
- const stmt = db.prepare("SELECT id, path, source, start_line, end_line, text FROM chunks");
2200
- const rows = stmt.all();
2201
- return rows.map((r) => ({
2202
- ...r,
2203
- namespace: "default",
2204
- scope: "agent",
2205
- user_id: "default"
2206
- }));
2207
- } finally {
2208
- db.close();
2209
- }
2210
- }
2211
1935
  function nfcEqual(a, b) {
2212
1936
  return a.normalize("NFC") === b.normalize("NFC");
2213
1937
  }
2214
1938
  async function migrateSqliteToLance(opts) {
2215
1939
  const cwd = opts.cwd;
2216
- const finalPath = lanceStoragePath(cwd);
2217
- const newPath = path.join(cwd, ".theokit", "memory", "lance-new");
1940
+ const memoryRoot = memoryStore.resolveMemoryRoot(cwd, { directory: opts.directory });
1941
+ const finalPath = memoryStore.lanceStoragePath(memoryRoot);
1942
+ const newPath = path.join(memoryRoot, "lance-new");
2218
1943
  const rawLog = opts.logger ?? ((m) => console.log(m));
2219
1944
  const log = (m) => rawLog(redactSecrets(m));
2220
1945
  if (fs.existsSync(finalPath)) {
@@ -2228,7 +1953,7 @@ async function migrateSqliteToLance(opts) {
2228
1953
  fs.rmSync(newPath, { recursive: true, force: true });
2229
1954
  }
2230
1955
  log(`Reading SQLite facts from ${cwd}/.theokit/memory/index.sqlite ...`);
2231
- const sqliteFacts = await readAllSqliteFacts(cwd);
1956
+ const sqliteFacts = await memoryStore.readAllSqliteFacts(memoryRoot);
2232
1957
  log(`SQLite has ${sqliteFacts.length} facts.`);
2233
1958
  if (sqliteFacts.length === 0) {
2234
1959
  return {
@@ -2349,7 +2074,7 @@ async function readLegacyFacts(jsonPath) {
2349
2074
  }
2350
2075
  async function writeMigratedFacts(cwd, jsonPath, facts) {
2351
2076
  try {
2352
- for (const fact of facts) await appendFactToMarkdown(cwd, fact);
2077
+ for (const fact of facts) await memoryStore.appendFactToMarkdown(cwd, fact);
2353
2078
  await promises.unlink(jsonPath).catch(() => void 0);
2354
2079
  process.stderr.write(
2355
2080
  `[theokit-sdk] migrated ${facts.length} fact(s) from ${jsonPath} to MEMORY.md
@@ -2372,7 +2097,7 @@ async function migrateLegacyJson(cwd, config) {
2372
2097
  if (!await fileExists(jsonPath)) {
2373
2098
  return { migrated: false, factCount: 0, reason: "no-legacy-json" };
2374
2099
  }
2375
- if (await fileExists(memoryMdPath(cwd))) {
2100
+ if (await fileExists(memoryStore.memoryMdPath(memoryStore.resolveMemoryRoot(cwd)))) {
2376
2101
  process.stderr.write(
2377
2102
  `[theokit-sdk] memory migration skipped: both MEMORY.md and legacy JSON exist at ${jsonPath}; leaving both intact
2378
2103
  `
@@ -2458,7 +2183,7 @@ function createMemorySearchTool(opts) {
2458
2183
  };
2459
2184
  }
2460
2185
  function createMemoryGetTool(opts) {
2461
- const memoryRoot = path.resolve(memoryDir(opts.cwd));
2186
+ const memoryRoot = path.resolve(opts.root);
2462
2187
  return {
2463
2188
  name: "memory_get",
2464
2189
  description: GET_DESCRIPTION,
@@ -2527,6 +2252,122 @@ function isPathInside(root, candidate) {
2527
2252
  return candidate === root || candidate.startsWith(normalizedRoot);
2528
2253
  }
2529
2254
 
2255
+ Object.defineProperty(exports, "MEMORY_INDEX_MAX_BYTES", {
2256
+ enumerable: true,
2257
+ get: function () { return memoryStore.MEMORY_INDEX_MAX_BYTES; }
2258
+ });
2259
+ Object.defineProperty(exports, "MEMORY_INDEX_MAX_LINES", {
2260
+ enumerable: true,
2261
+ get: function () { return memoryStore.MEMORY_INDEX_MAX_LINES; }
2262
+ });
2263
+ Object.defineProperty(exports, "appendDiaryEntry", {
2264
+ enumerable: true,
2265
+ get: function () { return memoryStore.appendDiaryEntry; }
2266
+ });
2267
+ Object.defineProperty(exports, "appendFact", {
2268
+ enumerable: true,
2269
+ get: function () { return memoryStore.appendFact; }
2270
+ });
2271
+ Object.defineProperty(exports, "appendFactToMarkdown", {
2272
+ enumerable: true,
2273
+ get: function () { return memoryStore.appendFactToMarkdown; }
2274
+ });
2275
+ Object.defineProperty(exports, "asMemoryRoot", {
2276
+ enumerable: true,
2277
+ get: function () { return memoryStore.asMemoryRoot; }
2278
+ });
2279
+ Object.defineProperty(exports, "claudeProjectMemoryDir", {
2280
+ enumerable: true,
2281
+ get: function () { return memoryStore.claudeProjectMemoryDir; }
2282
+ });
2283
+ Object.defineProperty(exports, "collectMarkdownFiles", {
2284
+ enumerable: true,
2285
+ get: function () { return memoryStore.collectMarkdownFiles; }
2286
+ });
2287
+ Object.defineProperty(exports, "defaultIndexPath", {
2288
+ enumerable: true,
2289
+ get: function () { return memoryStore.defaultIndexPath; }
2290
+ });
2291
+ Object.defineProperty(exports, "diaryPath", {
2292
+ enumerable: true,
2293
+ get: function () { return memoryStore.diaryPath; }
2294
+ });
2295
+ Object.defineProperty(exports, "discoverSessionFiles", {
2296
+ enumerable: true,
2297
+ get: function () { return memoryStore.discoverSessionFiles; }
2298
+ });
2299
+ Object.defineProperty(exports, "discoverWikiFiles", {
2300
+ enumerable: true,
2301
+ get: function () { return memoryStore.discoverWikiFiles; }
2302
+ });
2303
+ Object.defineProperty(exports, "entryHash", {
2304
+ enumerable: true,
2305
+ get: function () { return memoryStore.entryHash; }
2306
+ });
2307
+ Object.defineProperty(exports, "indexBudgetWarning", {
2308
+ enumerable: true,
2309
+ get: function () { return memoryStore.indexBudgetWarning; }
2310
+ });
2311
+ Object.defineProperty(exports, "lanceStoragePath", {
2312
+ enumerable: true,
2313
+ get: function () { return memoryStore.lanceStoragePath; }
2314
+ });
2315
+ Object.defineProperty(exports, "memoryMdPath", {
2316
+ enumerable: true,
2317
+ get: function () { return memoryStore.memoryMdPath; }
2318
+ });
2319
+ Object.defineProperty(exports, "memoryReadRoots", {
2320
+ enumerable: true,
2321
+ get: function () { return memoryStore.memoryReadRoots; }
2322
+ });
2323
+ Object.defineProperty(exports, "notesDir", {
2324
+ enumerable: true,
2325
+ get: function () { return memoryStore.notesDir; }
2326
+ });
2327
+ Object.defineProperty(exports, "persistActiveMemoryTranscript", {
2328
+ enumerable: true,
2329
+ get: function () { return memoryStore.persistActiveMemoryTranscript; }
2330
+ });
2331
+ Object.defineProperty(exports, "projectMemoryDir", {
2332
+ enumerable: true,
2333
+ get: function () { return memoryStore.projectMemoryDir; }
2334
+ });
2335
+ Object.defineProperty(exports, "readAllSqliteFacts", {
2336
+ enumerable: true,
2337
+ get: function () { return memoryStore.readAllSqliteFacts; }
2338
+ });
2339
+ Object.defineProperty(exports, "readFacts", {
2340
+ enumerable: true,
2341
+ get: function () { return memoryStore.readFacts; }
2342
+ });
2343
+ Object.defineProperty(exports, "readFactsFromMarkdown", {
2344
+ enumerable: true,
2345
+ get: function () { return memoryStore.readFactsFromMarkdown; }
2346
+ });
2347
+ Object.defineProperty(exports, "renderDiaryEntry", {
2348
+ enumerable: true,
2349
+ get: function () { return memoryStore.renderDiaryEntry; }
2350
+ });
2351
+ Object.defineProperty(exports, "resolveMemoryRoot", {
2352
+ enumerable: true,
2353
+ get: function () { return memoryStore.resolveMemoryRoot; }
2354
+ });
2355
+ Object.defineProperty(exports, "sessionSummaryPath", {
2356
+ enumerable: true,
2357
+ get: function () { return memoryStore.sessionSummaryPath; }
2358
+ });
2359
+ Object.defineProperty(exports, "sessionsDir", {
2360
+ enumerable: true,
2361
+ get: function () { return memoryStore.sessionsDir; }
2362
+ });
2363
+ Object.defineProperty(exports, "wikiDir", {
2364
+ enumerable: true,
2365
+ get: function () { return memoryStore.wikiDir; }
2366
+ });
2367
+ Object.defineProperty(exports, "writeSessionSummary", {
2368
+ enumerable: true,
2369
+ get: function () { return memoryStore.writeSessionSummary; }
2370
+ });
2530
2371
  Object.defineProperty(exports, "createOpenAiCompatibleRuntime", {
2531
2372
  enumerable: true,
2532
2373
  get: function () { return memoryAdapters.createOpenAiCompatibleRuntime; }
@@ -2554,9 +2395,6 @@ exports.META_KEY_PROVIDER_ID = META_KEY_PROVIDER_ID;
2554
2395
  exports.PRAGMA_STATEMENTS = PRAGMA_STATEMENTS;
2555
2396
  exports.SCHEMA_STATEMENTS = SCHEMA_STATEMENTS;
2556
2397
  exports.VALID_BACKENDS = VALID_BACKENDS;
2557
- exports.appendDiaryEntry = appendDiaryEntry;
2558
- exports.appendFact = appendFact;
2559
- exports.appendFactToMarkdown = appendFactToMarkdown;
2560
2398
  exports.assertValidBackend = assertValidBackend;
2561
2399
  exports.azureOpenAiMemoryEmbeddingProviderAdapter = azureOpenAiMemoryEmbeddingProviderAdapter;
2562
2400
  exports.buildErrorMetadata = buildErrorMetadata;
@@ -2569,30 +2407,21 @@ exports.createMemorySearchTool = createMemorySearchTool;
2569
2407
  exports.createVectorIndex = createVectorIndex;
2570
2408
  exports.deepPhase = deepPhase;
2571
2409
  exports.deepinfraMemoryEmbeddingProviderAdapter = deepinfraMemoryEmbeddingProviderAdapter;
2572
- exports.defaultIndexPath = defaultIndexPath;
2573
- exports.diaryPath = diaryPath;
2574
- exports.discoverSessionFiles = discoverSessionFiles;
2575
- exports.discoverWikiFiles = discoverWikiFiles;
2576
2410
  exports.dropVectorIndex = dropVectorIndex;
2577
2411
  exports.embedMissingChunks = embedMissingChunks;
2578
- exports.entryHash = entryHash;
2579
2412
  exports.geminiMemoryEmbeddingProviderAdapter = geminiMemoryEmbeddingProviderAdapter;
2580
2413
  exports.identityMatches = identityMatches;
2581
2414
  exports.isLanceAvailable = isLanceAvailable;
2582
2415
  exports.isSqliteVecLoaded = isSqliteVecLoaded;
2583
2416
  exports.jinaMemoryEmbeddingProviderAdapter = jinaMemoryEmbeddingProviderAdapter;
2584
- exports.lanceStoragePath = lanceStoragePath;
2585
2417
  exports.legacyMemoryJsonPath = legacyMemoryJsonPath;
2586
2418
  exports.lightPhase = lightPhase;
2587
2419
  exports.listNotes = listNotes;
2588
2420
  exports.loadSqliteVecExtension = loadSqliteVecExtension;
2589
2421
  exports.mapOpenAICompatibleError = mapOpenAICompatibleError;
2590
- exports.memoryDir = memoryDir;
2591
- exports.memoryMdPath = memoryMdPath;
2592
2422
  exports.migrateLegacyJson = migrateLegacyJson;
2593
2423
  exports.migrateSqliteToLance = migrateSqliteToLance;
2594
2424
  exports.mistralMemoryEmbeddingProviderAdapter = mistralMemoryEmbeddingProviderAdapter;
2595
- exports.notesDir = notesDir;
2596
2425
  exports.ollamaMemoryEmbeddingProviderAdapter = ollamaMemoryEmbeddingProviderAdapter;
2597
2426
  exports.openAiMemoryEmbeddingProviderAdapter = openAiMemoryEmbeddingProviderAdapter;
2598
2427
  exports.openLanceIndex = openLanceIndex;
@@ -2601,25 +2430,17 @@ exports.openRouterMemoryEmbeddingProviderAdapter = openRouterMemoryEmbeddingProv
2601
2430
  exports.packVector = packVector;
2602
2431
  exports.parseRetryAfter = parseRetryAfter;
2603
2432
  exports.parseSearchOptions = parseSearchOptions;
2604
- exports.persistActiveMemoryTranscript = persistActiveMemoryTranscript;
2605
2433
  exports.readEmbeddingIdentity = readEmbeddingIdentity;
2606
- exports.readFacts = readFacts;
2607
- exports.readFactsFromMarkdown = readFactsFromMarkdown;
2608
2434
  exports.readMemoryFileBounded = readMemoryFileBounded;
2609
2435
  exports.redactSecrets = redactSecrets;
2610
2436
  exports.remPhase = remPhase;
2611
- exports.renderDiaryEntry = renderDiaryEntry;
2612
2437
  exports.resetMigrationStateForTests = resetMigrationStateForTests;
2613
2438
  exports.runActiveMemory = runActiveMemory;
2614
2439
  exports.runDreamingSweep = runDreamingSweep;
2615
- exports.sessionSummaryPath = sessionSummaryPath;
2616
- exports.sessionsDir = sessionsDir;
2617
2440
  exports.truncateRaw = truncateRaw;
2618
2441
  exports.upsertEmbedding = upsertEmbedding;
2619
2442
  exports.vectorSearch = vectorSearch;
2620
2443
  exports.voyageMemoryEmbeddingProviderAdapter = voyageMemoryEmbeddingProviderAdapter;
2621
- exports.wikiDir = wikiDir;
2622
2444
  exports.writeEmbeddingIdentity = writeEmbeddingIdentity;
2623
- exports.writeSessionSummary = writeSessionSummary;
2624
2445
  //# sourceMappingURL=index.cjs.map
2625
2446
  //# sourceMappingURL=index.cjs.map