minimem 0.0.5 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/index.js CHANGED
@@ -4,18 +4,28 @@
4
4
  import { program } from "commander";
5
5
 
6
6
  // src/cli/commands/init.ts
7
- import fs2 from "fs/promises";
7
+ import fs3 from "fs/promises";
8
8
  import path3 from "path";
9
9
 
10
10
  // src/cli/config.ts
11
- import fs from "fs/promises";
11
+ import fs2 from "fs/promises";
12
+ import fsSync from "fs";
12
13
  import path2 from "path";
13
14
  import os2 from "os";
14
15
  import crypto from "crypto";
15
16
 
16
17
  // src/cli/shared.ts
18
+ import * as fs from "fs";
17
19
  import * as path from "path";
18
20
  import * as os from "os";
21
+ function discoverMemoryDir(base) {
22
+ if (fs.existsSync(path.join(base, "MEMORY.md"))) return base;
23
+ const swarmDir = path.join(base, ".swarm", "minimem");
24
+ if (fs.existsSync(path.join(swarmDir, "config.json"))) return swarmDir;
25
+ const minimemDir = path.join(base, ".minimem");
26
+ if (fs.existsSync(path.join(minimemDir, "config.json"))) return minimemDir;
27
+ return base;
28
+ }
19
29
  function resolveMemoryDir(options) {
20
30
  const dir = Array.isArray(options.dir) ? options.dir[0] : options.dir;
21
31
  if (dir) {
@@ -28,7 +38,7 @@ function resolveMemoryDir(options) {
28
38
  if (options.global) {
29
39
  return path.join(os.homedir(), ".minimem");
30
40
  }
31
- return process.cwd();
41
+ return discoverMemoryDir(process.cwd());
32
42
  }
33
43
  function resolveMemoryDirs(options) {
34
44
  const dirs = [];
@@ -46,7 +56,7 @@ function resolveMemoryDirs(options) {
46
56
  }
47
57
  }
48
58
  if (dirs.length === 0) {
49
- dirs.push(process.cwd());
59
+ dirs.push(discoverMemoryDir(process.cwd()));
50
60
  }
51
61
  return [...new Set(dirs)];
52
62
  }
@@ -90,8 +100,16 @@ function getGlobalDir() {
90
100
  function getGlobalConfigPath() {
91
101
  return path2.join(getGlobalDir(), CONFIG_DIR, CONFIG_FILENAME);
92
102
  }
103
+ function resolveConfigSubdir(memoryDir) {
104
+ const envDir = process.env.MINIMEM_CONFIG_DIR;
105
+ if (envDir) return envDir;
106
+ if (fsSync.existsSync(path2.join(memoryDir, CONFIG_FILENAME))) return ".";
107
+ const swarmDir = path2.join(memoryDir, ".swarm", "minimem");
108
+ if (fsSync.existsSync(path2.join(swarmDir, CONFIG_FILENAME))) return path2.join(".swarm", "minimem");
109
+ return CONFIG_DIR;
110
+ }
93
111
  function getConfigPath(memoryDir) {
94
- return path2.join(memoryDir, CONFIG_DIR, CONFIG_FILENAME);
112
+ return path2.join(memoryDir, resolveConfigSubdir(memoryDir), CONFIG_FILENAME);
95
113
  }
96
114
  function getXdgConfigDir() {
97
115
  return path2.join(os2.homedir(), XDG_CONFIG_DIR);
@@ -110,7 +128,7 @@ function expandPath(filePath) {
110
128
  }
111
129
  async function loadXdgConfig() {
112
130
  try {
113
- const content = await fs.readFile(getXdgConfigPath(), "utf-8");
131
+ const content = await fs2.readFile(getXdgConfigPath(), "utf-8");
114
132
  return JSON.parse(content);
115
133
  } catch {
116
134
  return {};
@@ -119,8 +137,8 @@ async function loadXdgConfig() {
119
137
  async function saveXdgConfig(config2) {
120
138
  const configDir = getXdgConfigDir();
121
139
  const configPath = getXdgConfigPath();
122
- await fs.mkdir(configDir, { recursive: true });
123
- await fs.writeFile(configPath, JSON.stringify(config2, null, 2), "utf-8");
140
+ await fs2.mkdir(configDir, { recursive: true });
141
+ await fs2.writeFile(configPath, JSON.stringify(config2, null, 2), "utf-8");
124
142
  }
125
143
  async function getMachineId() {
126
144
  const globalConfig = await loadXdgConfig();
@@ -135,7 +153,7 @@ async function getMachineId() {
135
153
  }
136
154
  async function loadConfigFile(configPath) {
137
155
  try {
138
- const content = await fs.readFile(configPath, "utf-8");
156
+ const content = await fs2.readFile(configPath, "utf-8");
139
157
  return JSON.parse(content);
140
158
  } catch {
141
159
  return {};
@@ -189,10 +207,10 @@ function deepMergeConfig(target, source) {
189
207
  return result;
190
208
  }
191
209
  async function saveConfig(memoryDir, config2) {
192
- const configDir = path2.join(memoryDir, CONFIG_DIR);
193
210
  const configPath = getConfigPath(memoryDir);
194
- await fs.mkdir(configDir, { recursive: true });
195
- await fs.writeFile(configPath, JSON.stringify(config2, null, 2), "utf-8");
211
+ const configDir = path2.dirname(configPath);
212
+ await fs2.mkdir(configDir, { recursive: true });
213
+ await fs2.writeFile(configPath, JSON.stringify(config2, null, 2), "utf-8");
196
214
  }
197
215
  function getDefaultConfig() {
198
216
  return {
@@ -309,7 +327,7 @@ function buildMinimemConfig(memoryDir, cliConfig, options) {
309
327
  async function isInitialized(memoryDir) {
310
328
  const configPath = getConfigPath(memoryDir);
311
329
  try {
312
- await fs.access(configPath);
330
+ await fs2.access(configPath);
313
331
  return true;
314
332
  } catch {
315
333
  return false;
@@ -346,23 +364,23 @@ async function init(dir, options) {
346
364
  return;
347
365
  }
348
366
  console.log(`Initializing minimem in ${displayPath}...`);
349
- await fs2.mkdir(memoryDir, { recursive: true });
350
- await fs2.mkdir(path3.join(memoryDir, "memory"), { recursive: true });
351
- await fs2.mkdir(path3.join(memoryDir, ".minimem"), { recursive: true });
367
+ await fs3.mkdir(memoryDir, { recursive: true });
368
+ await fs3.mkdir(path3.join(memoryDir, "memory"), { recursive: true });
352
369
  const memoryFilePath = path3.join(memoryDir, "MEMORY.md");
353
370
  try {
354
- await fs2.access(memoryFilePath);
371
+ await fs3.access(memoryFilePath);
355
372
  console.log(" MEMORY.md already exists, skipping");
356
373
  } catch {
357
- await fs2.writeFile(memoryFilePath, MEMORY_TEMPLATE, "utf-8");
374
+ await fs3.writeFile(memoryFilePath, MEMORY_TEMPLATE, "utf-8");
358
375
  console.log(" Created MEMORY.md");
359
376
  }
360
377
  const config2 = getInitConfig();
361
- await saveConfig(memoryDir, config2);
362
- console.log(" Created .minimem/config.json");
363
- const gitignorePath = path3.join(memoryDir, ".minimem", ".gitignore");
364
- await fs2.writeFile(gitignorePath, "index.db\nindex.db-*\n", "utf-8");
365
- console.log(" Created .minimem/.gitignore");
378
+ const configPath = path3.join(memoryDir, "config.json");
379
+ await fs3.writeFile(configPath, JSON.stringify(config2, null, 2), "utf-8");
380
+ console.log(" Created config.json");
381
+ const gitignorePath = path3.join(memoryDir, ".gitignore");
382
+ await fs3.writeFile(gitignorePath, "index.db\nindex.db-*\n", "utf-8");
383
+ console.log(" Created .gitignore");
366
384
  console.log();
367
385
  console.log("Done! Your memory directory is ready.");
368
386
  console.log();
@@ -379,15 +397,16 @@ async function init(dir, options) {
379
397
 
380
398
  // src/minimem.ts
381
399
  import { randomUUID } from "crypto";
382
- import fs4 from "fs/promises";
400
+ import fs5 from "fs/promises";
401
+ import fsSync4 from "fs";
383
402
  import path6 from "path";
384
403
  import { DatabaseSync } from "node:sqlite";
385
404
  import chokidar from "chokidar";
386
405
 
387
406
  // src/internal.ts
388
407
  import crypto2 from "crypto";
389
- import fsSync from "fs";
390
- import fs3 from "fs/promises";
408
+ import fsSync2 from "fs";
409
+ import fs4 from "fs/promises";
391
410
  import path4 from "path";
392
411
  function logError2(context, error, debug) {
393
412
  if (!debug) return;
@@ -396,7 +415,7 @@ function logError2(context, error, debug) {
396
415
  }
397
416
  function ensureDir(dir, debug) {
398
417
  try {
399
- fsSync.mkdirSync(dir, { recursive: true });
418
+ fsSync2.mkdirSync(dir, { recursive: true });
400
419
  } catch (error) {
401
420
  const nodeError = error;
402
421
  if (nodeError.code !== "EEXIST") {
@@ -407,14 +426,14 @@ function ensureDir(dir, debug) {
407
426
  }
408
427
  async function exists(filePath) {
409
428
  try {
410
- await fs3.access(filePath);
429
+ await fs4.access(filePath);
411
430
  return true;
412
431
  } catch {
413
432
  return false;
414
433
  }
415
434
  }
416
435
  async function walkDir(dir, files) {
417
- const entries = await fs3.readdir(dir, { withFileTypes: true });
436
+ const entries = await fs4.readdir(dir, { withFileTypes: true });
418
437
  for (const entry of entries) {
419
438
  const full = path4.join(dir, entry.name);
420
439
  if (entry.isDirectory()) {
@@ -436,11 +455,11 @@ async function listMemoryFiles(memoryDir) {
436
455
  let upperReal = memoryFile;
437
456
  let lowerReal = altMemoryFile;
438
457
  try {
439
- upperReal = await fs3.realpath(memoryFile);
458
+ upperReal = await fs4.realpath(memoryFile);
440
459
  } catch {
441
460
  }
442
461
  try {
443
- lowerReal = await fs3.realpath(altMemoryFile);
462
+ lowerReal = await fs4.realpath(altMemoryFile);
444
463
  } catch {
445
464
  }
446
465
  if (upperReal !== lowerReal) {
@@ -464,7 +483,7 @@ async function listMemoryFiles(memoryDir) {
464
483
  for (const entry of result) {
465
484
  let key = entry;
466
485
  try {
467
- key = await fs3.realpath(entry);
486
+ key = await fs4.realpath(entry);
468
487
  } catch {
469
488
  }
470
489
  if (seen.has(key)) continue;
@@ -477,8 +496,8 @@ function hashText(value) {
477
496
  return crypto2.createHash("sha256").update(value).digest("hex");
478
497
  }
479
498
  async function buildFileEntry(absPath, memoryDir) {
480
- const stat = await fs3.stat(absPath);
481
- const content = await fs3.readFile(absPath, "utf-8");
499
+ const stat = await fs4.stat(absPath);
500
+ const content = await fs4.readFile(absPath, "utf-8");
482
501
  const hash = hashText(content);
483
502
  return {
484
503
  path: path4.relative(memoryDir, absPath).replace(/\\/g, "/"),
@@ -1298,7 +1317,7 @@ async function loadSqliteVecExtension(params) {
1298
1317
  }
1299
1318
 
1300
1319
  // src/embeddings/embeddings.ts
1301
- import fsSync2 from "fs";
1320
+ import fsSync3 from "fs";
1302
1321
  import path5 from "path";
1303
1322
  import os4 from "os";
1304
1323
  var DEFAULT_LOCAL_MODEL = "hf:ggml-org/embeddinggemma-300M-GGUF/embeddinggemma-300M-Q8_0.gguf";
@@ -1326,7 +1345,7 @@ function canAutoSelectLocal(options) {
1326
1345
  if (/^(hf:|https?:)/i.test(modelPath)) return false;
1327
1346
  const resolved = resolveUserPath(modelPath);
1328
1347
  try {
1329
- return fsSync2.statSync(resolved).isFile();
1348
+ return fsSync3.statSync(resolved).isFile();
1330
1349
  } catch {
1331
1350
  return false;
1332
1351
  }
@@ -2202,6 +2221,14 @@ async function runGeminiEmbeddingBatches(params) {
2202
2221
  }
2203
2222
 
2204
2223
  // src/minimem.ts
2224
+ function resolveMinimemSubdir(memoryDir) {
2225
+ const envDir = process.env.MINIMEM_CONFIG_DIR;
2226
+ if (envDir) return envDir;
2227
+ if (fsSync4.existsSync(path6.join(memoryDir, "config.json"))) return ".";
2228
+ const swarmDir = path6.join(memoryDir, ".swarm", "minimem");
2229
+ if (fsSync4.existsSync(path6.join(swarmDir, "config.json"))) return path6.join(".swarm", "minimem");
2230
+ return ".minimem";
2231
+ }
2205
2232
  var META_KEY = "memory_index_meta_v1";
2206
2233
  var SNIPPET_MAX_CHARS = 700;
2207
2234
  var VECTOR_TABLE = "chunks_vec";
@@ -2241,7 +2268,7 @@ var Minimem = class _Minimem {
2241
2268
  embeddingOptions;
2242
2269
  constructor(config2) {
2243
2270
  this.memoryDir = path6.resolve(config2.memoryDir);
2244
- this.dbPath = config2.dbPath ?? path6.join(this.memoryDir, ".minimem", "index.db");
2271
+ this.dbPath = config2.dbPath ?? path6.join(this.memoryDir, resolveMinimemSubdir(this.memoryDir), "index.db");
2245
2272
  this.chunking = {
2246
2273
  tokens: config2.chunking?.tokens ?? 256,
2247
2274
  overlap: config2.chunking?.overlap ?? 32
@@ -2387,7 +2414,7 @@ var Minimem = class _Minimem {
2387
2414
  this.debug?.(`Stale: new file ${relPath}`);
2388
2415
  return true;
2389
2416
  }
2390
- const stat = await fs4.stat(absPath);
2417
+ const stat = await fs5.stat(absPath);
2391
2418
  const currentMtime = Math.floor(stat.mtimeMs);
2392
2419
  if (currentMtime !== storedMtime) {
2393
2420
  this.debug?.(`Stale: mtime changed for ${relPath}`);
@@ -2555,7 +2582,7 @@ var Minimem = class _Minimem {
2555
2582
  this.debug?.(`memory sync complete`, { files: files.length });
2556
2583
  }
2557
2584
  async indexFile(entry) {
2558
- const content = await fs4.readFile(entry.absPath, "utf-8");
2585
+ const content = await fs5.readFile(entry.absPath, "utf-8");
2559
2586
  const chunks = chunkMarkdown(content, this.chunking);
2560
2587
  const { frontmatter } = parseFrontmatter(content);
2561
2588
  const knowledgeType = frontmatter?.type ?? null;
@@ -2859,7 +2886,7 @@ var Minimem = class _Minimem {
2859
2886
  async readFile(relativePath) {
2860
2887
  const absPath = path6.join(this.memoryDir, relativePath);
2861
2888
  try {
2862
- return await fs4.readFile(absPath, "utf-8");
2889
+ return await fs5.readFile(absPath, "utf-8");
2863
2890
  } catch {
2864
2891
  return null;
2865
2892
  }
@@ -2889,8 +2916,8 @@ var Minimem = class _Minimem {
2889
2916
  this.validateMemoryPath(relativePath);
2890
2917
  const absPath = path6.join(this.memoryDir, relativePath);
2891
2918
  const dir = path6.dirname(absPath);
2892
- await fs4.mkdir(dir, { recursive: true });
2893
- await fs4.writeFile(absPath, content, "utf-8");
2919
+ await fs5.mkdir(dir, { recursive: true });
2920
+ await fs5.writeFile(absPath, content, "utf-8");
2894
2921
  this.dirty = true;
2895
2922
  this.debug?.(`memory write: ${relativePath}`);
2896
2923
  }
@@ -2901,16 +2928,16 @@ var Minimem = class _Minimem {
2901
2928
  this.validateMemoryPath(relativePath);
2902
2929
  const absPath = path6.join(this.memoryDir, relativePath);
2903
2930
  const dir = path6.dirname(absPath);
2904
- await fs4.mkdir(dir, { recursive: true });
2931
+ await fs5.mkdir(dir, { recursive: true });
2905
2932
  let toAppend = content;
2906
2933
  try {
2907
- const existing = await fs4.readFile(absPath, "utf-8");
2934
+ const existing = await fs5.readFile(absPath, "utf-8");
2908
2935
  if (existing.length > 0 && !existing.endsWith("\n")) {
2909
2936
  toAppend = "\n" + content;
2910
2937
  }
2911
2938
  } catch {
2912
2939
  }
2913
- await fs4.appendFile(absPath, toAppend, "utf-8");
2940
+ await fs5.appendFile(absPath, toAppend, "utf-8");
2914
2941
  this.dirty = true;
2915
2942
  this.debug?.(`memory append: ${relativePath}`);
2916
2943
  }
@@ -3277,7 +3304,7 @@ ${text}`;
3277
3304
  }
3278
3305
 
3279
3306
  // src/cli/commands/upsert.ts
3280
- import * as fs5 from "fs/promises";
3307
+ import * as fs6 from "fs/promises";
3281
3308
  import * as path7 from "path";
3282
3309
  async function upsert(file, content, options) {
3283
3310
  const memoryDir = resolveMemoryDir({ dir: options.dir, global: options.global });
@@ -3312,13 +3339,13 @@ async function upsert(file, content, options) {
3312
3339
  );
3313
3340
  }
3314
3341
  const parentDir = path7.dirname(filePath);
3315
- await fs5.mkdir(parentDir, { recursive: true });
3342
+ await fs6.mkdir(parentDir, { recursive: true });
3316
3343
  let isUpdate = false;
3317
3344
  let existingContent;
3318
3345
  try {
3319
- await fs5.access(filePath);
3346
+ await fs6.access(filePath);
3320
3347
  isUpdate = true;
3321
- existingContent = await fs5.readFile(filePath, "utf-8");
3348
+ existingContent = await fs6.readFile(filePath, "utf-8");
3322
3349
  } catch {
3323
3350
  }
3324
3351
  let contentToWrite = finalContent;
@@ -3346,7 +3373,7 @@ async function upsert(file, content, options) {
3346
3373
  });
3347
3374
  }
3348
3375
  }
3349
- await fs5.writeFile(filePath, contentToWrite, "utf-8");
3376
+ await fs6.writeFile(filePath, contentToWrite, "utf-8");
3350
3377
  const relativePath = path7.relative(memoryDir, filePath);
3351
3378
  const action = isUpdate ? "Updated" : "Created";
3352
3379
  console.log(`${action}: ${relativePath}`);
@@ -3386,7 +3413,7 @@ async function readStdin() {
3386
3413
  }
3387
3414
 
3388
3415
  // src/cli/commands/mcp.ts
3389
- import * as fs6 from "fs/promises";
3416
+ import * as fs7 from "fs/promises";
3390
3417
  import * as path8 from "path";
3391
3418
 
3392
3419
  // src/server/mcp.ts
@@ -4083,12 +4110,11 @@ async function mcp(options) {
4083
4110
  }
4084
4111
  async function ensureGlobalInitialized(globalDir) {
4085
4112
  console.error(`Auto-initializing global memory directory (~/.minimem)...`);
4086
- await fs6.mkdir(globalDir, { recursive: true });
4087
- await fs6.mkdir(path8.join(globalDir, "memory"), { recursive: true });
4088
- await fs6.mkdir(path8.join(globalDir, ".minimem"), { recursive: true });
4113
+ await fs7.mkdir(globalDir, { recursive: true });
4114
+ await fs7.mkdir(path8.join(globalDir, "memory"), { recursive: true });
4089
4115
  const memoryFilePath = path8.join(globalDir, "MEMORY.md");
4090
4116
  try {
4091
- await fs6.access(memoryFilePath);
4117
+ await fs7.access(memoryFilePath);
4092
4118
  } catch {
4093
4119
  const template = `# Global Memory
4094
4120
 
@@ -4099,12 +4125,13 @@ Notes stored here are available across all projects.
4099
4125
  ## Notes
4100
4126
 
4101
4127
  `;
4102
- await fs6.writeFile(memoryFilePath, template, "utf-8");
4128
+ await fs7.writeFile(memoryFilePath, template, "utf-8");
4103
4129
  }
4104
4130
  const config2 = getInitConfig();
4105
- await saveConfig(globalDir, config2);
4106
- const gitignorePath = path8.join(globalDir, ".minimem", ".gitignore");
4107
- await fs6.writeFile(gitignorePath, "index.db\nindex.db-*\n", "utf-8");
4131
+ const configPath = path8.join(globalDir, "config.json");
4132
+ await fs7.writeFile(configPath, JSON.stringify(config2, null, 2), "utf-8");
4133
+ const gitignorePath = path8.join(globalDir, ".gitignore");
4134
+ await fs7.writeFile(gitignorePath, "index.db\nindex.db-*\n", "utf-8");
4108
4135
  console.error(` Created ~/.minimem with default configuration.`);
4109
4136
  }
4110
4137
 
@@ -4250,9 +4277,9 @@ async function handleXdgConfigEdit(options) {
4250
4277
  }
4251
4278
  }
4252
4279
  async function loadConfigFile2(configPath) {
4253
- const fs18 = await import("fs/promises");
4280
+ const fs19 = await import("fs/promises");
4254
4281
  try {
4255
- const content = await fs18.readFile(configPath, "utf-8");
4282
+ const content = await fs19.readFile(configPath, "utf-8");
4256
4283
  return JSON.parse(content);
4257
4284
  } catch {
4258
4285
  return {};
@@ -4298,16 +4325,16 @@ function unsetConfigValue(config2, keyPath) {
4298
4325
  }
4299
4326
 
4300
4327
  // src/cli/commands/sync-init.ts
4301
- import fs10 from "fs/promises";
4328
+ import fs11 from "fs/promises";
4302
4329
  import path12 from "path";
4303
4330
 
4304
4331
  // src/cli/sync/central.ts
4305
- import fs9 from "fs/promises";
4332
+ import fs10 from "fs/promises";
4306
4333
  import path11 from "path";
4307
4334
  import { execSync } from "child_process";
4308
4335
 
4309
4336
  // src/cli/sync/registry.ts
4310
- import fs7 from "fs/promises";
4337
+ import fs8 from "fs/promises";
4311
4338
  import path9 from "path";
4312
4339
  import os5 from "os";
4313
4340
  import crypto3 from "crypto";
@@ -4324,7 +4351,7 @@ function createEmptyRegistry() {
4324
4351
  async function readRegistry(centralRepo) {
4325
4352
  const registryPath = getRegistryPath(centralRepo);
4326
4353
  try {
4327
- const content = await fs7.readFile(registryPath, "utf-8");
4354
+ const content = await fs8.readFile(registryPath, "utf-8");
4328
4355
  const registry = JSON.parse(content);
4329
4356
  if (!registry.mappings || !Array.isArray(registry.mappings)) {
4330
4357
  return createEmptyRegistry();
@@ -4338,8 +4365,8 @@ async function writeRegistry(centralRepo, registry) {
4338
4365
  const registryPath = getRegistryPath(centralRepo);
4339
4366
  const tempPath = `${registryPath}.${crypto3.randomBytes(4).toString("hex")}.tmp`;
4340
4367
  registry.version = registry.version || 1;
4341
- await fs7.writeFile(tempPath, JSON.stringify(registry, null, 2), "utf-8");
4342
- await fs7.rename(tempPath, registryPath);
4368
+ await fs8.writeFile(tempPath, JSON.stringify(registry, null, 2), "utf-8");
4369
+ await fs8.rename(tempPath, registryPath);
4343
4370
  }
4344
4371
  function normalizePath(filePath) {
4345
4372
  if (filePath.startsWith("~/")) {
@@ -4417,7 +4444,7 @@ function updateLastSync(registry, centralPath, machineId) {
4417
4444
  }
4418
4445
 
4419
4446
  // src/cli/sync/detection.ts
4420
- import fs8 from "fs/promises";
4447
+ import fs9 from "fs/promises";
4421
4448
  import path10 from "path";
4422
4449
  async function isInsideGitRepo(dir) {
4423
4450
  let current = path10.resolve(dir);
@@ -4425,7 +4452,7 @@ async function isInsideGitRepo(dir) {
4425
4452
  while (current !== root) {
4426
4453
  try {
4427
4454
  const gitPath = path10.join(current, ".git");
4428
- const stat = await fs8.stat(gitPath);
4455
+ const stat = await fs9.stat(gitPath);
4429
4456
  if (stat.isDirectory() || stat.isFile()) {
4430
4457
  return true;
4431
4458
  }
@@ -4438,7 +4465,7 @@ async function isInsideGitRepo(dir) {
4438
4465
  async function hasSyncConfig(dir) {
4439
4466
  const configPath = getConfigPath(dir);
4440
4467
  try {
4441
- const content = await fs8.readFile(configPath, "utf-8");
4468
+ const content = await fs9.readFile(configPath, "utf-8");
4442
4469
  const config2 = JSON.parse(content);
4443
4470
  return config2.sync?.enabled === true || typeof config2.sync?.path === "string";
4444
4471
  } catch {
@@ -4508,8 +4535,8 @@ minimem sync init --path <directory-name>/
4508
4535
  async function isWritable(dirPath) {
4509
4536
  try {
4510
4537
  const testFile = path11.join(dirPath, `.minimem-write-test-${Date.now()}`);
4511
- await fs9.writeFile(testFile, "test");
4512
- await fs9.unlink(testFile);
4538
+ await fs10.writeFile(testFile, "test");
4539
+ await fs10.unlink(testFile);
4513
4540
  return true;
4514
4541
  } catch {
4515
4542
  return false;
@@ -4539,7 +4566,7 @@ async function initCentralRepo(repoPath) {
4539
4566
  }
4540
4567
  let dirExists = false;
4541
4568
  try {
4542
- const stat = await fs9.stat(resolvedPath);
4569
+ const stat = await fs10.stat(resolvedPath);
4543
4570
  dirExists = stat.isDirectory();
4544
4571
  } catch {
4545
4572
  dirExists = false;
@@ -4547,7 +4574,7 @@ async function initCentralRepo(repoPath) {
4547
4574
  let created = false;
4548
4575
  if (!dirExists) {
4549
4576
  try {
4550
- await fs9.mkdir(resolvedPath, { recursive: true });
4577
+ await fs10.mkdir(resolvedPath, { recursive: true });
4551
4578
  created = true;
4552
4579
  } catch (error) {
4553
4580
  return {
@@ -4581,21 +4608,21 @@ async function initCentralRepo(repoPath) {
4581
4608
  }
4582
4609
  const gitignorePath = path11.join(resolvedPath, ".gitignore");
4583
4610
  try {
4584
- await fs9.access(gitignorePath);
4611
+ await fs10.access(gitignorePath);
4585
4612
  } catch {
4586
- await fs9.writeFile(gitignorePath, GITIGNORE_CONTENT, "utf-8");
4613
+ await fs10.writeFile(gitignorePath, GITIGNORE_CONTENT, "utf-8");
4587
4614
  }
4588
4615
  const registryPath = getRegistryPath(resolvedPath);
4589
4616
  try {
4590
- await fs9.access(registryPath);
4617
+ await fs10.access(registryPath);
4591
4618
  } catch {
4592
4619
  await writeRegistry(resolvedPath, createEmptyRegistry());
4593
4620
  }
4594
4621
  const readmePath = path11.join(resolvedPath, "README.md");
4595
4622
  try {
4596
- await fs9.access(readmePath);
4623
+ await fs10.access(readmePath);
4597
4624
  } catch {
4598
- await fs9.writeFile(readmePath, README_CONTENT, "utf-8");
4625
+ await fs10.writeFile(readmePath, README_CONTENT, "utf-8");
4599
4626
  }
4600
4627
  const globalConfig = await loadXdgConfig();
4601
4628
  globalConfig.centralRepo = repoPath;
@@ -4613,7 +4640,7 @@ async function validateCentralRepo(repoPath) {
4613
4640
  const warnings = [];
4614
4641
  const errors = [];
4615
4642
  try {
4616
- const stat = await fs9.stat(resolvedPath);
4643
+ const stat = await fs10.stat(resolvedPath);
4617
4644
  if (!stat.isDirectory()) {
4618
4645
  errors.push("Path is not a directory");
4619
4646
  return { valid: false, warnings, errors };
@@ -4628,7 +4655,7 @@ async function validateCentralRepo(repoPath) {
4628
4655
  }
4629
4656
  const registryPath = getRegistryPath(resolvedPath);
4630
4657
  try {
4631
- await fs9.access(registryPath);
4658
+ await fs10.access(registryPath);
4632
4659
  const registry = await readRegistry(resolvedPath);
4633
4660
  if (!registry.mappings) {
4634
4661
  warnings.push("Registry file is malformed");
@@ -4638,7 +4665,7 @@ async function validateCentralRepo(repoPath) {
4638
4665
  }
4639
4666
  const gitignorePath = path11.join(resolvedPath, ".gitignore");
4640
4667
  try {
4641
- const gitignore = await fs9.readFile(gitignorePath, "utf-8");
4668
+ const gitignore = await fs10.readFile(gitignorePath, "utf-8");
4642
4669
  if (!gitignore.includes("*.db")) {
4643
4670
  warnings.push(".gitignore does not exclude database files");
4644
4671
  }
@@ -4765,7 +4792,7 @@ async function syncInit(options) {
4765
4792
  console.log(" Registered mapping in central repository");
4766
4793
  const centralDir = path12.join(centralRepo, centralPath);
4767
4794
  try {
4768
- await fs10.mkdir(centralDir, { recursive: true });
4795
+ await fs11.mkdir(centralDir, { recursive: true });
4769
4796
  } catch {
4770
4797
  }
4771
4798
  console.log();
@@ -4842,19 +4869,19 @@ async function syncRemove(options) {
4842
4869
  }
4843
4870
 
4844
4871
  // src/cli/sync/operations.ts
4845
- import fs14 from "fs/promises";
4872
+ import fs15 from "fs/promises";
4846
4873
  import path16 from "path";
4847
4874
  import crypto5 from "crypto";
4848
4875
 
4849
4876
  // src/cli/sync/state.ts
4850
- import fs11 from "fs/promises";
4877
+ import fs12 from "fs/promises";
4851
4878
  import path13 from "path";
4852
4879
  import crypto4 from "crypto";
4853
4880
  import { minimatch } from "minimatch";
4854
4881
  var STATE_FILENAME = "sync-state.json";
4855
- var STATE_DIR = ".minimem";
4856
4882
  function getSyncStatePath(dir) {
4857
- return path13.join(dir, STATE_DIR, STATE_FILENAME);
4883
+ const subdir = resolveConfigSubdir(dir);
4884
+ return path13.join(dir, subdir, STATE_FILENAME);
4858
4885
  }
4859
4886
  function createEmptySyncState(centralPath) {
4860
4887
  return {
@@ -4868,7 +4895,7 @@ function createEmptySyncState(centralPath) {
4868
4895
  async function loadSyncState(dir, centralPath) {
4869
4896
  const statePath = getSyncStatePath(dir);
4870
4897
  try {
4871
- const content = await fs11.readFile(statePath, "utf-8");
4898
+ const content = await fs12.readFile(statePath, "utf-8");
4872
4899
  const state = JSON.parse(content);
4873
4900
  if (!state.files || typeof state.files !== "object") {
4874
4901
  return createEmptySyncState(centralPath);
@@ -4890,23 +4917,24 @@ async function saveSyncState(dir, state) {
4890
4917
  const statePath = getSyncStatePath(dir);
4891
4918
  const stateDir = path13.dirname(statePath);
4892
4919
  const tempPath = `${statePath}.${crypto4.randomBytes(4).toString("hex")}.tmp`;
4893
- await fs11.mkdir(stateDir, { recursive: true });
4920
+ await fs12.mkdir(stateDir, { recursive: true });
4894
4921
  state.version = state.version || 2;
4895
- await fs11.writeFile(tempPath, JSON.stringify(state, null, 2), "utf-8");
4896
- await fs11.rename(tempPath, statePath);
4922
+ await fs12.writeFile(tempPath, JSON.stringify(state, null, 2), "utf-8");
4923
+ await fs12.rename(tempPath, statePath);
4897
4924
  }
4898
4925
  async function computeFileHash(filePath) {
4899
- const content = await fs11.readFile(filePath);
4926
+ const content = await fs12.readFile(filePath);
4900
4927
  return crypto4.createHash("sha256").update(content).digest("hex");
4901
4928
  }
4902
4929
  async function listSyncableFiles(dir, include, exclude) {
4903
4930
  const files = [];
4904
4931
  async function walkDir2(currentDir, relativePath = "") {
4905
- const entries = await fs11.readdir(currentDir, { withFileTypes: true });
4932
+ const entries = await fs12.readdir(currentDir, { withFileTypes: true });
4906
4933
  for (const entry of entries) {
4907
4934
  const entryPath = path13.join(currentDir, entry.name);
4908
4935
  const relPath = relativePath ? `${relativePath}/${entry.name}` : entry.name;
4909
- if (entry.name === ".minimem") continue;
4936
+ if (entry.name === ".minimem" || entry.name === ".swarm") continue;
4937
+ if (entry.name === "index.db" || entry.name.startsWith("index.db-")) continue;
4910
4938
  if (entry.isDirectory()) {
4911
4939
  await walkDir2(entryPath, relPath);
4912
4940
  } else if (entry.isFile()) {
@@ -4933,7 +4961,7 @@ async function listSyncableFiles(dir, include, exclude) {
4933
4961
  }
4934
4962
  async function getFileHashInfo(filePath) {
4935
4963
  try {
4936
- const stat = await fs11.stat(filePath);
4964
+ const stat = await fs12.stat(filePath);
4937
4965
  const hash = await computeFileHash(filePath);
4938
4966
  return {
4939
4967
  exists: true,
@@ -4961,26 +4989,27 @@ function getFileSyncStatus(localHash, remoteHash) {
4961
4989
  }
4962
4990
 
4963
4991
  // src/cli/commands/conflicts.ts
4964
- import fs13 from "fs/promises";
4992
+ import fs14 from "fs/promises";
4965
4993
  import path15 from "path";
4966
4994
  import { spawn } from "child_process";
4967
4995
 
4968
4996
  // src/cli/sync/conflicts.ts
4969
- import fs12 from "fs/promises";
4997
+ import fs13 from "fs/promises";
4970
4998
  import path14 from "path";
4971
4999
  var CONFLICTS_DIR = "conflicts";
4972
5000
  function getConflictsDir(memoryDir) {
4973
- return path14.join(memoryDir, ".minimem", CONFLICTS_DIR);
5001
+ const subdir = resolveConfigSubdir(memoryDir);
5002
+ return path14.join(memoryDir, subdir, CONFLICTS_DIR);
4974
5003
  }
4975
5004
  async function listQuarantinedConflicts(memoryDir) {
4976
5005
  const conflictsDir = getConflictsDir(memoryDir);
4977
5006
  const conflicts = [];
4978
5007
  try {
4979
- const entries = await fs12.readdir(conflictsDir, { withFileTypes: true });
5008
+ const entries = await fs13.readdir(conflictsDir, { withFileTypes: true });
4980
5009
  for (const entry of entries) {
4981
5010
  if (entry.isDirectory()) {
4982
5011
  const dirPath = path14.join(conflictsDir, entry.name);
4983
- const files = await fs12.readdir(dirPath);
5012
+ const files = await fs13.readdir(dirPath);
4984
5013
  const uniqueFiles = /* @__PURE__ */ new Set();
4985
5014
  for (const file of files) {
4986
5015
  const baseName = file.replace(/\.(local|remote|base)$/, "");
@@ -5103,7 +5132,7 @@ async function resolveCommand(timestamp, options) {
5103
5132
  }
5104
5133
  const conflictDir = path15.join(getConflictsDir(memoryDir), timestamp);
5105
5134
  try {
5106
- await fs13.access(conflictDir);
5135
+ await fs14.access(conflictDir);
5107
5136
  } catch {
5108
5137
  exitWithError(
5109
5138
  `Conflict '${timestamp}' not found.`,
@@ -5111,7 +5140,7 @@ async function resolveCommand(timestamp, options) {
5111
5140
  );
5112
5141
  }
5113
5142
  try {
5114
- const files = await fs13.readdir(conflictDir);
5143
+ const files = await fs14.readdir(conflictDir);
5115
5144
  const fileGroups = /* @__PURE__ */ new Map();
5116
5145
  for (const file of files) {
5117
5146
  const match = file.match(/^(.+)\.(local|remote|base)$/);
@@ -5194,7 +5223,7 @@ async function cleanupCommand(options) {
5194
5223
  const conflictsDir = getConflictsDir(memoryDir);
5195
5224
  let entries = [];
5196
5225
  try {
5197
- entries = await fs13.readdir(conflictsDir);
5226
+ entries = await fs14.readdir(conflictsDir);
5198
5227
  } catch {
5199
5228
  console.log("No conflicts directory found.");
5200
5229
  return;
@@ -5213,7 +5242,7 @@ async function cleanupCommand(options) {
5213
5242
  if (options.dryRun) {
5214
5243
  console.log(` Would remove: ${entry}`);
5215
5244
  } else {
5216
- await fs13.rm(entryPath, { recursive: true, force: true });
5245
+ await fs14.rm(entryPath, { recursive: true, force: true });
5217
5246
  console.log(` Removed: ${entry}`);
5218
5247
  }
5219
5248
  cleaned++;
@@ -5236,15 +5265,16 @@ Removed ${cleaned} conflict(s), kept ${kept}`);
5236
5265
  var SYNC_LOG_FILE = "sync.log";
5237
5266
  var MAX_LOG_ENTRIES = 1e3;
5238
5267
  function getSyncLogPath(memoryDir) {
5239
- return path15.join(memoryDir, ".minimem", SYNC_LOG_FILE);
5268
+ const subdir = resolveConfigSubdir(memoryDir);
5269
+ return path15.join(memoryDir, subdir, SYNC_LOG_FILE);
5240
5270
  }
5241
5271
  async function appendSyncLog(memoryDir, entry) {
5242
5272
  const logPath = getSyncLogPath(memoryDir);
5243
5273
  try {
5244
- await fs13.mkdir(path15.dirname(logPath), { recursive: true });
5274
+ await fs14.mkdir(path15.dirname(logPath), { recursive: true });
5245
5275
  let entries = [];
5246
5276
  try {
5247
- const content2 = await fs13.readFile(logPath, "utf-8");
5277
+ const content2 = await fs14.readFile(logPath, "utf-8");
5248
5278
  entries = content2.split("\n").filter(Boolean).map((line) => JSON.parse(line));
5249
5279
  } catch {
5250
5280
  }
@@ -5253,7 +5283,7 @@ async function appendSyncLog(memoryDir, entry) {
5253
5283
  entries = entries.slice(-MAX_LOG_ENTRIES);
5254
5284
  }
5255
5285
  const content = entries.map((e) => JSON.stringify(e)).join("\n") + "\n";
5256
- await fs13.writeFile(logPath, content);
5286
+ await fs14.writeFile(logPath, content);
5257
5287
  } catch (error) {
5258
5288
  const message = error instanceof Error ? error.message : String(error);
5259
5289
  warn(`Failed to write sync log: ${message}`);
@@ -5262,7 +5292,7 @@ async function appendSyncLog(memoryDir, entry) {
5262
5292
  async function readSyncLog(memoryDir) {
5263
5293
  const logPath = getSyncLogPath(memoryDir);
5264
5294
  try {
5265
- const content = await fs13.readFile(logPath, "utf-8");
5295
+ const content = await fs14.readFile(logPath, "utf-8");
5266
5296
  return content.split("\n").filter(Boolean).map((line) => JSON.parse(line));
5267
5297
  } catch {
5268
5298
  return [];
@@ -5312,18 +5342,18 @@ async function logCommand(options) {
5312
5342
 
5313
5343
  // src/cli/sync/operations.ts
5314
5344
  async function ensureDir2(dirPath) {
5315
- await fs14.mkdir(dirPath, { recursive: true });
5345
+ await fs15.mkdir(dirPath, { recursive: true });
5316
5346
  }
5317
5347
  async function copyFileAtomic(src, dest) {
5318
5348
  const destDir = path16.dirname(dest);
5319
5349
  await ensureDir2(destDir);
5320
5350
  const tempDest = `${dest}.${crypto5.randomBytes(4).toString("hex")}.tmp`;
5321
5351
  try {
5322
- await fs14.copyFile(src, tempDest);
5323
- await fs14.rename(tempDest, dest);
5352
+ await fs15.copyFile(src, tempDest);
5353
+ await fs15.rename(tempDest, dest);
5324
5354
  } catch (error) {
5325
5355
  try {
5326
- await fs14.unlink(tempDest);
5356
+ await fs15.unlink(tempDest);
5327
5357
  } catch {
5328
5358
  }
5329
5359
  throw error;
@@ -5696,10 +5726,10 @@ async function syncStatusCommand(options) {
5696
5726
  }
5697
5727
 
5698
5728
  // src/cli/commands/daemon.ts
5699
- import fs17 from "fs/promises";
5729
+ import fs18 from "fs/promises";
5700
5730
 
5701
5731
  // src/cli/sync/daemon.ts
5702
- import fs16 from "fs/promises";
5732
+ import fs17 from "fs/promises";
5703
5733
  import path19 from "path";
5704
5734
  import os6 from "os";
5705
5735
 
@@ -5710,7 +5740,7 @@ import { EventEmitter } from "events";
5710
5740
  var DEFAULT_DEBOUNCE_MS = 2e3;
5711
5741
  var DEFAULT_POLL_INTERVAL = 1e3;
5712
5742
  var DEFAULT_INCLUDE = ["MEMORY.md", "memory/**/*.md"];
5713
- var DEFAULT_EXCLUDE = [".minimem/**", "node_modules/**", ".git/**"];
5743
+ var DEFAULT_EXCLUDE = [".minimem/**", "index.db", "index.db-*", "node_modules/**", ".git/**"];
5714
5744
  function createFileWatcher(memoryDir, options = {}) {
5715
5745
  const debounceMs = options.debounceMs ?? DEFAULT_DEBOUNCE_MS;
5716
5746
  const include = options.include ?? DEFAULT_INCLUDE;
@@ -5736,7 +5766,10 @@ function createFileWatcher(memoryDir, options = {}) {
5736
5766
  };
5737
5767
  const handleEvent = (event, filePath) => {
5738
5768
  const relativePath = path17.relative(memoryDir, filePath);
5739
- if (relativePath.startsWith(".minimem")) {
5769
+ if (relativePath.startsWith(".minimem") || relativePath.startsWith(".swarm")) {
5770
+ return;
5771
+ }
5772
+ if (relativePath === "index.db" || relativePath.startsWith("index.db-")) {
5740
5773
  return;
5741
5774
  }
5742
5775
  const isIncluded = include.some((pattern) => {
@@ -5808,7 +5841,7 @@ function createFileWatcher(memoryDir, options = {}) {
5808
5841
  }
5809
5842
 
5810
5843
  // src/cli/sync/validation.ts
5811
- import fs15 from "fs/promises";
5844
+ import fs16 from "fs/promises";
5812
5845
  import path18 from "path";
5813
5846
  var STALE_THRESHOLD_DAYS = 30;
5814
5847
  async function validateRegistry() {
@@ -5893,7 +5926,7 @@ async function validateRegistry() {
5893
5926
  if (mapping.machineId === currentMachineId) {
5894
5927
  const localPath = expandPath3(mapping.localPath);
5895
5928
  try {
5896
- await fs15.access(localPath);
5929
+ await fs16.access(localPath);
5897
5930
  } catch {
5898
5931
  result.issues.push({
5899
5932
  type: "missing",
@@ -5962,7 +5995,7 @@ function getDaemonLogPath() {
5962
5995
  async function isDaemonRunning() {
5963
5996
  const pidFile = getPidFilePath();
5964
5997
  try {
5965
- const content = await fs16.readFile(pidFile, "utf-8");
5998
+ const content = await fs17.readFile(pidFile, "utf-8");
5966
5999
  const pid = parseInt(content.trim(), 10);
5967
6000
  if (isNaN(pid)) {
5968
6001
  return false;
@@ -5971,7 +6004,7 @@ async function isDaemonRunning() {
5971
6004
  process.kill(pid, 0);
5972
6005
  return true;
5973
6006
  } catch {
5974
- await fs16.unlink(pidFile).catch(() => {
6007
+ await fs17.unlink(pidFile).catch(() => {
5975
6008
  });
5976
6009
  return false;
5977
6010
  }
@@ -5985,7 +6018,7 @@ async function getDaemonStatus() {
5985
6018
  return { running: false };
5986
6019
  }
5987
6020
  const pidFile = getPidFilePath();
5988
- const content = await fs16.readFile(pidFile, "utf-8");
6021
+ const content = await fs17.readFile(pidFile, "utf-8");
5989
6022
  const pid = parseInt(content.trim(), 10);
5990
6023
  return {
5991
6024
  running: true,
@@ -5998,15 +6031,15 @@ async function writeLog(message, level = "info") {
5998
6031
  const line = `[${timestamp}] [${level.toUpperCase()}] ${message}
5999
6032
  `;
6000
6033
  try {
6001
- await fs16.mkdir(path19.dirname(logPath), { recursive: true });
6034
+ await fs17.mkdir(path19.dirname(logPath), { recursive: true });
6002
6035
  try {
6003
- const stats = await fs16.stat(logPath);
6036
+ const stats = await fs17.stat(logPath);
6004
6037
  if (stats.size > MAX_LOG_SIZE) {
6005
- await fs16.rename(logPath, `${logPath}.old`);
6038
+ await fs17.rename(logPath, `${logPath}.old`);
6006
6039
  }
6007
6040
  } catch {
6008
6041
  }
6009
- await fs16.appendFile(logPath, line);
6042
+ await fs17.appendFile(logPath, line);
6010
6043
  } catch (error) {
6011
6044
  console.error(`Failed to write log: ${error}`);
6012
6045
  }
@@ -6041,8 +6074,8 @@ async function startDaemon(options = {}) {
6041
6074
  throw new Error("Daemon is already running");
6042
6075
  }
6043
6076
  const daemonDir = getDaemonDir();
6044
- await fs16.mkdir(daemonDir, { recursive: true });
6045
- await fs16.writeFile(getPidFilePath(), String(process.pid));
6077
+ await fs17.mkdir(daemonDir, { recursive: true });
6078
+ await fs17.writeFile(getPidFilePath(), String(process.pid));
6046
6079
  await writeLog("Daemon starting");
6047
6080
  const centralRepo = await getCentralRepoPath();
6048
6081
  if (!centralRepo) {
@@ -6133,7 +6166,7 @@ async function startDaemon(options = {}) {
6133
6166
  }
6134
6167
  watchedDirs.clear();
6135
6168
  try {
6136
- await fs16.unlink(getPidFilePath());
6169
+ await fs17.unlink(getPidFilePath());
6137
6170
  } catch {
6138
6171
  }
6139
6172
  await writeLog("Daemon stopped");
@@ -6257,7 +6290,7 @@ async function daemonStatusCommand() {
6257
6290
  async function daemonLogsCommand(options) {
6258
6291
  const logPath = getDaemonLogPath();
6259
6292
  try {
6260
- const content = await fs17.readFile(logPath, "utf-8");
6293
+ const content = await fs18.readFile(logPath, "utf-8");
6261
6294
  const lines = content.split("\n").filter(Boolean);
6262
6295
  const numLines = options.lines ?? 50;
6263
6296
  const displayLines = lines.slice(-numLines);
@@ -6266,12 +6299,12 @@ async function daemonLogsCommand(options) {
6266
6299
  }
6267
6300
  if (options.follow) {
6268
6301
  console.log("\n--- Following log (Ctrl+C to stop) ---\n");
6269
- let lastSize = (await fs17.stat(logPath)).size;
6302
+ let lastSize = (await fs18.stat(logPath)).size;
6270
6303
  const poll = async () => {
6271
6304
  try {
6272
- const stats = await fs17.stat(logPath);
6305
+ const stats = await fs18.stat(logPath);
6273
6306
  if (stats.size > lastSize) {
6274
- const fd = await fs17.open(logPath, "r");
6307
+ const fd = await fs18.open(logPath, "r");
6275
6308
  const buffer = Buffer.alloc(stats.size - lastSize);
6276
6309
  await fd.read(buffer, 0, buffer.length, lastSize);
6277
6310
  await fd.close();