minimem 0.0.6 → 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 +166 -133
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +10 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +10 -1
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
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
|
|
7
|
+
import fs3 from "fs/promises";
|
|
8
8
|
import path3 from "path";
|
|
9
9
|
|
|
10
10
|
// src/cli/config.ts
|
|
11
|
-
import
|
|
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,
|
|
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
|
|
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
|
|
123
|
-
await
|
|
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
|
|
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
|
-
|
|
195
|
-
await
|
|
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
|
|
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
|
|
350
|
-
await
|
|
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
|
|
371
|
+
await fs3.access(memoryFilePath);
|
|
355
372
|
console.log(" MEMORY.md already exists, skipping");
|
|
356
373
|
} catch {
|
|
357
|
-
await
|
|
374
|
+
await fs3.writeFile(memoryFilePath, MEMORY_TEMPLATE, "utf-8");
|
|
358
375
|
console.log(" Created MEMORY.md");
|
|
359
376
|
}
|
|
360
377
|
const config2 = getInitConfig();
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
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
|
|
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
|
|
390
|
-
import
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
458
|
+
upperReal = await fs4.realpath(memoryFile);
|
|
440
459
|
} catch {
|
|
441
460
|
}
|
|
442
461
|
try {
|
|
443
|
-
lowerReal = await
|
|
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
|
|
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
|
|
481
|
-
const content = await
|
|
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
|
|
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
|
|
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,
|
|
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
|
|
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
|
|
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
|
|
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
|
|
2893
|
-
await
|
|
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
|
|
2931
|
+
await fs5.mkdir(dir, { recursive: true });
|
|
2905
2932
|
let toAppend = content;
|
|
2906
2933
|
try {
|
|
2907
|
-
const existing = await
|
|
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
|
|
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
|
|
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
|
|
3342
|
+
await fs6.mkdir(parentDir, { recursive: true });
|
|
3316
3343
|
let isUpdate = false;
|
|
3317
3344
|
let existingContent;
|
|
3318
3345
|
try {
|
|
3319
|
-
await
|
|
3346
|
+
await fs6.access(filePath);
|
|
3320
3347
|
isUpdate = true;
|
|
3321
|
-
existingContent = await
|
|
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
|
|
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
|
|
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
|
|
4087
|
-
await
|
|
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
|
|
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
|
|
4128
|
+
await fs7.writeFile(memoryFilePath, template, "utf-8");
|
|
4103
4129
|
}
|
|
4104
4130
|
const config2 = getInitConfig();
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
|
|
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
|
|
4280
|
+
const fs19 = await import("fs/promises");
|
|
4254
4281
|
try {
|
|
4255
|
-
const content = await
|
|
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
|
|
4328
|
+
import fs11 from "fs/promises";
|
|
4302
4329
|
import path12 from "path";
|
|
4303
4330
|
|
|
4304
4331
|
// src/cli/sync/central.ts
|
|
4305
|
-
import
|
|
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
|
|
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
|
|
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
|
|
4342
|
-
await
|
|
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
|
|
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
|
|
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
|
|
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
|
|
4512
|
-
await
|
|
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
|
|
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
|
|
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
|
|
4611
|
+
await fs10.access(gitignorePath);
|
|
4585
4612
|
} catch {
|
|
4586
|
-
await
|
|
4613
|
+
await fs10.writeFile(gitignorePath, GITIGNORE_CONTENT, "utf-8");
|
|
4587
4614
|
}
|
|
4588
4615
|
const registryPath = getRegistryPath(resolvedPath);
|
|
4589
4616
|
try {
|
|
4590
|
-
await
|
|
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
|
|
4623
|
+
await fs10.access(readmePath);
|
|
4597
4624
|
} catch {
|
|
4598
|
-
await
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
4920
|
+
await fs12.mkdir(stateDir, { recursive: true });
|
|
4894
4921
|
state.version = state.version || 2;
|
|
4895
|
-
await
|
|
4896
|
-
await
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
4997
|
+
import fs13 from "fs/promises";
|
|
4970
4998
|
import path14 from "path";
|
|
4971
4999
|
var CONFLICTS_DIR = "conflicts";
|
|
4972
5000
|
function getConflictsDir(memoryDir) {
|
|
4973
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
5274
|
+
await fs14.mkdir(path15.dirname(logPath), { recursive: true });
|
|
5245
5275
|
let entries = [];
|
|
5246
5276
|
try {
|
|
5247
|
-
const content2 = await
|
|
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
|
|
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
|
|
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
|
|
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
|
|
5323
|
-
await
|
|
5352
|
+
await fs15.copyFile(src, tempDest);
|
|
5353
|
+
await fs15.rename(tempDest, dest);
|
|
5324
5354
|
} catch (error) {
|
|
5325
5355
|
try {
|
|
5326
|
-
await
|
|
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
|
|
5729
|
+
import fs18 from "fs/promises";
|
|
5700
5730
|
|
|
5701
5731
|
// src/cli/sync/daemon.ts
|
|
5702
|
-
import
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
6034
|
+
await fs17.mkdir(path19.dirname(logPath), { recursive: true });
|
|
6002
6035
|
try {
|
|
6003
|
-
const stats = await
|
|
6036
|
+
const stats = await fs17.stat(logPath);
|
|
6004
6037
|
if (stats.size > MAX_LOG_SIZE) {
|
|
6005
|
-
await
|
|
6038
|
+
await fs17.rename(logPath, `${logPath}.old`);
|
|
6006
6039
|
}
|
|
6007
6040
|
} catch {
|
|
6008
6041
|
}
|
|
6009
|
-
await
|
|
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
|
|
6045
|
-
await
|
|
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
|
|
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
|
|
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
|
|
6302
|
+
let lastSize = (await fs18.stat(logPath)).size;
|
|
6270
6303
|
const poll = async () => {
|
|
6271
6304
|
try {
|
|
6272
|
-
const stats = await
|
|
6305
|
+
const stats = await fs18.stat(logPath);
|
|
6273
6306
|
if (stats.size > lastSize) {
|
|
6274
|
-
const fd = await
|
|
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();
|