@remnic/cli 9.21.0 → 9.22.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +499 -338
- package/package.json +32 -28
package/dist/index.js
CHANGED
|
@@ -18,7 +18,7 @@ async function persistEnrichmentCandidate(storage, entityName, candidate) {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
// src/index.ts
|
|
21
|
-
import
|
|
21
|
+
import fs11 from "fs";
|
|
22
22
|
import os from "os";
|
|
23
23
|
import path12 from "path";
|
|
24
24
|
import { createHash as createHash2 } from "crypto";
|
|
@@ -26,11 +26,11 @@ import * as childProcess2 from "child_process";
|
|
|
26
26
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
27
27
|
import { gzipSync } from "zlib";
|
|
28
28
|
import {
|
|
29
|
-
parseConfig as
|
|
29
|
+
parseConfig as parseConfig4,
|
|
30
30
|
isOpenaiApiKeyDisabled,
|
|
31
31
|
resolveEnvVars,
|
|
32
|
-
resolveRemnicConfigRecord as
|
|
33
|
-
Orchestrator as
|
|
32
|
+
resolveRemnicConfigRecord as resolveRemnicConfigRecord4,
|
|
33
|
+
Orchestrator as Orchestrator3,
|
|
34
34
|
EngramAccessService as EngramAccessService2,
|
|
35
35
|
initLogger as initLogger2,
|
|
36
36
|
onboard,
|
|
@@ -139,6 +139,56 @@ import {
|
|
|
139
139
|
validateCapabilitiesForMint
|
|
140
140
|
} from "@remnic/core";
|
|
141
141
|
|
|
142
|
+
// src/commands/meetings.ts
|
|
143
|
+
import fs from "fs";
|
|
144
|
+
import {
|
|
145
|
+
Orchestrator,
|
|
146
|
+
parseConfig,
|
|
147
|
+
resolveRemnicConfigRecord,
|
|
148
|
+
runMeetingsCliCommand
|
|
149
|
+
} from "@remnic/core";
|
|
150
|
+
async function runMeetingsBinaryCommand(rest) {
|
|
151
|
+
const meetingsArgs = rest.length === 0 || rest[0] === "--help" || rest[0] === "-h" ? ["help"] : rest;
|
|
152
|
+
let meetingsOrchestrator;
|
|
153
|
+
try {
|
|
154
|
+
let meetingsService;
|
|
155
|
+
try {
|
|
156
|
+
const configPath = resolveConfigPath();
|
|
157
|
+
const raw = fs.existsSync(configPath) ? JSON.parse(fs.readFileSync(configPath, "utf8")) : {};
|
|
158
|
+
const config = parseConfig(resolveRemnicConfigRecord(raw));
|
|
159
|
+
meetingsOrchestrator = new Orchestrator(config);
|
|
160
|
+
await meetingsOrchestrator.initialize();
|
|
161
|
+
await meetingsOrchestrator.deferredReady;
|
|
162
|
+
meetingsService = await meetingsOrchestrator.getMeetingsService();
|
|
163
|
+
} catch {
|
|
164
|
+
console.error(
|
|
165
|
+
"meetings: failed to load the Remnic config or start the memory engine \u2014 run `remnic doctor` and check the config file for errors"
|
|
166
|
+
);
|
|
167
|
+
process.exitCode = 1;
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
const code = await runMeetingsCliCommand(
|
|
171
|
+
{ store: meetingsService.store, builder: meetingsService.builder, config: meetingsService.config },
|
|
172
|
+
meetingsArgs,
|
|
173
|
+
{ stdout: process.stdout, stderr: process.stderr }
|
|
174
|
+
);
|
|
175
|
+
if (code !== 0) process.exitCode = code;
|
|
176
|
+
} catch (err) {
|
|
177
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
178
|
+
process.exitCode = 1;
|
|
179
|
+
} finally {
|
|
180
|
+
if (meetingsOrchestrator) {
|
|
181
|
+
const maybeShutdown = meetingsOrchestrator.shutdown;
|
|
182
|
+
if (typeof maybeShutdown === "function") {
|
|
183
|
+
try {
|
|
184
|
+
await maybeShutdown.call(meetingsOrchestrator);
|
|
185
|
+
} catch {
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
142
192
|
// src/optional-module-loader.ts
|
|
143
193
|
function isSpecifierNotFoundError(err, specifier) {
|
|
144
194
|
if (!err || typeof err !== "object") {
|
|
@@ -321,8 +371,8 @@ function renderReplayResult(result, targetNamespace, format) {
|
|
|
321
371
|
}
|
|
322
372
|
|
|
323
373
|
// src/quarantine-replay.ts
|
|
324
|
-
import * as
|
|
325
|
-
import { EngramAccessService, Orchestrator, initLogger, parseConfig, resolveRemnicConfigRecord } from "@remnic/core";
|
|
374
|
+
import * as fs2 from "fs";
|
|
375
|
+
import { EngramAccessService, Orchestrator as Orchestrator2, initLogger, parseConfig as parseConfig2, resolveRemnicConfigRecord as resolveRemnicConfigRecord2 } from "@remnic/core";
|
|
326
376
|
import { WriteQuarantineStore } from "@remnic/core/write-quarantine.js";
|
|
327
377
|
function valueFlag(args, flag) {
|
|
328
378
|
const occurrences = args.filter((a) => a === flag).length;
|
|
@@ -370,9 +420,9 @@ async function runQuarantineReplay(rest, format, resolveConfigPath2) {
|
|
|
370
420
|
let orchestrator;
|
|
371
421
|
try {
|
|
372
422
|
const configPath = resolveConfigPath2();
|
|
373
|
-
const raw =
|
|
374
|
-
const config =
|
|
375
|
-
orchestrator = new
|
|
423
|
+
const raw = fs2.existsSync(configPath) ? JSON.parse(fs2.readFileSync(configPath, "utf8")) : {};
|
|
424
|
+
const config = parseConfig2(resolveRemnicConfigRecord2(raw));
|
|
425
|
+
orchestrator = new Orchestrator2(config);
|
|
376
426
|
await orchestrator.initialize();
|
|
377
427
|
await orchestrator.deferredReady;
|
|
378
428
|
const service = new EngramAccessService(orchestrator);
|
|
@@ -402,15 +452,15 @@ async function runQuarantineReplay(rest, format, resolveConfigPath2) {
|
|
|
402
452
|
}
|
|
403
453
|
|
|
404
454
|
// src/offline-impression-rotation.ts
|
|
405
|
-
import
|
|
406
|
-
import { parseConfig as
|
|
455
|
+
import fs3 from "fs";
|
|
456
|
+
import { parseConfig as parseConfig3, resolveRemnicConfigRecord as resolveRemnicConfigRecord3, drainPendingImpressionsForOfflineSync } from "@remnic/core";
|
|
407
457
|
import { LastRecallStore } from "@remnic/core/recall-state";
|
|
408
458
|
function parseConfigQuietly(raw) {
|
|
409
459
|
const originalWarn = console.warn;
|
|
410
460
|
console.warn = () => {
|
|
411
461
|
};
|
|
412
462
|
try {
|
|
413
|
-
return
|
|
463
|
+
return parseConfig3(resolveRemnicConfigRecord3(raw));
|
|
414
464
|
} finally {
|
|
415
465
|
console.warn = originalWarn;
|
|
416
466
|
}
|
|
@@ -424,7 +474,7 @@ var OFFLINE_CONFIG_KEYS = [
|
|
|
424
474
|
function pickOfflineConfigRecord(raw) {
|
|
425
475
|
let resolved;
|
|
426
476
|
try {
|
|
427
|
-
resolved =
|
|
477
|
+
resolved = resolveRemnicConfigRecord3(raw);
|
|
428
478
|
} catch {
|
|
429
479
|
resolved = raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
|
|
430
480
|
}
|
|
@@ -437,7 +487,7 @@ function pickOfflineConfigRecord(raw) {
|
|
|
437
487
|
function resolveOfflineImpressionRotation(configPath) {
|
|
438
488
|
let raw;
|
|
439
489
|
try {
|
|
440
|
-
raw =
|
|
490
|
+
raw = fs3.existsSync(configPath) ? JSON.parse(fs3.readFileSync(configPath, "utf8")) : {};
|
|
441
491
|
} catch {
|
|
442
492
|
throw new Error(
|
|
443
493
|
`cannot read recall-impression rotation from ${configPath}: config file could not be read as JSON`
|
|
@@ -467,7 +517,7 @@ async function drainOfflineSyncImpressions(memoryDir, rotation) {
|
|
|
467
517
|
|
|
468
518
|
// src/offline-storage-io.ts
|
|
469
519
|
import { mkdtemp, readdir, lstat, rm } from "fs/promises";
|
|
470
|
-
import
|
|
520
|
+
import fs4 from "fs";
|
|
471
521
|
import path from "path";
|
|
472
522
|
import { createHash, createDecipheriv } from "crypto";
|
|
473
523
|
import {
|
|
@@ -603,7 +653,7 @@ async function* readOfflineSyncFileChunks(options) {
|
|
|
603
653
|
});
|
|
604
654
|
}
|
|
605
655
|
async function readFilePrefix(filePath, length) {
|
|
606
|
-
const handle = await
|
|
656
|
+
const handle = await fs4.promises.open(filePath, "r");
|
|
607
657
|
try {
|
|
608
658
|
const out = Buffer.alloc(length);
|
|
609
659
|
const { bytesRead } = await handle.read(out, 0, length, 0);
|
|
@@ -613,7 +663,7 @@ async function readFilePrefix(filePath, length) {
|
|
|
613
663
|
}
|
|
614
664
|
}
|
|
615
665
|
async function* readPlainOfflineFileChunks(filePath, chunkSize) {
|
|
616
|
-
const stream =
|
|
666
|
+
const stream = fs4.createReadStream(filePath, { highWaterMark: chunkSize });
|
|
617
667
|
for await (const chunk of stream) {
|
|
618
668
|
yield Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
619
669
|
}
|
|
@@ -656,9 +706,9 @@ async function* readEncryptedOfflineFileChunks(options) {
|
|
|
656
706
|
});
|
|
657
707
|
decipher.setAuthTag(authTag);
|
|
658
708
|
decipher.setAAD(Buffer.concat([secureStoreEnvelopeHeaderAad(salt), aad]));
|
|
659
|
-
const output =
|
|
709
|
+
const output = fs4.createWriteStream(tempPath, { mode: 384 });
|
|
660
710
|
try {
|
|
661
|
-
const stream =
|
|
711
|
+
const stream = fs4.createReadStream(options.filePath, {
|
|
662
712
|
start: MAGIC_HEADER_SIZE + ENVELOPE_HEADER_SIZE,
|
|
663
713
|
highWaterMark: options.chunkSize
|
|
664
714
|
});
|
|
@@ -954,7 +1004,7 @@ function assertBenchModuleFreshForDevelopment() {
|
|
|
954
1004
|
}
|
|
955
1005
|
|
|
956
1006
|
// src/daemon-service-candidates.ts
|
|
957
|
-
import
|
|
1007
|
+
import fs5 from "fs";
|
|
958
1008
|
import path4 from "path";
|
|
959
1009
|
var LAUNCHD_LABEL = "ai.remnic.daemon";
|
|
960
1010
|
var LEGACY_REMNIC_SERVER_LAUNCHD_LABEL = "ai.remnic.server";
|
|
@@ -976,7 +1026,7 @@ function systemdUnitPaths(homeDir) {
|
|
|
976
1026
|
function anyFileExists(paths) {
|
|
977
1027
|
return paths.some((candidate) => {
|
|
978
1028
|
try {
|
|
979
|
-
return
|
|
1029
|
+
return fs5.statSync(candidate).isFile();
|
|
980
1030
|
} catch {
|
|
981
1031
|
return false;
|
|
982
1032
|
}
|
|
@@ -988,7 +1038,7 @@ function commandNames(command) {
|
|
|
988
1038
|
}
|
|
989
1039
|
function isRunnableNodeScript(filePath) {
|
|
990
1040
|
try {
|
|
991
|
-
const text =
|
|
1041
|
+
const text = fs5.readFileSync(filePath, "utf8").slice(0, 4096);
|
|
992
1042
|
const firstLine = text.split(/\r?\n/, 1)[0] ?? "";
|
|
993
1043
|
if (/^#!.*\bnode\b/.test(firstLine)) return true;
|
|
994
1044
|
if (firstLine.startsWith("#!")) return false;
|
|
@@ -1001,7 +1051,7 @@ function isRunnableNodeScript(filePath) {
|
|
|
1001
1051
|
function resolveShimNodeScript(filePath) {
|
|
1002
1052
|
let text;
|
|
1003
1053
|
try {
|
|
1004
|
-
text =
|
|
1054
|
+
text = fs5.readFileSync(filePath, "utf8").slice(0, 16384);
|
|
1005
1055
|
} catch {
|
|
1006
1056
|
return void 0;
|
|
1007
1057
|
}
|
|
@@ -1013,8 +1063,8 @@ function resolveShimNodeScript(filePath) {
|
|
|
1013
1063
|
const candidate = raw.replaceAll("${basedir}", basedir).replaceAll("$basedir", basedir).replaceAll("\\ ", " ");
|
|
1014
1064
|
const resolved = path4.isAbsolute(candidate) ? candidate : path4.resolve(basedir, candidate);
|
|
1015
1065
|
try {
|
|
1016
|
-
if (
|
|
1017
|
-
return
|
|
1066
|
+
if (fs5.statSync(resolved).isFile() && isRunnableNodeScript(resolved)) {
|
|
1067
|
+
return fs5.realpathSync(resolved);
|
|
1018
1068
|
}
|
|
1019
1069
|
} catch {
|
|
1020
1070
|
}
|
|
@@ -1022,7 +1072,7 @@ function resolveShimNodeScript(filePath) {
|
|
|
1022
1072
|
return void 0;
|
|
1023
1073
|
}
|
|
1024
1074
|
function resolveRunnableNodeScript(filePath) {
|
|
1025
|
-
const realPath =
|
|
1075
|
+
const realPath = fs5.realpathSync(filePath);
|
|
1026
1076
|
if (isRunnableNodeScript(realPath)) return realPath;
|
|
1027
1077
|
return resolveShimNodeScript(realPath);
|
|
1028
1078
|
}
|
|
@@ -1032,9 +1082,9 @@ function findCommandOnPath(command, pathEnv = process.env.PATH ?? "") {
|
|
|
1032
1082
|
for (const name of commandNames(command)) {
|
|
1033
1083
|
const candidate = path4.join(dir, name);
|
|
1034
1084
|
try {
|
|
1035
|
-
const stat =
|
|
1085
|
+
const stat = fs5.statSync(candidate);
|
|
1036
1086
|
if (!stat.isFile()) continue;
|
|
1037
|
-
if (process.platform !== "win32")
|
|
1087
|
+
if (process.platform !== "win32") fs5.accessSync(candidate, fs5.constants.X_OK);
|
|
1038
1088
|
const runnable = resolveRunnableNodeScript(candidate);
|
|
1039
1089
|
if (runnable) return runnable;
|
|
1040
1090
|
} catch {
|
|
@@ -2389,7 +2439,7 @@ function finalizeBenchStatus(filePath) {
|
|
|
2389
2439
|
}
|
|
2390
2440
|
|
|
2391
2441
|
// src/bench-fallback.ts
|
|
2392
|
-
import
|
|
2442
|
+
import fs6 from "fs";
|
|
2393
2443
|
import path7 from "path";
|
|
2394
2444
|
var FALLBACK_RESULTS_DIRNAME = "fallback-runs";
|
|
2395
2445
|
function buildBenchRunnerArgs(parsed, benchmarkId, outputDir) {
|
|
@@ -2461,7 +2511,7 @@ function createFallbackBenchOutputDir(resultsDir, benchmarkId, pid, startedAtMs
|
|
|
2461
2511
|
);
|
|
2462
2512
|
}
|
|
2463
2513
|
function resolveFallbackBenchResultPath(outputDir) {
|
|
2464
|
-
const entries =
|
|
2514
|
+
const entries = fs6.readdirSync(outputDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name).sort();
|
|
2465
2515
|
if (entries.length === 0) {
|
|
2466
2516
|
throw new Error(`Fallback benchmark runner did not write a JSON result artifact in ${outputDir}`);
|
|
2467
2517
|
}
|
|
@@ -2469,7 +2519,7 @@ function resolveFallbackBenchResultPath(outputDir) {
|
|
|
2469
2519
|
}
|
|
2470
2520
|
|
|
2471
2521
|
// src/openclaw-upgrade-swap.ts
|
|
2472
|
-
import
|
|
2522
|
+
import fs7 from "fs";
|
|
2473
2523
|
import path8 from "path";
|
|
2474
2524
|
function describeError(error) {
|
|
2475
2525
|
return error instanceof Error ? error.message : String(error);
|
|
@@ -2481,7 +2531,7 @@ function createSiblingTempFilePath(targetPath, label) {
|
|
|
2481
2531
|
function resolveAtomicWriteMode(targetPath, explicitMode) {
|
|
2482
2532
|
if (explicitMode !== void 0) return explicitMode;
|
|
2483
2533
|
try {
|
|
2484
|
-
return
|
|
2534
|
+
return fs7.statSync(targetPath).mode & 4095;
|
|
2485
2535
|
} catch (error) {
|
|
2486
2536
|
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
2487
2537
|
return 384;
|
|
@@ -2491,8 +2541,8 @@ function resolveAtomicWriteMode(targetPath, explicitMode) {
|
|
|
2491
2541
|
}
|
|
2492
2542
|
function resolveAtomicReplacementPath(targetPath) {
|
|
2493
2543
|
try {
|
|
2494
|
-
if (
|
|
2495
|
-
return
|
|
2544
|
+
if (fs7.lstatSync(targetPath).isSymbolicLink()) {
|
|
2545
|
+
return fs7.realpathSync(targetPath);
|
|
2496
2546
|
}
|
|
2497
2547
|
} catch (error) {
|
|
2498
2548
|
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
@@ -2509,7 +2559,7 @@ function createSiblingSwapPath(targetDir, label) {
|
|
|
2509
2559
|
function cleanupDisplacedDirectoryBestEffort(displacedDir, context) {
|
|
2510
2560
|
if (!displacedDir) return void 0;
|
|
2511
2561
|
try {
|
|
2512
|
-
|
|
2562
|
+
fs7.rmSync(displacedDir, { recursive: true, force: true });
|
|
2513
2563
|
return void 0;
|
|
2514
2564
|
} catch (error) {
|
|
2515
2565
|
return `Warning: ${context}, but failed to remove the displaced plugin copy at ${displacedDir}: ${describeError(error)}`;
|
|
@@ -2517,55 +2567,55 @@ function cleanupDisplacedDirectoryBestEffort(displacedDir, context) {
|
|
|
2517
2567
|
}
|
|
2518
2568
|
function atomicWriteFileSync(targetPath, data, options = {}) {
|
|
2519
2569
|
const resolvedTargetPath = resolveAtomicReplacementPath(targetPath);
|
|
2520
|
-
|
|
2570
|
+
fs7.mkdirSync(path8.dirname(resolvedTargetPath), { recursive: true });
|
|
2521
2571
|
const tempPath = createSiblingTempFilePath(resolvedTargetPath, "write");
|
|
2522
2572
|
const mode = resolveAtomicWriteMode(resolvedTargetPath, options.mode);
|
|
2523
2573
|
try {
|
|
2524
2574
|
if (options.hooks?.writeTempFileSync) {
|
|
2525
2575
|
options.hooks.writeTempFileSync(tempPath);
|
|
2526
2576
|
} else {
|
|
2527
|
-
|
|
2577
|
+
fs7.writeFileSync(tempPath, data, { mode });
|
|
2528
2578
|
}
|
|
2529
|
-
|
|
2530
|
-
const renameTempFileSync = options.hooks?.renameTempFileSync ??
|
|
2579
|
+
fs7.chmodSync(tempPath, mode);
|
|
2580
|
+
const renameTempFileSync = options.hooks?.renameTempFileSync ?? fs7.renameSync;
|
|
2531
2581
|
renameTempFileSync(tempPath, resolvedTargetPath);
|
|
2532
2582
|
} catch (error) {
|
|
2533
|
-
|
|
2583
|
+
fs7.rmSync(tempPath, { force: true });
|
|
2534
2584
|
throw error;
|
|
2535
2585
|
}
|
|
2536
2586
|
}
|
|
2537
2587
|
function atomicCopyFileSync(sourcePath, targetPath, options = {}) {
|
|
2538
|
-
if (!
|
|
2588
|
+
if (!fs7.existsSync(sourcePath)) return;
|
|
2539
2589
|
const resolvedTargetPath = resolveAtomicReplacementPath(targetPath);
|
|
2540
|
-
|
|
2590
|
+
fs7.mkdirSync(path8.dirname(resolvedTargetPath), { recursive: true });
|
|
2541
2591
|
const tempPath = createSiblingTempFilePath(resolvedTargetPath, "copy");
|
|
2542
|
-
const mode =
|
|
2592
|
+
const mode = fs7.statSync(sourcePath).mode & 4095;
|
|
2543
2593
|
try {
|
|
2544
|
-
const copyTempFileSync = options.hooks?.copyTempFileSync ??
|
|
2594
|
+
const copyTempFileSync = options.hooks?.copyTempFileSync ?? fs7.copyFileSync;
|
|
2545
2595
|
copyTempFileSync(sourcePath, tempPath);
|
|
2546
|
-
|
|
2547
|
-
const renameTempFileSync = options.hooks?.renameTempFileSync ??
|
|
2596
|
+
fs7.chmodSync(tempPath, mode);
|
|
2597
|
+
const renameTempFileSync = options.hooks?.renameTempFileSync ?? fs7.renameSync;
|
|
2548
2598
|
renameTempFileSync(tempPath, resolvedTargetPath);
|
|
2549
2599
|
} catch (error) {
|
|
2550
|
-
|
|
2600
|
+
fs7.rmSync(tempPath, { force: true });
|
|
2551
2601
|
throw error;
|
|
2552
2602
|
}
|
|
2553
2603
|
}
|
|
2554
2604
|
function swapDirectoryWithRollback(stagedDir, targetDir, rollbackDir) {
|
|
2555
2605
|
let hasRollbackCopy = false;
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
if (
|
|
2559
|
-
|
|
2606
|
+
fs7.mkdirSync(path8.dirname(targetDir), { recursive: true });
|
|
2607
|
+
fs7.rmSync(rollbackDir, { recursive: true, force: true });
|
|
2608
|
+
if (fs7.existsSync(targetDir)) {
|
|
2609
|
+
fs7.renameSync(targetDir, rollbackDir);
|
|
2560
2610
|
hasRollbackCopy = true;
|
|
2561
2611
|
}
|
|
2562
2612
|
try {
|
|
2563
|
-
|
|
2613
|
+
fs7.renameSync(stagedDir, targetDir);
|
|
2564
2614
|
} catch (swapError) {
|
|
2565
|
-
|
|
2566
|
-
if (hasRollbackCopy &&
|
|
2615
|
+
fs7.rmSync(targetDir, { recursive: true, force: true });
|
|
2616
|
+
if (hasRollbackCopy && fs7.existsSync(rollbackDir)) {
|
|
2567
2617
|
try {
|
|
2568
|
-
|
|
2618
|
+
fs7.renameSync(rollbackDir, targetDir);
|
|
2569
2619
|
hasRollbackCopy = false;
|
|
2570
2620
|
} catch (restoreError) {
|
|
2571
2621
|
throw new AggregateError(
|
|
@@ -2580,7 +2630,7 @@ function swapDirectoryWithRollback(stagedDir, targetDir, rollbackDir) {
|
|
|
2580
2630
|
}
|
|
2581
2631
|
function cleanupRollbackDirectory(rollbackDir) {
|
|
2582
2632
|
if (!rollbackDir) return;
|
|
2583
|
-
|
|
2633
|
+
fs7.rmSync(rollbackDir, { recursive: true, force: true });
|
|
2584
2634
|
}
|
|
2585
2635
|
function cleanupRollbackDirectoryBestEffort(rollbackDir) {
|
|
2586
2636
|
if (!rollbackDir) return void 0;
|
|
@@ -2592,20 +2642,20 @@ function cleanupRollbackDirectoryBestEffort(rollbackDir) {
|
|
|
2592
2642
|
}
|
|
2593
2643
|
}
|
|
2594
2644
|
function restoreDirectoryFromRollback(targetDir, rollbackDir) {
|
|
2595
|
-
if (!
|
|
2645
|
+
if (!fs7.existsSync(rollbackDir)) {
|
|
2596
2646
|
throw new Error(`Rollback directory is missing: ${rollbackDir}`);
|
|
2597
2647
|
}
|
|
2598
|
-
|
|
2599
|
-
const displacedDir =
|
|
2648
|
+
fs7.mkdirSync(path8.dirname(targetDir), { recursive: true });
|
|
2649
|
+
const displacedDir = fs7.existsSync(targetDir) ? createSiblingSwapPath(targetDir, "rollback-restore") : void 0;
|
|
2600
2650
|
if (displacedDir) {
|
|
2601
|
-
|
|
2651
|
+
fs7.renameSync(targetDir, displacedDir);
|
|
2602
2652
|
}
|
|
2603
2653
|
try {
|
|
2604
|
-
|
|
2654
|
+
fs7.renameSync(rollbackDir, targetDir);
|
|
2605
2655
|
} catch (restoreError) {
|
|
2606
|
-
if (displacedDir &&
|
|
2656
|
+
if (displacedDir && fs7.existsSync(displacedDir)) {
|
|
2607
2657
|
try {
|
|
2608
|
-
|
|
2658
|
+
fs7.renameSync(displacedDir, targetDir);
|
|
2609
2659
|
} catch (revertError) {
|
|
2610
2660
|
throw new AggregateError(
|
|
2611
2661
|
[restoreError, revertError],
|
|
@@ -2624,23 +2674,23 @@ function restoreDirectoryFromRollback(targetDir, rollbackDir) {
|
|
|
2624
2674
|
);
|
|
2625
2675
|
}
|
|
2626
2676
|
function restoreDirectoryFromBackup(targetDir, backupDir) {
|
|
2627
|
-
if (!
|
|
2677
|
+
if (!fs7.existsSync(backupDir)) {
|
|
2628
2678
|
throw new Error(`Plugin backup directory is missing: ${backupDir}`);
|
|
2629
2679
|
}
|
|
2630
|
-
|
|
2680
|
+
fs7.mkdirSync(path8.dirname(targetDir), { recursive: true });
|
|
2631
2681
|
const stagedDir = createSiblingSwapPath(targetDir, "backup-restore");
|
|
2632
|
-
const displacedDir =
|
|
2633
|
-
|
|
2682
|
+
const displacedDir = fs7.existsSync(targetDir) ? createSiblingSwapPath(targetDir, "pre-backup-restore") : void 0;
|
|
2683
|
+
fs7.cpSync(backupDir, stagedDir, { recursive: true });
|
|
2634
2684
|
if (displacedDir) {
|
|
2635
|
-
|
|
2685
|
+
fs7.renameSync(targetDir, displacedDir);
|
|
2636
2686
|
}
|
|
2637
2687
|
try {
|
|
2638
|
-
|
|
2688
|
+
fs7.renameSync(stagedDir, targetDir);
|
|
2639
2689
|
} catch (restoreError) {
|
|
2640
|
-
|
|
2641
|
-
if (displacedDir &&
|
|
2690
|
+
fs7.rmSync(targetDir, { recursive: true, force: true });
|
|
2691
|
+
if (displacedDir && fs7.existsSync(displacedDir)) {
|
|
2642
2692
|
try {
|
|
2643
|
-
|
|
2693
|
+
fs7.renameSync(displacedDir, targetDir);
|
|
2644
2694
|
} catch (revertError) {
|
|
2645
2695
|
throw new AggregateError(
|
|
2646
2696
|
[restoreError, revertError],
|
|
@@ -2648,7 +2698,7 @@ function restoreDirectoryFromBackup(targetDir, backupDir) {
|
|
|
2648
2698
|
);
|
|
2649
2699
|
}
|
|
2650
2700
|
}
|
|
2651
|
-
|
|
2701
|
+
fs7.rmSync(stagedDir, { recursive: true, force: true });
|
|
2652
2702
|
throw new Error(
|
|
2653
2703
|
`Failed to restore the plugin backup into ${targetDir}. The durable backup remains preserved at ${backupDir}.`,
|
|
2654
2704
|
{ cause: restoreError }
|
|
@@ -2674,7 +2724,7 @@ function rollbackOpenclawUpgrade({
|
|
|
2674
2724
|
let rollbackRestoreError;
|
|
2675
2725
|
let pluginRestored = false;
|
|
2676
2726
|
try {
|
|
2677
|
-
if (rollbackDir &&
|
|
2727
|
+
if (rollbackDir && fs7.existsSync(rollbackDir)) {
|
|
2678
2728
|
const cleanupWarning = restoreDirectoryFromRollback(pluginDir, rollbackDir);
|
|
2679
2729
|
notes.push(`Restored previous plugin from rollback copy at ${rollbackDir}`);
|
|
2680
2730
|
if (cleanupWarning) notes.push(cleanupWarning);
|
|
@@ -2684,7 +2734,7 @@ function rollbackOpenclawUpgrade({
|
|
|
2684
2734
|
rollbackRestoreError = error instanceof Error ? error.message : String(error);
|
|
2685
2735
|
}
|
|
2686
2736
|
try {
|
|
2687
|
-
if (!pluginRestored && pluginBackupDir &&
|
|
2737
|
+
if (!pluginRestored && pluginBackupDir && fs7.existsSync(pluginBackupDir)) {
|
|
2688
2738
|
const cleanupWarning = restoreDirectoryFromBackup(pluginDir, pluginBackupDir);
|
|
2689
2739
|
if (rollbackRestoreError) {
|
|
2690
2740
|
notes.push(
|
|
@@ -2711,7 +2761,7 @@ function rollbackOpenclawUpgrade({
|
|
|
2711
2761
|
notes.push("No previous plugin copy was available for automatic restore");
|
|
2712
2762
|
}
|
|
2713
2763
|
try {
|
|
2714
|
-
if (configBackupPath &&
|
|
2764
|
+
if (configBackupPath && fs7.existsSync(configBackupPath)) {
|
|
2715
2765
|
restoreFileFromBackup(configPath, configBackupPath);
|
|
2716
2766
|
notes.push(`Restored OpenClaw config from backup at ${configBackupPath}`);
|
|
2717
2767
|
}
|
|
@@ -2751,7 +2801,7 @@ Run this manually when you're ready:
|
|
|
2751
2801
|
}
|
|
2752
2802
|
|
|
2753
2803
|
// src/daemon-service.ts
|
|
2754
|
-
import
|
|
2804
|
+
import fs8 from "fs";
|
|
2755
2805
|
import path9 from "path";
|
|
2756
2806
|
import * as childProcess from "child_process";
|
|
2757
2807
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
@@ -2763,7 +2813,7 @@ function launchdUnloadPlist(plistPath, processApi = childProcess) {
|
|
|
2763
2813
|
processApi.execFileSync("launchctl", ["unload", plistPath], { stdio: "pipe" });
|
|
2764
2814
|
}
|
|
2765
2815
|
function resolveServerBinDetails(options = {}) {
|
|
2766
|
-
const existsSync4 = options.existsSync ??
|
|
2816
|
+
const existsSync4 = options.existsSync ?? fs8.existsSync;
|
|
2767
2817
|
const findCommandOnPath2 = options.findCommandOnPath ?? findCommandOnPath;
|
|
2768
2818
|
const moduleDir = options.moduleDir ?? thisModuleDir;
|
|
2769
2819
|
const packageResolve = options.packageResolve ?? resolveImportSpecifier;
|
|
@@ -2822,8 +2872,8 @@ function resolveServerBin(options = {}) {
|
|
|
2822
2872
|
return resolveServerBinDetails(options).path;
|
|
2823
2873
|
}
|
|
2824
2874
|
function readVerifiedDaemonPid(options) {
|
|
2825
|
-
const readFileSync4 = options.readFileSync ??
|
|
2826
|
-
const unlinkSync = options.unlinkSync ??
|
|
2875
|
+
const readFileSync4 = options.readFileSync ?? fs8.readFileSync;
|
|
2876
|
+
const unlinkSync = options.unlinkSync ?? fs8.unlinkSync;
|
|
2827
2877
|
const processKill = options.processKill ?? process.kill;
|
|
2828
2878
|
const platform = options.platform ?? process.platform;
|
|
2829
2879
|
const execFileSync3 = options.execFileSync ?? ((command, args, execOptions) => childProcess.execFileSync(command, args, execOptions));
|
|
@@ -2923,8 +2973,8 @@ function removePidFileBestEffort(file, unlinkSync) {
|
|
|
2923
2973
|
}
|
|
2924
2974
|
}
|
|
2925
2975
|
function inspectLaunchdPlist(plistPath, options = {}) {
|
|
2926
|
-
const existsSync4 = options.existsSync ??
|
|
2927
|
-
const readFileSync4 = options.readFileSync ??
|
|
2976
|
+
const existsSync4 = options.existsSync ?? fs8.existsSync;
|
|
2977
|
+
const readFileSync4 = options.readFileSync ?? fs8.readFileSync;
|
|
2928
2978
|
if (!existsSync4(plistPath)) {
|
|
2929
2979
|
return {
|
|
2930
2980
|
installed: false,
|
|
@@ -3158,7 +3208,7 @@ function stripConfigArgv(args) {
|
|
|
3158
3208
|
}
|
|
3159
3209
|
|
|
3160
3210
|
// src/import-dispatch.ts
|
|
3161
|
-
import
|
|
3211
|
+
import fs9 from "fs";
|
|
3162
3212
|
import {
|
|
3163
3213
|
runImporter,
|
|
3164
3214
|
validateImportBatchSize,
|
|
@@ -3672,7 +3722,7 @@ async function cmdImport(rest, targetFactory, disposeTarget, ioOverrides = {}) {
|
|
|
3672
3722
|
let materializedTarget;
|
|
3673
3723
|
let materializePromise;
|
|
3674
3724
|
const io = {
|
|
3675
|
-
readFile: ioOverrides.readFile ?? (async (p) =>
|
|
3725
|
+
readFile: ioOverrides.readFile ?? (async (p) => fs9.promises.readFile(p, "utf-8")),
|
|
3676
3726
|
loadAdapter: ioOverrides.loadAdapter ?? (async (name) => (await loadImporterModule(name)).adapter),
|
|
3677
3727
|
runImporter: ioOverrides.runImporter ?? runImporter,
|
|
3678
3728
|
getWriteTarget: async () => {
|
|
@@ -3744,8 +3794,48 @@ function takeOptionalValue(args, flag) {
|
|
|
3744
3794
|
return takeValue(args, flag);
|
|
3745
3795
|
}
|
|
3746
3796
|
|
|
3797
|
+
// src/capture-dispatch.ts
|
|
3798
|
+
var SPECIFIER3 = "@remnic/capture-audio";
|
|
3799
|
+
var INSTALL_HINT = "`remnic capture audio` requires the optional @remnic/capture-audio package. Install it with: npm install @remnic/capture-audio";
|
|
3800
|
+
var USAGE = "usage: remnic capture audio <init|start|stop|status|devices|logs|download-model|janitor|enroll-self> [options]";
|
|
3801
|
+
function translateCaptureLoadError(err) {
|
|
3802
|
+
if (isSpecifierNotFoundError(err, SPECIFIER3)) return new Error(INSTALL_HINT);
|
|
3803
|
+
return err instanceof Error ? err : new Error(String(err));
|
|
3804
|
+
}
|
|
3805
|
+
async function defaultLoadCaptureAudio() {
|
|
3806
|
+
try {
|
|
3807
|
+
return await import(SPECIFIER3);
|
|
3808
|
+
} catch (err) {
|
|
3809
|
+
throw translateCaptureLoadError(err);
|
|
3810
|
+
}
|
|
3811
|
+
}
|
|
3812
|
+
async function cmdCapture(rest, io) {
|
|
3813
|
+
if (rest.length === 0 || rest[0] === "--help" || rest[0] === "-h") {
|
|
3814
|
+
io.stdout(USAGE);
|
|
3815
|
+
return rest.length === 0 ? 2 : 0;
|
|
3816
|
+
}
|
|
3817
|
+
if (rest[0] !== "audio") {
|
|
3818
|
+
io.stderr(`unknown capture subgroup '${rest[0]}'. ${USAGE}`);
|
|
3819
|
+
return 2;
|
|
3820
|
+
}
|
|
3821
|
+
const forwarded = rest.slice(1);
|
|
3822
|
+
let mod;
|
|
3823
|
+
try {
|
|
3824
|
+
mod = await (io.loadCaptureAudio ?? defaultLoadCaptureAudio)();
|
|
3825
|
+
} catch (err) {
|
|
3826
|
+
io.stderr(err instanceof Error ? err.message : String(err));
|
|
3827
|
+
return 2;
|
|
3828
|
+
}
|
|
3829
|
+
return mod.runCapture({
|
|
3830
|
+
argv: forwarded,
|
|
3831
|
+
stdout: io.stdout,
|
|
3832
|
+
stderr: io.stderr,
|
|
3833
|
+
spawnArgvPrefix: [process.argv[1], "capture", "audio"]
|
|
3834
|
+
});
|
|
3835
|
+
}
|
|
3836
|
+
|
|
3747
3837
|
// src/import-lossless-claw-cmd.ts
|
|
3748
|
-
import
|
|
3838
|
+
import fs10 from "fs";
|
|
3749
3839
|
import path11 from "path";
|
|
3750
3840
|
import {
|
|
3751
3841
|
applyLcmSchema,
|
|
@@ -3831,13 +3921,13 @@ function parseImportLosslessClawArgs(argv) {
|
|
|
3831
3921
|
}
|
|
3832
3922
|
|
|
3833
3923
|
// src/optional-import-lossless-claw.ts
|
|
3834
|
-
var
|
|
3924
|
+
var SPECIFIER4 = "@remnic/import-lossless-claw";
|
|
3835
3925
|
var cached4;
|
|
3836
3926
|
async function tryImport() {
|
|
3837
3927
|
try {
|
|
3838
|
-
return await import(
|
|
3928
|
+
return await import(SPECIFIER4);
|
|
3839
3929
|
} catch (err) {
|
|
3840
|
-
if (isSpecifierNotFoundError(err,
|
|
3930
|
+
if (isSpecifierNotFoundError(err, SPECIFIER4)) {
|
|
3841
3931
|
return null;
|
|
3842
3932
|
}
|
|
3843
3933
|
throw err;
|
|
@@ -3857,15 +3947,15 @@ async function loadImportLosslessClawModule() {
|
|
|
3857
3947
|
|
|
3858
3948
|
// src/import-lossless-claw-cmd.ts
|
|
3859
3949
|
function assertDirectoryOrAbsent(p, label) {
|
|
3860
|
-
if (
|
|
3950
|
+
if (fs10.existsSync(p) && !fs10.statSync(p).isDirectory()) {
|
|
3861
3951
|
throw new Error(`${label} is not a directory: ${p}`);
|
|
3862
3952
|
}
|
|
3863
3953
|
}
|
|
3864
3954
|
function assertFile(p, label) {
|
|
3865
|
-
if (!
|
|
3955
|
+
if (!fs10.existsSync(p)) {
|
|
3866
3956
|
throw new Error(`${label} does not exist: ${p}`);
|
|
3867
3957
|
}
|
|
3868
|
-
if (!
|
|
3958
|
+
if (!fs10.statSync(p).isFile()) {
|
|
3869
3959
|
throw new Error(`${label} is not a file: ${p}`);
|
|
3870
3960
|
}
|
|
3871
3961
|
}
|
|
@@ -3897,7 +3987,7 @@ async function cmdImportLosslessClaw(argv, io, deps = {}) {
|
|
|
3897
3987
|
try {
|
|
3898
3988
|
if (parsed.dryRun) {
|
|
3899
3989
|
const lcmPath = path11.join(memoryDir, "state", "lcm.sqlite");
|
|
3900
|
-
if (
|
|
3990
|
+
if (fs10.existsSync(lcmPath)) {
|
|
3901
3991
|
destDb = mod.openExistingLcmDatabaseReadOnly(lcmPath);
|
|
3902
3992
|
} else {
|
|
3903
3993
|
destDb = mod.openInMemoryDestinationDatabase();
|
|
@@ -3946,6 +4036,74 @@ async function cmdImportLosslessClaw(argv, io, deps = {}) {
|
|
|
3946
4036
|
}
|
|
3947
4037
|
}
|
|
3948
4038
|
|
|
4039
|
+
// src/bench-output-printer.ts
|
|
4040
|
+
function printStoredBenchResultSummary(result, summary) {
|
|
4041
|
+
console.log(`Run id: ${summary.id}`);
|
|
4042
|
+
printBenchPackageSummary(result, summary.path, "Stored result");
|
|
4043
|
+
}
|
|
4044
|
+
function printBenchStatusLine(jsonMode, message) {
|
|
4045
|
+
if (jsonMode) {
|
|
4046
|
+
console.error(message);
|
|
4047
|
+
} else {
|
|
4048
|
+
console.log(message);
|
|
4049
|
+
}
|
|
4050
|
+
}
|
|
4051
|
+
function printBenchPackageSummary(result, outputPath, outputLabel = "Results saved") {
|
|
4052
|
+
console.log(`Benchmark: ${result.meta.benchmark}`);
|
|
4053
|
+
console.log(`Mode: ${result.meta.mode}`);
|
|
4054
|
+
if (result.config.runtimeProfile) {
|
|
4055
|
+
console.log(`Runtime profile: ${result.config.runtimeProfile}`);
|
|
4056
|
+
}
|
|
4057
|
+
console.log(`Tasks: ${result.results.tasks.length}`);
|
|
4058
|
+
console.log(`Mean query latency: ${result.cost.meanQueryLatencyMs.toFixed(1)}ms`);
|
|
4059
|
+
for (const [metric, aggregate] of Object.entries(result.results.aggregates).sort()) {
|
|
4060
|
+
console.log(` ${metric.padEnd(20)} ${aggregate.mean.toFixed(4)}`);
|
|
4061
|
+
}
|
|
4062
|
+
console.log(`${outputLabel}: ${outputPath}`);
|
|
4063
|
+
}
|
|
4064
|
+
function printStoredBenchResultDetails(result, summary) {
|
|
4065
|
+
printStoredBenchResultSummary(result, summary);
|
|
4066
|
+
if (result.results.tasks.length === 0) {
|
|
4067
|
+
console.log("Tasks: none");
|
|
4068
|
+
return;
|
|
4069
|
+
}
|
|
4070
|
+
console.log("Task breakdown:");
|
|
4071
|
+
for (const task of result.results.tasks) {
|
|
4072
|
+
const scores = Object.entries(task.scores ?? {}).sort(([left], [right]) => left.localeCompare(right)).map(([metric, value]) => `${metric}=${value.toFixed(4)}`).join(", ");
|
|
4073
|
+
const taskLabel = task.taskId ?? "(unknown task)";
|
|
4074
|
+
const taskLatency = typeof task.latencyMs === "number" ? task.latencyMs.toFixed(1) : "?";
|
|
4075
|
+
console.log(
|
|
4076
|
+
` ${taskLabel}: ${taskLatency}ms${scores.length > 0 ? ` [${scores}]` : ""}`
|
|
4077
|
+
);
|
|
4078
|
+
}
|
|
4079
|
+
}
|
|
4080
|
+
function printBenchComparisonSummary(comparison, baseline, candidate) {
|
|
4081
|
+
console.log(`Benchmark: ${comparison.benchmark}`);
|
|
4082
|
+
console.log(`Baseline: ${baseline.id} (${baseline.path})`);
|
|
4083
|
+
console.log(`Candidate: ${candidate.id} (${candidate.path})`);
|
|
4084
|
+
console.log(`Verdict: ${comparison.verdict}`);
|
|
4085
|
+
const metrics = Object.entries(comparison.metricDeltas).sort(
|
|
4086
|
+
([left], [right]) => left.localeCompare(right)
|
|
4087
|
+
);
|
|
4088
|
+
if (metrics.length === 0) {
|
|
4089
|
+
console.log("No overlapping metrics were found between the two results.");
|
|
4090
|
+
return;
|
|
4091
|
+
}
|
|
4092
|
+
console.log("Metrics:");
|
|
4093
|
+
for (const [metric, delta] of metrics) {
|
|
4094
|
+
const percent = Number.isFinite(delta.percentChange) ? `${(delta.percentChange * 100).toFixed(2)}%` : delta.percentChange > 0 ? "+Infinity%" : "-Infinity%";
|
|
4095
|
+
const direction = delta.delta >= 0 ? "+" : "";
|
|
4096
|
+
console.log(
|
|
4097
|
+
` ${metric.padEnd(18)} ${delta.baseline.toFixed(4)} -> ${delta.candidate.toFixed(4)} (${direction}${delta.delta.toFixed(4)}, ${percent}, d=${delta.effectSize.cohensD.toFixed(3)} ${delta.effectSize.interpretation})`
|
|
4098
|
+
);
|
|
4099
|
+
if (delta.ciOnDelta) {
|
|
4100
|
+
console.log(
|
|
4101
|
+
` 95% CI on delta: [${delta.ciOnDelta.lower.toFixed(4)}, ${delta.ciOnDelta.upper.toFixed(4)}]`
|
|
4102
|
+
);
|
|
4103
|
+
}
|
|
4104
|
+
}
|
|
4105
|
+
}
|
|
4106
|
+
|
|
3949
4107
|
// src/index.ts
|
|
3950
4108
|
var LazyPluginPiPublisher = class {
|
|
3951
4109
|
constructor(hostId, select) {
|
|
@@ -4330,7 +4488,7 @@ async function resolveAllBenchmarks() {
|
|
|
4330
4488
|
if (packageBenchmarks) {
|
|
4331
4489
|
return packageBenchmarks.filter((entry) => entry.runnerAvailable).map((entry) => entry.id);
|
|
4332
4490
|
}
|
|
4333
|
-
if (!
|
|
4491
|
+
if (!fs11.existsSync(EVAL_RUNNER_PATH)) {
|
|
4334
4492
|
return [];
|
|
4335
4493
|
}
|
|
4336
4494
|
return BENCHMARK_CATALOG.filter((entry) => entry.category !== "ingestion").map((entry) => entry.id);
|
|
@@ -4378,7 +4536,7 @@ async function runBenchViaFallback(parsed, benchmarkId, runtimeProfile) {
|
|
|
4378
4536
|
`Fallback benchmark runner does not support provider-backed, gateway, or thinking/timeout flags (${unsupportedOptions.join(", ")}). Build/install @remnic/bench to use those options.`
|
|
4379
4537
|
);
|
|
4380
4538
|
}
|
|
4381
|
-
if (!
|
|
4539
|
+
if (!fs11.existsSync(EVAL_RUNNER_PATH)) {
|
|
4382
4540
|
console.error(
|
|
4383
4541
|
"Benchmark runner not found. Expected eval runner at evals/run.ts or a phase-1 @remnic/bench runtime export."
|
|
4384
4542
|
);
|
|
@@ -4388,7 +4546,7 @@ async function runBenchViaFallback(parsed, benchmarkId, runtimeProfile) {
|
|
|
4388
4546
|
path12.join(CLI_REPO_ROOT, "node_modules", ".bin", "tsx"),
|
|
4389
4547
|
path12.join(CLI_REPO_ROOT, "packages", "remnic-cli", "node_modules", ".bin", "tsx")
|
|
4390
4548
|
];
|
|
4391
|
-
const tsxCmd = tsxCandidates.find((candidate) =>
|
|
4549
|
+
const tsxCmd = tsxCandidates.find((candidate) => fs11.existsSync(candidate)) ?? "tsx";
|
|
4392
4550
|
const fallbackOutputDir = createFallbackBenchOutputDir(
|
|
4393
4551
|
parsed.resultsDir ?? resolveBenchOutputDir(),
|
|
4394
4552
|
benchmarkId,
|
|
@@ -4533,9 +4691,9 @@ var PERSONAMEM_COMPLETION_MARKER = path12.join(
|
|
|
4533
4691
|
);
|
|
4534
4692
|
function resolveRealpathWithinDataset(datasetPath, relativePath) {
|
|
4535
4693
|
try {
|
|
4536
|
-
const datasetRoot =
|
|
4694
|
+
const datasetRoot = fs11.realpathSync(datasetPath);
|
|
4537
4695
|
const candidatePath = path12.resolve(datasetRoot, relativePath);
|
|
4538
|
-
const candidateRealPath =
|
|
4696
|
+
const candidateRealPath = fs11.realpathSync(candidatePath);
|
|
4539
4697
|
const relativeToRoot = path12.relative(datasetRoot, candidateRealPath);
|
|
4540
4698
|
if (relativeToRoot.startsWith("..") || path12.isAbsolute(relativeToRoot)) {
|
|
4541
4699
|
return null;
|
|
@@ -4594,14 +4752,14 @@ function parseCsvRows(raw) {
|
|
|
4594
4752
|
function isPersonaMemDatasetComplete(datasetPath) {
|
|
4595
4753
|
try {
|
|
4596
4754
|
const completionMarkerPath = path12.join(datasetPath, PERSONAMEM_COMPLETION_MARKER);
|
|
4597
|
-
if (
|
|
4755
|
+
if (fs11.statSync(completionMarkerPath).isFile()) {
|
|
4598
4756
|
return true;
|
|
4599
4757
|
}
|
|
4600
4758
|
} catch {
|
|
4601
4759
|
}
|
|
4602
4760
|
const datasetFile = PERSONAMEM_DATASET_FILE_CANDIDATES.find((candidate) => {
|
|
4603
4761
|
try {
|
|
4604
|
-
return
|
|
4762
|
+
return fs11.statSync(path12.join(datasetPath, candidate)).isFile();
|
|
4605
4763
|
} catch {
|
|
4606
4764
|
return false;
|
|
4607
4765
|
}
|
|
@@ -4610,7 +4768,7 @@ function isPersonaMemDatasetComplete(datasetPath) {
|
|
|
4610
4768
|
return false;
|
|
4611
4769
|
}
|
|
4612
4770
|
try {
|
|
4613
|
-
const rows = parseCsvRows(
|
|
4771
|
+
const rows = parseCsvRows(fs11.readFileSync(path12.join(datasetPath, datasetFile), "utf8"));
|
|
4614
4772
|
if (rows.length < 2) {
|
|
4615
4773
|
return false;
|
|
4616
4774
|
}
|
|
@@ -4625,7 +4783,7 @@ function isPersonaMemDatasetComplete(datasetPath) {
|
|
|
4625
4783
|
}
|
|
4626
4784
|
return historyPaths.every((relativePath) => {
|
|
4627
4785
|
const resolvedPath = resolveRealpathWithinDataset(datasetPath, relativePath);
|
|
4628
|
-
return resolvedPath !== null &&
|
|
4786
|
+
return resolvedPath !== null && fs11.statSync(resolvedPath).isFile();
|
|
4629
4787
|
});
|
|
4630
4788
|
} catch {
|
|
4631
4789
|
return false;
|
|
@@ -4633,7 +4791,7 @@ function isPersonaMemDatasetComplete(datasetPath) {
|
|
|
4633
4791
|
}
|
|
4634
4792
|
function hasDatasetFile(datasetPath, relativePath) {
|
|
4635
4793
|
try {
|
|
4636
|
-
return
|
|
4794
|
+
return fs11.statSync(path12.join(datasetPath, relativePath)).isFile();
|
|
4637
4795
|
} catch {
|
|
4638
4796
|
return false;
|
|
4639
4797
|
}
|
|
@@ -4653,10 +4811,10 @@ function memoryAgentBenchDatasetHasRecSysSamples(datasetPath) {
|
|
|
4653
4811
|
return candidateFilenames.some((filename) => {
|
|
4654
4812
|
const filePath = path12.join(datasetPath, filename);
|
|
4655
4813
|
try {
|
|
4656
|
-
if (!
|
|
4814
|
+
if (!fs11.statSync(filePath).isFile()) {
|
|
4657
4815
|
return false;
|
|
4658
4816
|
}
|
|
4659
|
-
const raw =
|
|
4817
|
+
const raw = fs11.readFileSync(filePath, "utf8");
|
|
4660
4818
|
return /"source"\s*:\s*"recsys[_-]/i.test(raw);
|
|
4661
4819
|
} catch {
|
|
4662
4820
|
return false;
|
|
@@ -4672,7 +4830,7 @@ function isMemoryAgentBenchDatasetComplete(datasetPath) {
|
|
|
4672
4830
|
function isDatasetDownloaded(datasetPath, benchmarkId) {
|
|
4673
4831
|
let stats;
|
|
4674
4832
|
try {
|
|
4675
|
-
stats =
|
|
4833
|
+
stats = fs11.statSync(datasetPath);
|
|
4676
4834
|
} catch {
|
|
4677
4835
|
return false;
|
|
4678
4836
|
}
|
|
@@ -4682,7 +4840,7 @@ function isDatasetDownloaded(datasetPath, benchmarkId) {
|
|
|
4682
4840
|
const marker = DOWNLOADED_DATASET_MARKERS[benchmarkId];
|
|
4683
4841
|
if (!marker) {
|
|
4684
4842
|
try {
|
|
4685
|
-
return
|
|
4843
|
+
return fs11.readdirSync(datasetPath).length > 0;
|
|
4686
4844
|
} catch {
|
|
4687
4845
|
return false;
|
|
4688
4846
|
}
|
|
@@ -4690,7 +4848,7 @@ function isDatasetDownloaded(datasetPath, benchmarkId) {
|
|
|
4690
4848
|
if (marker.allOf) {
|
|
4691
4849
|
const hasAllRequiredFiles = marker.allOf.every((name) => {
|
|
4692
4850
|
try {
|
|
4693
|
-
return
|
|
4851
|
+
return fs11.statSync(path12.join(datasetPath, name)).isFile();
|
|
4694
4852
|
} catch {
|
|
4695
4853
|
return false;
|
|
4696
4854
|
}
|
|
@@ -4702,7 +4860,7 @@ function isDatasetDownloaded(datasetPath, benchmarkId) {
|
|
|
4702
4860
|
if (marker.anyOf) {
|
|
4703
4861
|
const hasMarkerFile = marker.anyOf.some((name) => {
|
|
4704
4862
|
try {
|
|
4705
|
-
return
|
|
4863
|
+
return fs11.statSync(path12.join(datasetPath, name)).isFile();
|
|
4706
4864
|
} catch {
|
|
4707
4865
|
return false;
|
|
4708
4866
|
}
|
|
@@ -4720,7 +4878,7 @@ function isDatasetDownloaded(datasetPath, benchmarkId) {
|
|
|
4720
4878
|
}
|
|
4721
4879
|
if (marker.ext) {
|
|
4722
4880
|
try {
|
|
4723
|
-
return
|
|
4881
|
+
return fs11.readdirSync(datasetPath).some(
|
|
4724
4882
|
(name) => name.endsWith(marker.ext) && !marker.exclude?.includes(name)
|
|
4725
4883
|
);
|
|
4726
4884
|
} catch {
|
|
@@ -4732,7 +4890,7 @@ function isDatasetDownloaded(datasetPath, benchmarkId) {
|
|
|
4732
4890
|
async function launchBenchUi(resultsDir) {
|
|
4733
4891
|
const benchUiDir = path12.join(CLI_REPO_ROOT, "packages", "bench-ui");
|
|
4734
4892
|
const pnpmCmd = process.platform === "win32" ? "pnpm.cmd" : "pnpm";
|
|
4735
|
-
if (!
|
|
4893
|
+
if (!fs11.existsSync(path12.join(benchUiDir, "package.json"))) {
|
|
4736
4894
|
console.error("ERROR: @remnic/bench-ui is not available in this checkout.");
|
|
4737
4895
|
process.exit(1);
|
|
4738
4896
|
}
|
|
@@ -4770,13 +4928,13 @@ function listDownloadableBenchmarks() {
|
|
|
4770
4928
|
}
|
|
4771
4929
|
function resolveDatasetDownloadScriptPath() {
|
|
4772
4930
|
const bundled = path12.join(CLI_MODULE_DIR, "assets", "download-datasets.sh");
|
|
4773
|
-
if (
|
|
4931
|
+
if (fs11.existsSync(bundled)) {
|
|
4774
4932
|
return bundled;
|
|
4775
4933
|
}
|
|
4776
4934
|
return path12.join(CLI_REPO_ROOT, "evals", "scripts", "download-datasets.sh");
|
|
4777
4935
|
}
|
|
4778
4936
|
function isRepoCheckout() {
|
|
4779
|
-
return
|
|
4937
|
+
return fs11.existsSync(path12.join(CLI_REPO_ROOT, "pnpm-workspace.yaml")) && fs11.existsSync(path12.join(CLI_REPO_ROOT, "evals", "scripts", "download-datasets.sh"));
|
|
4780
4938
|
}
|
|
4781
4939
|
function runDatasetDownloadScript(scriptPath, benchmarkId, datasetRoot, jsonMode) {
|
|
4782
4940
|
const stdio = jsonMode ? ["inherit", process.stderr, "inherit"] : "inherit";
|
|
@@ -4848,6 +5006,8 @@ var __benchDatasetTestHooks = {
|
|
|
4848
5006
|
isDatasetDownloaded,
|
|
4849
5007
|
resolveBenchDatasetDir,
|
|
4850
5008
|
resolveDownloadedBenchDatasetDir,
|
|
5009
|
+
pairedAnswerReplayCacheForBenchmark,
|
|
5010
|
+
orderPairedLoCoMoWorkItemsForTest: orderPairedLoCoMoWorkItems,
|
|
4851
5011
|
buildPublishedBenchmarkOptionsForTest(benchmarkId, args, taskSelector) {
|
|
4852
5012
|
return buildPublishedBenchmarkOptions(benchmarkId, args, taskSelector);
|
|
4853
5013
|
},
|
|
@@ -4876,72 +5036,9 @@ var __benchDatasetTestHooks = {
|
|
|
4876
5036
|
taskSelector
|
|
4877
5037
|
);
|
|
4878
5038
|
},
|
|
4879
|
-
printBenchStatusLineForTest: printBenchStatusLine
|
|
5039
|
+
printBenchStatusLineForTest: printBenchStatusLine,
|
|
5040
|
+
clearPairedAnswerReplayCacheOnFailureForTest: clearPairedAnswerReplayCacheOnFailure
|
|
4880
5041
|
};
|
|
4881
|
-
function printBenchPackageSummary(result, outputPath, outputLabel = "Results saved") {
|
|
4882
|
-
console.log(`Benchmark: ${result.meta.benchmark}`);
|
|
4883
|
-
console.log(`Mode: ${result.meta.mode}`);
|
|
4884
|
-
if (result.config.runtimeProfile) {
|
|
4885
|
-
console.log(`Runtime profile: ${result.config.runtimeProfile}`);
|
|
4886
|
-
}
|
|
4887
|
-
console.log(`Tasks: ${result.results.tasks.length}`);
|
|
4888
|
-
console.log(`Mean query latency: ${result.cost.meanQueryLatencyMs.toFixed(1)}ms`);
|
|
4889
|
-
for (const [metric, aggregate] of Object.entries(result.results.aggregates).sort()) {
|
|
4890
|
-
console.log(` ${metric.padEnd(20)} ${aggregate.mean.toFixed(4)}`);
|
|
4891
|
-
}
|
|
4892
|
-
console.log(`${outputLabel}: ${outputPath}`);
|
|
4893
|
-
}
|
|
4894
|
-
function printBenchStatusLine(jsonMode, message) {
|
|
4895
|
-
if (jsonMode) {
|
|
4896
|
-
console.error(message);
|
|
4897
|
-
} else {
|
|
4898
|
-
console.log(message);
|
|
4899
|
-
}
|
|
4900
|
-
}
|
|
4901
|
-
function printStoredBenchResultSummary(result, summary) {
|
|
4902
|
-
printBenchPackageSummary(result, summary.path, "Stored result");
|
|
4903
|
-
console.log(`Run id: ${summary.id}`);
|
|
4904
|
-
}
|
|
4905
|
-
function printStoredBenchResultDetails(result, summary) {
|
|
4906
|
-
printStoredBenchResultSummary(result, summary);
|
|
4907
|
-
if (result.results.tasks.length === 0) {
|
|
4908
|
-
console.log("Tasks: none");
|
|
4909
|
-
return;
|
|
4910
|
-
}
|
|
4911
|
-
console.log("Task breakdown:");
|
|
4912
|
-
for (const task of result.results.tasks) {
|
|
4913
|
-
const scores = Object.entries(task.scores).sort(([left], [right]) => left.localeCompare(right)).map(([metric, value]) => `${metric}=${value.toFixed(4)}`).join(", ");
|
|
4914
|
-
console.log(
|
|
4915
|
-
` ${task.taskId}: ${task.latencyMs.toFixed(1)}ms${scores.length > 0 ? ` [${scores}]` : ""}`
|
|
4916
|
-
);
|
|
4917
|
-
}
|
|
4918
|
-
}
|
|
4919
|
-
function printBenchComparisonSummary(comparison, baseline, candidate) {
|
|
4920
|
-
console.log(`Benchmark: ${comparison.benchmark}`);
|
|
4921
|
-
console.log(`Baseline: ${baseline.id} (${baseline.path})`);
|
|
4922
|
-
console.log(`Candidate: ${candidate.id} (${candidate.path})`);
|
|
4923
|
-
console.log(`Verdict: ${comparison.verdict}`);
|
|
4924
|
-
const metrics = Object.entries(comparison.metricDeltas).sort(
|
|
4925
|
-
([left], [right]) => left.localeCompare(right)
|
|
4926
|
-
);
|
|
4927
|
-
if (metrics.length === 0) {
|
|
4928
|
-
console.log("No overlapping metrics were found between the two results.");
|
|
4929
|
-
return;
|
|
4930
|
-
}
|
|
4931
|
-
console.log("Metrics:");
|
|
4932
|
-
for (const [metric, delta] of metrics) {
|
|
4933
|
-
const percent = Number.isFinite(delta.percentChange) ? `${(delta.percentChange * 100).toFixed(2)}%` : delta.percentChange > 0 ? "+Infinity%" : "-Infinity%";
|
|
4934
|
-
const direction = delta.delta >= 0 ? "+" : "";
|
|
4935
|
-
console.log(
|
|
4936
|
-
` ${metric.padEnd(18)} ${delta.baseline.toFixed(4)} -> ${delta.candidate.toFixed(4)} (${direction}${delta.delta.toFixed(4)}, ${percent}, d=${delta.effectSize.cohensD.toFixed(3)} ${delta.effectSize.interpretation})`
|
|
4937
|
-
);
|
|
4938
|
-
if (delta.ciOnDelta) {
|
|
4939
|
-
console.log(
|
|
4940
|
-
` CI95 delta: [${delta.ciOnDelta.lower.toFixed(4)}, ${delta.ciOnDelta.upper.toFixed(4)}]`
|
|
4941
|
-
);
|
|
4942
|
-
}
|
|
4943
|
-
}
|
|
4944
|
-
}
|
|
4945
5042
|
async function compareBenchPackageResults(parsed) {
|
|
4946
5043
|
const refs = parsed.benchmarks;
|
|
4947
5044
|
if (refs.length !== 2) {
|
|
@@ -5150,8 +5247,8 @@ async function exportBenchPackageResult(parsed) {
|
|
|
5150
5247
|
...reportCardProvenance ? { reportCardProvenance } : {}
|
|
5151
5248
|
});
|
|
5152
5249
|
if (parsed.output) {
|
|
5153
|
-
|
|
5154
|
-
|
|
5250
|
+
fs11.mkdirSync(path12.dirname(parsed.output), { recursive: true });
|
|
5251
|
+
fs11.writeFileSync(parsed.output, rendered);
|
|
5155
5252
|
console.log(`Exported ${summary.id} as ${parsed.format} to ${parsed.output}`);
|
|
5156
5253
|
return;
|
|
5157
5254
|
}
|
|
@@ -5196,7 +5293,7 @@ async function manageBenchDatasets(parsed) {
|
|
|
5196
5293
|
process.exit(1);
|
|
5197
5294
|
}
|
|
5198
5295
|
const scriptPath = resolveDatasetDownloadScriptPath();
|
|
5199
|
-
if (!
|
|
5296
|
+
if (!fs11.existsSync(scriptPath)) {
|
|
5200
5297
|
console.error(`ERROR: dataset download script not found: ${scriptPath}`);
|
|
5201
5298
|
process.exit(1);
|
|
5202
5299
|
}
|
|
@@ -5396,7 +5493,7 @@ async function calibrateBenchJudges(parsed, rawArgs) {
|
|
|
5396
5493
|
);
|
|
5397
5494
|
process.exit(1);
|
|
5398
5495
|
}
|
|
5399
|
-
const sourceResultSha256 = createHash2("sha256").update(
|
|
5496
|
+
const sourceResultSha256 = createHash2("sha256").update(fs11.readFileSync(latest.path)).digest("hex");
|
|
5400
5497
|
const expandedManifestPath = expandTilde(manifestPath);
|
|
5401
5498
|
if (!bench.resolveLocalLabJudgeProviderConfig) {
|
|
5402
5499
|
console.error(
|
|
@@ -5705,16 +5802,23 @@ async function runBenchPublished(parsed) {
|
|
|
5705
5802
|
}
|
|
5706
5803
|
return;
|
|
5707
5804
|
}
|
|
5708
|
-
const runtimeProfiles = resolveBenchRunProfiles(parsed);
|
|
5709
5805
|
const benchmarkId = parsed.publishedName;
|
|
5806
|
+
const runtimeProfiles = orderPairedLoCoMoWorkItems(
|
|
5807
|
+
resolveBenchRunProfiles(parsed).map((runtimeProfile) => ({
|
|
5808
|
+
benchmarkId,
|
|
5809
|
+
runtimeProfile
|
|
5810
|
+
}))
|
|
5811
|
+
).map((item) => item.runtimeProfile);
|
|
5710
5812
|
const writtenPaths = [];
|
|
5813
|
+
const pairedAnswerReplayCache = benchmarkId === "locomo" && runtimeProfiles.includes("baseline") && runtimeProfiles.includes("real") ? /* @__PURE__ */ new Map() : void 0;
|
|
5711
5814
|
for (const runtimeProfile of runtimeProfiles) {
|
|
5712
5815
|
const result = await runBenchViaPackage(
|
|
5713
5816
|
parsed,
|
|
5714
5817
|
benchmarkId,
|
|
5715
5818
|
runtimeProfile,
|
|
5716
5819
|
void 0,
|
|
5717
|
-
taskSelector
|
|
5820
|
+
taskSelector,
|
|
5821
|
+
pairedAnswerReplayCache
|
|
5718
5822
|
);
|
|
5719
5823
|
if (!result.ok) {
|
|
5720
5824
|
console.error(
|
|
@@ -5804,7 +5908,7 @@ function loadPinnedLoCoMoTaskSelector(parsed) {
|
|
|
5804
5908
|
}
|
|
5805
5909
|
let decoded;
|
|
5806
5910
|
try {
|
|
5807
|
-
decoded = JSON.parse(
|
|
5911
|
+
decoded = JSON.parse(fs11.readFileSync(parsed.taskIdsFile, "utf8"));
|
|
5808
5912
|
} catch (error) {
|
|
5809
5913
|
throw new Error(
|
|
5810
5914
|
`Unable to read --task-ids-file ${parsed.taskIdsFile}: ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -5969,7 +6073,29 @@ async function preflightLocalLabEndpointsIfNeeded(benchModule, plan) {
|
|
|
5969
6073
|
);
|
|
5970
6074
|
}
|
|
5971
6075
|
}
|
|
5972
|
-
|
|
6076
|
+
function pairedAnswerReplayCacheForBenchmark(benchmarkId, pairedAnswerReplayCache) {
|
|
6077
|
+
return benchmarkId === "locomo" ? pairedAnswerReplayCache : void 0;
|
|
6078
|
+
}
|
|
6079
|
+
function clearPairedAnswerReplayCacheOnFailure(runtimeProfile, benchmarkId, pairedAnswerReplayCache) {
|
|
6080
|
+
if (runtimeProfile !== "baseline" || benchmarkId !== "locomo") return;
|
|
6081
|
+
pairedAnswerReplayCache?.clear();
|
|
6082
|
+
}
|
|
6083
|
+
function orderPairedLoCoMoWorkItems(workItems) {
|
|
6084
|
+
const baselineIndex = workItems.findIndex(
|
|
6085
|
+
(item) => item.benchmarkId === "locomo" && item.runtimeProfile === "baseline"
|
|
6086
|
+
);
|
|
6087
|
+
const realIndex = workItems.findIndex(
|
|
6088
|
+
(item) => item.benchmarkId === "locomo" && item.runtimeProfile === "real"
|
|
6089
|
+
);
|
|
6090
|
+
if (baselineIndex < 0 || realIndex < 0 || baselineIndex < realIndex) {
|
|
6091
|
+
return [...workItems];
|
|
6092
|
+
}
|
|
6093
|
+
const ordered = [...workItems];
|
|
6094
|
+
const [baseline] = ordered.splice(baselineIndex, 1);
|
|
6095
|
+
ordered.splice(realIndex, 0, baseline);
|
|
6096
|
+
return ordered;
|
|
6097
|
+
}
|
|
6098
|
+
async function runBenchViaPackage(parsed, benchmarkId, runtimeProfile, benchStatusPath, taskSelector, pairedAnswerReplayCache) {
|
|
5973
6099
|
const loaded = await tryLoadBenchModule();
|
|
5974
6100
|
if (!loaded) return { ok: false };
|
|
5975
6101
|
assertBenchModuleFreshForDevelopment();
|
|
@@ -6039,6 +6165,10 @@ async function runBenchViaPackage(parsed, benchmarkId, runtimeProfile, benchStat
|
|
|
6039
6165
|
if (benchmarkId === "memcorrect-v1" && parsed.adapter === "mcp") {
|
|
6040
6166
|
benchmarkOptions = { ...benchmarkOptions ?? {}, adapter: system };
|
|
6041
6167
|
}
|
|
6168
|
+
const locomoPairedAnswerReplayCache = pairedAnswerReplayCacheForBenchmark(
|
|
6169
|
+
benchmarkId,
|
|
6170
|
+
pairedAnswerReplayCache
|
|
6171
|
+
);
|
|
6042
6172
|
const result = await benchModule.runBenchmark(benchmarkId, {
|
|
6043
6173
|
mode: parsed.quick ? "quick" : "full",
|
|
6044
6174
|
datasetDir,
|
|
@@ -6055,6 +6185,7 @@ async function runBenchViaPackage(parsed, benchmarkId, runtimeProfile, benchStat
|
|
|
6055
6185
|
// Issue #1573 PR1: judge-result cache controls from the CLI flags.
|
|
6056
6186
|
...parsed.noJudgeCache ? { noJudgeCache: true } : {},
|
|
6057
6187
|
...parsed.judgeCacheDir ? { judgeCacheDir: parsed.judgeCacheDir } : {},
|
|
6188
|
+
...locomoPairedAnswerReplayCache ? { pairedAnswerReplayCache: locomoPairedAnswerReplayCache } : {},
|
|
6058
6189
|
...benchmarkOptions ? { benchmarkOptions } : {},
|
|
6059
6190
|
...amaBenchProtocol.judgeProtocol ? { amaBenchJudgeProtocol: amaBenchProtocol.judgeProtocol } : {},
|
|
6060
6191
|
...amaBenchProtocol.crossJudge ? { amaBenchCrossJudge: amaBenchProtocol.crossJudge } : {},
|
|
@@ -6092,6 +6223,11 @@ async function runBenchViaPackage(parsed, benchmarkId, runtimeProfile, benchStat
|
|
|
6092
6223
|
}
|
|
6093
6224
|
return { ok: true, writtenPath };
|
|
6094
6225
|
} catch (err) {
|
|
6226
|
+
clearPairedAnswerReplayCacheOnFailure(
|
|
6227
|
+
runtimeProfile,
|
|
6228
|
+
benchmarkId,
|
|
6229
|
+
pairedAnswerReplayCache
|
|
6230
|
+
);
|
|
6095
6231
|
if (partialTasks.length > 0) {
|
|
6096
6232
|
const remnicVersion = await benchModule.getRemnicVersion?.() ?? "unknown";
|
|
6097
6233
|
const partialResult = buildPartialBenchmarkResult(
|
|
@@ -6444,7 +6580,7 @@ function resolveBenchReproDatasetDir(datasetDir) {
|
|
|
6444
6580
|
return void 0;
|
|
6445
6581
|
}
|
|
6446
6582
|
try {
|
|
6447
|
-
return
|
|
6583
|
+
return fs11.realpathSync(datasetDir);
|
|
6448
6584
|
} catch {
|
|
6449
6585
|
return datasetDir;
|
|
6450
6586
|
}
|
|
@@ -6507,13 +6643,13 @@ function resolveConfigPath(cliPath) {
|
|
|
6507
6643
|
path12.join(resolveHomeDir(), ".config", "engram", "config.json")
|
|
6508
6644
|
];
|
|
6509
6645
|
for (const candidate of candidates) {
|
|
6510
|
-
if (
|
|
6646
|
+
if (fs11.existsSync(candidate)) return candidate;
|
|
6511
6647
|
}
|
|
6512
6648
|
return path12.join(resolveHomeDir(), ".config", "remnic", "config.json");
|
|
6513
6649
|
}
|
|
6514
6650
|
function resolveExistingBenchRemnicConfigPath(cliPath) {
|
|
6515
6651
|
const configPath = resolveConfigPath(cliPath);
|
|
6516
|
-
if (
|
|
6652
|
+
if (fs11.existsSync(configPath)) {
|
|
6517
6653
|
return configPath;
|
|
6518
6654
|
}
|
|
6519
6655
|
if (cliPath) {
|
|
@@ -6523,7 +6659,7 @@ function resolveExistingBenchRemnicConfigPath(cliPath) {
|
|
|
6523
6659
|
}
|
|
6524
6660
|
function resolveExistingBenchOpenclawConfigPath(cliPath) {
|
|
6525
6661
|
const configPath = resolveOpenclawConfigPath(cliPath);
|
|
6526
|
-
if (
|
|
6662
|
+
if (fs11.existsSync(configPath)) {
|
|
6527
6663
|
return configPath;
|
|
6528
6664
|
}
|
|
6529
6665
|
if (cliPath) {
|
|
@@ -6630,8 +6766,8 @@ function resolveMemoryDir() {
|
|
|
6630
6766
|
const envMemoryDir = readCompatEnv("REMNIC_MEMORY_DIR", "ENGRAM_MEMORY_DIR");
|
|
6631
6767
|
if (envMemoryDir) return normalizeMemoryDirPath(envMemoryDir);
|
|
6632
6768
|
const configPath = resolveConfigPath();
|
|
6633
|
-
const raw =
|
|
6634
|
-
const remnicCfg =
|
|
6769
|
+
const raw = fs11.existsSync(configPath) ? JSON.parse(fs11.readFileSync(configPath, "utf8")) : {};
|
|
6770
|
+
const remnicCfg = resolveRemnicConfigRecord4(raw);
|
|
6635
6771
|
if (typeof remnicCfg.memoryDir === "string" && remnicCfg.memoryDir.length > 0) {
|
|
6636
6772
|
return normalizeMemoryDirPath(remnicCfg.memoryDir);
|
|
6637
6773
|
}
|
|
@@ -6639,18 +6775,18 @@ function resolveMemoryDir() {
|
|
|
6639
6775
|
const standalonePath = path12.join(home, ".remnic", "memory");
|
|
6640
6776
|
const legacyStandalonePath = path12.join(home, ".engram", "memory");
|
|
6641
6777
|
const openclawPath = path12.join(home, ".openclaw", "workspace", "memory", "local");
|
|
6642
|
-
if (
|
|
6643
|
-
if (
|
|
6778
|
+
if (fs11.existsSync(standalonePath)) return standalonePath;
|
|
6779
|
+
if (fs11.existsSync(legacyStandalonePath)) return legacyStandalonePath;
|
|
6644
6780
|
return openclawPath;
|
|
6645
6781
|
})();
|
|
6646
6782
|
const manifestPath = getManifestPath();
|
|
6647
|
-
if (
|
|
6783
|
+
if (fs11.existsSync(manifestPath)) {
|
|
6648
6784
|
try {
|
|
6649
6785
|
const active = getActiveSpace();
|
|
6650
6786
|
if (active?.memoryDir) {
|
|
6651
6787
|
const activeMemoryDir = normalizeMemoryDirPath(active.memoryDir);
|
|
6652
|
-
if (!
|
|
6653
|
-
|
|
6788
|
+
if (!fs11.existsSync(activeMemoryDir)) {
|
|
6789
|
+
fs11.mkdirSync(activeMemoryDir, { recursive: true });
|
|
6654
6790
|
}
|
|
6655
6791
|
return activeMemoryDir;
|
|
6656
6792
|
}
|
|
@@ -6696,13 +6832,13 @@ function resolveOpenclawConfigPath(cliPath) {
|
|
|
6696
6832
|
const envPath = process.env.OPENCLAW_CONFIG_PATH || process.env.OPENCLAW_ENGRAM_CONFIG_PATH;
|
|
6697
6833
|
if (envPath) return path12.resolve(expandTilde(envPath));
|
|
6698
6834
|
for (const candidate of DEFAULT_OPENCLAW_CONFIG_PATHS_FOR_DOCTOR) {
|
|
6699
|
-
if (
|
|
6835
|
+
if (fs11.existsSync(candidate)) return candidate;
|
|
6700
6836
|
}
|
|
6701
6837
|
return path12.join(resolveHomeDir(), ".openclaw", "openclaw.json");
|
|
6702
6838
|
}
|
|
6703
6839
|
function readOpenclawConfig(configPath) {
|
|
6704
|
-
if (!
|
|
6705
|
-
const raw =
|
|
6840
|
+
if (!fs11.existsSync(configPath)) return {};
|
|
6841
|
+
const raw = fs11.readFileSync(configPath, "utf-8");
|
|
6706
6842
|
let parsed;
|
|
6707
6843
|
try {
|
|
6708
6844
|
parsed = JSON.parse(raw);
|
|
@@ -6801,14 +6937,14 @@ function formatOpenclawUpgradeStamp(now = /* @__PURE__ */ new Date()) {
|
|
|
6801
6937
|
return `${yyyy}${mm}${dd}-${hh}${min}${ss}`;
|
|
6802
6938
|
}
|
|
6803
6939
|
function backupPathIfPresent(sourcePath, backupPath) {
|
|
6804
|
-
if (!
|
|
6805
|
-
|
|
6806
|
-
|
|
6940
|
+
if (!fs11.existsSync(sourcePath)) return false;
|
|
6941
|
+
fs11.mkdirSync(path12.dirname(backupPath), { recursive: true });
|
|
6942
|
+
fs11.cpSync(sourcePath, backupPath, { recursive: true });
|
|
6807
6943
|
return true;
|
|
6808
6944
|
}
|
|
6809
6945
|
function assertDirectoryPathOrMissing(targetPath, label) {
|
|
6810
|
-
if (!
|
|
6811
|
-
const stat =
|
|
6946
|
+
if (!fs11.existsSync(targetPath)) return;
|
|
6947
|
+
const stat = fs11.statSync(targetPath);
|
|
6812
6948
|
if (!stat.isDirectory()) {
|
|
6813
6949
|
throw new Error(`${label} must be a directory when it already exists: ${targetPath}`);
|
|
6814
6950
|
}
|
|
@@ -6833,7 +6969,7 @@ var PublishedOpenclawPluginInstallError = class extends Error {
|
|
|
6833
6969
|
}
|
|
6834
6970
|
};
|
|
6835
6971
|
function installPublishedOpenclawPlugin(spec, pluginDir) {
|
|
6836
|
-
const tempRoot =
|
|
6972
|
+
const tempRoot = fs11.mkdtempSync(path12.join(os.tmpdir(), "remnic-openclaw-upgrade-"));
|
|
6837
6973
|
const stagedDir = `${pluginDir}.next-${process.pid}-${Date.now()}`;
|
|
6838
6974
|
const rollbackDir = `${pluginDir}.rollback-${process.pid}-${Date.now()}`;
|
|
6839
6975
|
let swapRollbackDir;
|
|
@@ -6849,16 +6985,16 @@ function installPublishedOpenclawPlugin(spec, pluginDir) {
|
|
|
6849
6985
|
throw new Error(`npm pack ${spec} did not return a tarball name`);
|
|
6850
6986
|
}
|
|
6851
6987
|
const unpackDir = path12.join(tempRoot, "unpacked");
|
|
6852
|
-
|
|
6988
|
+
fs11.mkdirSync(unpackDir, { recursive: true });
|
|
6853
6989
|
childProcess2.execFileSync("tar", ["-xzf", path12.join(tempRoot, tarballName), "-C", unpackDir], {
|
|
6854
6990
|
stdio: ["ignore", "pipe", "pipe"]
|
|
6855
6991
|
});
|
|
6856
6992
|
const packagedDir = path12.join(unpackDir, "package");
|
|
6857
|
-
if (!
|
|
6993
|
+
if (!fs11.existsSync(packagedDir)) {
|
|
6858
6994
|
throw new Error(`npm pack ${spec} did not contain a package/ directory`);
|
|
6859
6995
|
}
|
|
6860
|
-
|
|
6861
|
-
|
|
6996
|
+
fs11.rmSync(stagedDir, { recursive: true, force: true });
|
|
6997
|
+
fs11.cpSync(packagedDir, stagedDir, { recursive: true });
|
|
6862
6998
|
childProcess2.execFileSync("npm", ["install", "--omit=dev"], {
|
|
6863
6999
|
cwd: stagedDir,
|
|
6864
7000
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -6874,7 +7010,7 @@ function installPublishedOpenclawPlugin(spec, pluginDir) {
|
|
|
6874
7010
|
})();
|
|
6875
7011
|
swapRollbackDir = swapResult.rollbackDir;
|
|
6876
7012
|
const installedPackageJsonPath = path12.join(pluginDir, "package.json");
|
|
6877
|
-
const installedPackage =
|
|
7013
|
+
const installedPackage = fs11.existsSync(installedPackageJsonPath) ? JSON.parse(fs11.readFileSync(installedPackageJsonPath, "utf8")) : {};
|
|
6878
7014
|
return {
|
|
6879
7015
|
rollbackDir: swapRollbackDir,
|
|
6880
7016
|
version: typeof installedPackage.version === "string" ? installedPackage.version : void 0
|
|
@@ -6889,8 +7025,8 @@ function installPublishedOpenclawPlugin(spec, pluginDir) {
|
|
|
6889
7025
|
}
|
|
6890
7026
|
);
|
|
6891
7027
|
} finally {
|
|
6892
|
-
|
|
6893
|
-
|
|
7028
|
+
fs11.rmSync(stagedDir, { recursive: true, force: true });
|
|
7029
|
+
fs11.rmSync(tempRoot, { recursive: true, force: true });
|
|
6894
7030
|
}
|
|
6895
7031
|
}
|
|
6896
7032
|
function restartOpenclawGateway() {
|
|
@@ -6909,7 +7045,7 @@ function restartOpenclawGateway() {
|
|
|
6909
7045
|
}
|
|
6910
7046
|
function cmdInit() {
|
|
6911
7047
|
const configPath = path12.join(process.cwd(), "remnic.config.json");
|
|
6912
|
-
if (
|
|
7048
|
+
if (fs11.existsSync(configPath)) {
|
|
6913
7049
|
console.log(`Config already exists: ${configPath}`);
|
|
6914
7050
|
return;
|
|
6915
7051
|
}
|
|
@@ -6925,7 +7061,7 @@ function cmdInit() {
|
|
|
6925
7061
|
authToken: "${REMNIC_AUTH_TOKEN}"
|
|
6926
7062
|
}
|
|
6927
7063
|
};
|
|
6928
|
-
|
|
7064
|
+
fs11.writeFileSync(configPath, JSON.stringify(template, null, 2) + "\n");
|
|
6929
7065
|
console.log(`Created ${configPath}`);
|
|
6930
7066
|
console.log("\nSet these environment variables:");
|
|
6931
7067
|
console.log(" export OPENAI_API_KEY=sk-...");
|
|
@@ -6995,7 +7131,7 @@ async function cmdStatus(json) {
|
|
|
6995
7131
|
}
|
|
6996
7132
|
function oauthReadConfigRecord(configPath) {
|
|
6997
7133
|
try {
|
|
6998
|
-
const parsed = JSON.parse(
|
|
7134
|
+
const parsed = JSON.parse(fs11.readFileSync(configPath, "utf8"));
|
|
6999
7135
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
7000
7136
|
return parsed;
|
|
7001
7137
|
}
|
|
@@ -7411,10 +7547,10 @@ async function cmdQuery(queryText, json, explain) {
|
|
|
7411
7547
|
}
|
|
7412
7548
|
initLogger2();
|
|
7413
7549
|
const configPath = resolveConfigPath();
|
|
7414
|
-
const raw =
|
|
7415
|
-
const remnicCfg =
|
|
7416
|
-
const config =
|
|
7417
|
-
const orchestrator = new
|
|
7550
|
+
const raw = fs11.existsSync(configPath) ? JSON.parse(fs11.readFileSync(configPath, "utf8")) : {};
|
|
7551
|
+
const remnicCfg = resolveRemnicConfigRecord4(raw);
|
|
7552
|
+
const config = parseConfig4(remnicCfg);
|
|
7553
|
+
const orchestrator = new Orchestrator3(config);
|
|
7418
7554
|
await orchestrator.initialize();
|
|
7419
7555
|
const service = new EngramAccessService2(orchestrator);
|
|
7420
7556
|
const recallRequest = buildQueryRecallRequest(queryText);
|
|
@@ -7582,10 +7718,10 @@ async function cmdXray(rest) {
|
|
|
7582
7718
|
parseXrayCliOptions(rawQuery, options);
|
|
7583
7719
|
initLogger2();
|
|
7584
7720
|
const configPath = resolveConfigPath();
|
|
7585
|
-
const raw =
|
|
7586
|
-
const remnicCfg =
|
|
7587
|
-
const config =
|
|
7588
|
-
const orchestrator = new
|
|
7721
|
+
const raw = fs11.existsSync(configPath) ? JSON.parse(fs11.readFileSync(configPath, "utf8")) : {};
|
|
7722
|
+
const remnicCfg = resolveRemnicConfigRecord4(raw);
|
|
7723
|
+
const config = parseConfig4(remnicCfg);
|
|
7724
|
+
const orchestrator = new Orchestrator3(config);
|
|
7589
7725
|
await orchestrator.initialize();
|
|
7590
7726
|
await orchestrator.deferredReady;
|
|
7591
7727
|
const service = new EngramAccessService2(orchestrator);
|
|
@@ -7605,9 +7741,9 @@ async function cmdXray(rest) {
|
|
|
7605
7741
|
async function cmdVersions(rest) {
|
|
7606
7742
|
initLogger2();
|
|
7607
7743
|
const configPath = resolveConfigPath();
|
|
7608
|
-
const raw =
|
|
7609
|
-
const remnicCfg =
|
|
7610
|
-
const config =
|
|
7744
|
+
const raw = fs11.existsSync(configPath) ? JSON.parse(fs11.readFileSync(configPath, "utf8")) : {};
|
|
7745
|
+
const remnicCfg = resolveRemnicConfigRecord4(raw);
|
|
7746
|
+
const config = parseConfig4(remnicCfg);
|
|
7611
7747
|
if (!config.versioningEnabled) {
|
|
7612
7748
|
console.error("Page versioning is disabled (versioningEnabled = false).");
|
|
7613
7749
|
process.exit(1);
|
|
@@ -7721,9 +7857,9 @@ Options:
|
|
|
7721
7857
|
async function cmdEnrich(rest) {
|
|
7722
7858
|
initLogger2();
|
|
7723
7859
|
const configPath = resolveConfigPath();
|
|
7724
|
-
const raw =
|
|
7725
|
-
const remnicCfg =
|
|
7726
|
-
const config =
|
|
7860
|
+
const raw = fs11.existsSync(configPath) ? JSON.parse(fs11.readFileSync(configPath, "utf8")) : {};
|
|
7861
|
+
const remnicCfg = resolveRemnicConfigRecord4(raw);
|
|
7862
|
+
const config = parseConfig4(remnicCfg);
|
|
7727
7863
|
const subcommand = rest[0];
|
|
7728
7864
|
if (subcommand === "audit") {
|
|
7729
7865
|
const memoryDir2 = expandTilde(config.memoryDir);
|
|
@@ -7751,7 +7887,7 @@ async function cmdEnrich(rest) {
|
|
|
7751
7887
|
pipelineConfig2.providers = [
|
|
7752
7888
|
{ id: "web-search", enabled: true, costTier: "cheap" }
|
|
7753
7889
|
];
|
|
7754
|
-
const orchestrator2 = new
|
|
7890
|
+
const orchestrator2 = new Orchestrator3(config);
|
|
7755
7891
|
await orchestrator2.initialize();
|
|
7756
7892
|
await orchestrator2.deferredReady;
|
|
7757
7893
|
const searchBackend2 = orchestrator2.qmd;
|
|
@@ -7787,7 +7923,7 @@ Registered providers:`);
|
|
|
7787
7923
|
console.error("Usage: remnic enrich <entity-name> | --all | --dry-run | audit | providers");
|
|
7788
7924
|
process.exit(1);
|
|
7789
7925
|
}
|
|
7790
|
-
const orchestrator = new
|
|
7926
|
+
const orchestrator = new Orchestrator3(config);
|
|
7791
7927
|
await orchestrator.initialize();
|
|
7792
7928
|
await orchestrator.deferredReady;
|
|
7793
7929
|
const storage = await orchestrator.getStorage(config.defaultNamespace);
|
|
@@ -7966,9 +8102,9 @@ Shared with:
|
|
|
7966
8102
|
process.exit(1);
|
|
7967
8103
|
}
|
|
7968
8104
|
const configPath = resolveConfigPath();
|
|
7969
|
-
const raw =
|
|
7970
|
-
const remnicCfg =
|
|
7971
|
-
const config =
|
|
8105
|
+
const raw = fs11.existsSync(configPath) ? JSON.parse(fs11.readFileSync(configPath, "utf8")) : {};
|
|
8106
|
+
const remnicCfg = resolveRemnicConfigRecord4(raw);
|
|
8107
|
+
const config = parseConfig4(remnicCfg);
|
|
7972
8108
|
const memoryDir = expandTilde(
|
|
7973
8109
|
typeof memoryDirOverride === "string" && memoryDirOverride.length > 0 ? memoryDirOverride : config.memoryDir ?? resolveMemoryDir()
|
|
7974
8110
|
);
|
|
@@ -7983,9 +8119,9 @@ Shared with:
|
|
|
7983
8119
|
async function cmdExtensions(action, rest) {
|
|
7984
8120
|
initLogger2();
|
|
7985
8121
|
const configPath = resolveConfigPath();
|
|
7986
|
-
const raw =
|
|
7987
|
-
const remnicCfg =
|
|
7988
|
-
const config =
|
|
8122
|
+
const raw = fs11.existsSync(configPath) ? JSON.parse(fs11.readFileSync(configPath, "utf8")) : {};
|
|
8123
|
+
const remnicCfg = resolveRemnicConfigRecord4(raw);
|
|
8124
|
+
const config = parseConfig4(remnicCfg);
|
|
7989
8125
|
const root = resolveExtensionsRoot(config);
|
|
7990
8126
|
const noopLog = { warn: () => {
|
|
7991
8127
|
}, debug: () => {
|
|
@@ -8034,7 +8170,7 @@ Root: ${root}`);
|
|
|
8034
8170
|
const extensions = await discoverMemoryExtensions(root, warnLog);
|
|
8035
8171
|
let entries = [];
|
|
8036
8172
|
try {
|
|
8037
|
-
entries =
|
|
8173
|
+
entries = fs11.readdirSync(root);
|
|
8038
8174
|
} catch {
|
|
8039
8175
|
console.log(`Extensions root does not exist: ${root}`);
|
|
8040
8176
|
process.exitCode = 0;
|
|
@@ -8045,7 +8181,7 @@ Root: ${root}`);
|
|
|
8045
8181
|
for (const entry of entries) {
|
|
8046
8182
|
const entryPath = path12.join(root, entry);
|
|
8047
8183
|
try {
|
|
8048
|
-
if (!
|
|
8184
|
+
if (!fs11.statSync(entryPath).isDirectory()) continue;
|
|
8049
8185
|
} catch {
|
|
8050
8186
|
continue;
|
|
8051
8187
|
}
|
|
@@ -8077,9 +8213,9 @@ Root: ${root}`);
|
|
|
8077
8213
|
async function cmdBriefing(rest) {
|
|
8078
8214
|
initLogger2();
|
|
8079
8215
|
const configPath = resolveConfigPath();
|
|
8080
|
-
const raw =
|
|
8081
|
-
const remnicCfg =
|
|
8082
|
-
const config =
|
|
8216
|
+
const raw = fs11.existsSync(configPath) ? JSON.parse(fs11.readFileSync(configPath, "utf8")) : {};
|
|
8217
|
+
const remnicCfg = resolveRemnicConfigRecord4(raw);
|
|
8218
|
+
const config = parseConfig4(remnicCfg);
|
|
8083
8219
|
if (!config.briefing.enabled) {
|
|
8084
8220
|
console.error("Briefing is disabled in config (briefing.enabled = false).");
|
|
8085
8221
|
process.exit(1);
|
|
@@ -8132,7 +8268,7 @@ async function cmdBriefing(rest) {
|
|
|
8132
8268
|
process.exit(1);
|
|
8133
8269
|
}
|
|
8134
8270
|
const format = effectiveFormatFlag === "json" ? "json" : effectiveFormatFlag === "markdown" ? "markdown" : config.briefing.defaultFormat;
|
|
8135
|
-
const orchestrator = new
|
|
8271
|
+
const orchestrator = new Orchestrator3(config);
|
|
8136
8272
|
await orchestrator.initialize();
|
|
8137
8273
|
const storage = await orchestrator.getStorage(config.defaultNamespace);
|
|
8138
8274
|
const calendarSource = config.briefing.calendarSource ? new FileCalendarSource(config.briefing.calendarSource) : void 0;
|
|
@@ -8157,10 +8293,10 @@ async function cmdBriefing(rest) {
|
|
|
8157
8293
|
if (save) {
|
|
8158
8294
|
try {
|
|
8159
8295
|
const saveDir = resolveBriefingSaveDir(config.briefing.saveDir);
|
|
8160
|
-
|
|
8296
|
+
fs11.mkdirSync(saveDir, { recursive: true });
|
|
8161
8297
|
const filename = briefingFilename(new Date(result.window.to), format);
|
|
8162
8298
|
const filePath = path12.join(saveDir, filename);
|
|
8163
|
-
|
|
8299
|
+
fs11.writeFileSync(filePath, payload + (payload.endsWith("\n") ? "" : "\n"));
|
|
8164
8300
|
console.error(`Saved briefing: ${filePath}`);
|
|
8165
8301
|
} catch (err) {
|
|
8166
8302
|
console.error(`Failed to save briefing: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -8178,7 +8314,7 @@ async function cmdDoctor() {
|
|
|
8178
8314
|
detail: `${nodeVersion} (requires >= 22.12.0)`
|
|
8179
8315
|
});
|
|
8180
8316
|
const configPath = resolveConfigPath();
|
|
8181
|
-
const configExists =
|
|
8317
|
+
const configExists = fs11.existsSync(configPath);
|
|
8182
8318
|
checks.push({ name: "Config file", ok: configExists, detail: configPath });
|
|
8183
8319
|
let standaloneConfig;
|
|
8184
8320
|
let standaloneConfigError;
|
|
@@ -8186,11 +8322,11 @@ async function cmdDoctor() {
|
|
|
8186
8322
|
let configuredNs = { invalid: false };
|
|
8187
8323
|
if (configExists) {
|
|
8188
8324
|
try {
|
|
8189
|
-
const raw = JSON.parse(
|
|
8190
|
-
const remnicCfg =
|
|
8325
|
+
const raw = JSON.parse(fs11.readFileSync(configPath, "utf8"));
|
|
8326
|
+
const remnicCfg = resolveRemnicConfigRecord4(raw);
|
|
8191
8327
|
standaloneOpenaiApiKeyExplicitlyFalse = isOpenaiApiKeyDisabled(remnicCfg.openaiApiKey);
|
|
8192
8328
|
configuredNs = readConfiguredNamespace(remnicCfg);
|
|
8193
|
-
standaloneConfig =
|
|
8329
|
+
standaloneConfig = parseConfig4(remnicCfg);
|
|
8194
8330
|
} catch (err) {
|
|
8195
8331
|
standaloneConfigError = err instanceof Error ? err.message : String(err);
|
|
8196
8332
|
}
|
|
@@ -8199,10 +8335,10 @@ async function cmdDoctor() {
|
|
|
8199
8335
|
try {
|
|
8200
8336
|
memoryDir = resolveMemoryDir();
|
|
8201
8337
|
} catch {
|
|
8202
|
-
memoryDir =
|
|
8338
|
+
memoryDir = parseConfig4({}).memoryDir;
|
|
8203
8339
|
}
|
|
8204
8340
|
try {
|
|
8205
|
-
|
|
8341
|
+
fs11.mkdirSync(memoryDir, { recursive: true });
|
|
8206
8342
|
checks.push({ name: "Memory directory", ok: true, detail: memoryDir });
|
|
8207
8343
|
} catch {
|
|
8208
8344
|
checks.push({ name: "Memory directory", ok: false, detail: `cannot create ${memoryDir}` });
|
|
@@ -8231,7 +8367,7 @@ async function cmdDoctor() {
|
|
|
8231
8367
|
});
|
|
8232
8368
|
if (nsPolicyCheck) checks.push(nsPolicyCheck);
|
|
8233
8369
|
const openclawConfigPath = resolveOpenclawConfigPath();
|
|
8234
|
-
const openclawConfigExists =
|
|
8370
|
+
const openclawConfigExists = fs11.existsSync(openclawConfigPath);
|
|
8235
8371
|
let openclawConfig = {};
|
|
8236
8372
|
let openclawConfigValid = false;
|
|
8237
8373
|
let openclawPluginModeConfigured = false;
|
|
@@ -8239,7 +8375,7 @@ async function cmdDoctor() {
|
|
|
8239
8375
|
let activeOpenclawEntryConfig = null;
|
|
8240
8376
|
if (openclawConfigExists) {
|
|
8241
8377
|
try {
|
|
8242
|
-
const parsed = JSON.parse(
|
|
8378
|
+
const parsed = JSON.parse(fs11.readFileSync(openclawConfigPath, "utf-8"));
|
|
8243
8379
|
if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
|
|
8244
8380
|
openclawConfig = parsed;
|
|
8245
8381
|
openclawConfigValid = true;
|
|
@@ -8319,9 +8455,9 @@ async function cmdDoctor() {
|
|
|
8319
8455
|
let memDirOk = false;
|
|
8320
8456
|
let memDirDetail = `${resolvedMemDir} (not found)`;
|
|
8321
8457
|
let memDirRemediation = `Run \`remnic openclaw install --memory-dir "${resolvedMemDir}"\` to create the directory.`;
|
|
8322
|
-
if (
|
|
8458
|
+
if (fs11.existsSync(resolvedMemDir)) {
|
|
8323
8459
|
try {
|
|
8324
|
-
const stat =
|
|
8460
|
+
const stat = fs11.statSync(resolvedMemDir);
|
|
8325
8461
|
if (stat.isDirectory()) {
|
|
8326
8462
|
memDirOk = true;
|
|
8327
8463
|
memDirDetail = resolvedMemDir;
|
|
@@ -8463,12 +8599,12 @@ async function cmdDoctor() {
|
|
|
8463
8599
|
}
|
|
8464
8600
|
function cmdConfig() {
|
|
8465
8601
|
const configPath = resolveConfigPath();
|
|
8466
|
-
if (!
|
|
8602
|
+
if (!fs11.existsSync(configPath)) {
|
|
8467
8603
|
console.log("No config file found. Run `remnic init` to create one.");
|
|
8468
8604
|
return;
|
|
8469
8605
|
}
|
|
8470
8606
|
console.log(`Config: ${configPath}`);
|
|
8471
|
-
const rawConfig =
|
|
8607
|
+
const rawConfig = fs11.readFileSync(configPath, "utf8");
|
|
8472
8608
|
const redacted = rawConfig.replace(
|
|
8473
8609
|
/("(?:openaiApiKey|localLlmApiKey|authToken|apiKey|remoteSearchApiKey|meilisearchApiKey|opikApiKey)"\s*:\s*")([^"]*)(")/g,
|
|
8474
8610
|
"$1[REDACTED]$3"
|
|
@@ -8576,9 +8712,9 @@ async function cmdReview(action, rest) {
|
|
|
8576
8712
|
const configPath = resolveConfigPath();
|
|
8577
8713
|
let tombstonesConfig = null;
|
|
8578
8714
|
try {
|
|
8579
|
-
const rawCfg =
|
|
8580
|
-
const remnicCfg =
|
|
8581
|
-
const config =
|
|
8715
|
+
const rawCfg = fs11.existsSync(configPath) ? JSON.parse(fs11.readFileSync(configPath, "utf8")) : {};
|
|
8716
|
+
const remnicCfg = resolveRemnicConfigRecord4(rawCfg);
|
|
8717
|
+
const config = parseConfig4(remnicCfg);
|
|
8582
8718
|
tombstonesConfig = {
|
|
8583
8719
|
enabled: config.tombstonesEnabled,
|
|
8584
8720
|
semanticMatch: config.tombstonesSemanticMatch,
|
|
@@ -9329,7 +9465,7 @@ async function pushOfflineFileContent(args) {
|
|
|
9329
9465
|
}
|
|
9330
9466
|
async function pushOfflineFileContentFromChunkReader(args) {
|
|
9331
9467
|
const filePath = resolveOfflineDirectHydrationPath(args.memoryDir, args.file.path);
|
|
9332
|
-
const stat =
|
|
9468
|
+
const stat = fs11.statSync(filePath);
|
|
9333
9469
|
if (stat.mtimeMs !== args.file.mtimeMs) {
|
|
9334
9470
|
throw new Error(`local file changed while pushing offline content: ${args.file.path}`);
|
|
9335
9471
|
}
|
|
@@ -9820,7 +9956,7 @@ function advanceOfflineBaseFilesForSuccessfulPush(options) {
|
|
|
9820
9956
|
return [...next.values()].sort((left, right) => left.path.localeCompare(right.path));
|
|
9821
9957
|
}
|
|
9822
9958
|
async function runOfflineSyncOnce(options) {
|
|
9823
|
-
|
|
9959
|
+
fs11.mkdirSync(options.memoryDir, { recursive: true });
|
|
9824
9960
|
let activeStatePath = options.statePath;
|
|
9825
9961
|
let priorState = await readOfflineSyncState(activeStatePath);
|
|
9826
9962
|
let syncNamespace = options.namespace ?? priorState?.namespace;
|
|
@@ -10446,7 +10582,7 @@ Environment fallbacks:
|
|
|
10446
10582
|
const configPath = resolveConfigPath();
|
|
10447
10583
|
let config;
|
|
10448
10584
|
try {
|
|
10449
|
-
const rawConfig =
|
|
10585
|
+
const rawConfig = fs11.existsSync(configPath) ? JSON.parse(fs11.readFileSync(configPath, "utf8")) : {};
|
|
10450
10586
|
config = parseConfigQuietly(pickOfflineConfigRecord(rawConfig));
|
|
10451
10587
|
} catch {
|
|
10452
10588
|
throw new Error(
|
|
@@ -10461,7 +10597,7 @@ Environment fallbacks:
|
|
|
10461
10597
|
const statePath = statePathExplicit ? path12.resolve(expandTilde(stateOverride)) : remoteUrl !== void 0 ? defaultOfflineSyncStatePath(memoryDir, remoteUrl, namespace) : void 0;
|
|
10462
10598
|
if (action === "prepare") {
|
|
10463
10599
|
if (!remoteUrl || !token || !statePath) throw new Error("offline prepare requires remote URL and token");
|
|
10464
|
-
|
|
10600
|
+
fs11.mkdirSync(memoryDir, { recursive: true });
|
|
10465
10601
|
const remoteSnapshot = await fetchOfflineSnapshot({
|
|
10466
10602
|
remoteUrl,
|
|
10467
10603
|
token,
|
|
@@ -10559,7 +10695,7 @@ Environment fallbacks:
|
|
|
10559
10695
|
return;
|
|
10560
10696
|
}
|
|
10561
10697
|
if (action === "status") {
|
|
10562
|
-
|
|
10698
|
+
fs11.mkdirSync(memoryDir, { recursive: true });
|
|
10563
10699
|
const state = statePath ? await readOfflineSyncState(statePath) : null;
|
|
10564
10700
|
if (state && remoteUrl && statePath) {
|
|
10565
10701
|
assertOfflineStateMatches({
|
|
@@ -10697,7 +10833,7 @@ function cmdDedup(json) {
|
|
|
10697
10833
|
function readInstalledConnectorConfig(configPath, fallback) {
|
|
10698
10834
|
if (!configPath) return fallback;
|
|
10699
10835
|
try {
|
|
10700
|
-
const parsed = JSON.parse(
|
|
10836
|
+
const parsed = JSON.parse(fs11.readFileSync(configPath, "utf8"));
|
|
10701
10837
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return fallback;
|
|
10702
10838
|
const { token: _token, ...config } = parsed;
|
|
10703
10839
|
return config;
|
|
@@ -10875,7 +11011,7 @@ async function cmdConnectors(action, rest, json) {
|
|
|
10875
11011
|
const pub = factory();
|
|
10876
11012
|
const available = await pub.isHostAvailable();
|
|
10877
11013
|
const extRoot = available ? await pub.resolveExtensionRoot() : "(host not installed)";
|
|
10878
|
-
const extensionExists = available && extRoot ?
|
|
11014
|
+
const extensionExists = available && extRoot ? fs11.existsSync(extRoot) : false;
|
|
10879
11015
|
publisherChecks.push({
|
|
10880
11016
|
name: `Publisher: ${targetHostId}`,
|
|
10881
11017
|
ok: !available || extensionExists,
|
|
@@ -10949,7 +11085,7 @@ async function cmdConnectors(action, rest, json) {
|
|
|
10949
11085
|
let connectorsCfg;
|
|
10950
11086
|
const configPath = resolveConfigPath();
|
|
10951
11087
|
try {
|
|
10952
|
-
const raw =
|
|
11088
|
+
const raw = fs11.existsSync(configPath) ? JSON.parse(fs11.readFileSync(configPath, "utf8")) : {};
|
|
10953
11089
|
connectorsCfg = parseConfigQuietly(raw).connectors;
|
|
10954
11090
|
} catch {
|
|
10955
11091
|
process.stderr.write(
|
|
@@ -11025,10 +11161,10 @@ async function cmdConnectors(action, rest, json) {
|
|
|
11025
11161
|
}
|
|
11026
11162
|
initLogger2();
|
|
11027
11163
|
const configPath = resolveConfigPath();
|
|
11028
|
-
const raw =
|
|
11029
|
-
const remnicCfg =
|
|
11030
|
-
const config =
|
|
11031
|
-
const orchestrator = new
|
|
11164
|
+
const raw = fs11.existsSync(configPath) ? JSON.parse(fs11.readFileSync(configPath, "utf8")) : {};
|
|
11165
|
+
const remnicCfg = resolveRemnicConfigRecord4(raw);
|
|
11166
|
+
const config = parseConfig4(remnicCfg);
|
|
11167
|
+
const orchestrator = new Orchestrator3(config);
|
|
11032
11168
|
try {
|
|
11033
11169
|
await orchestrator.initialize();
|
|
11034
11170
|
await orchestrator.deferredReady;
|
|
@@ -11150,9 +11286,9 @@ async function cmdConnectorsMarketplace(subAction, rest, json) {
|
|
|
11150
11286
|
console.error(`connectors marketplace: ${err instanceof Error ? err.message : String(err)}`);
|
|
11151
11287
|
process.exit(1);
|
|
11152
11288
|
}
|
|
11153
|
-
const rawConfig =
|
|
11154
|
-
const pluginConfig =
|
|
11155
|
-
const config =
|
|
11289
|
+
const rawConfig = fs11.existsSync(configPath) ? JSON.parse(fs11.readFileSync(configPath, "utf8")) : {};
|
|
11290
|
+
const pluginConfig = resolveRemnicConfigRecord4(rawConfig);
|
|
11291
|
+
const config = parseConfig4(pluginConfig);
|
|
11156
11292
|
if (subAction === "generate") {
|
|
11157
11293
|
let outputDir;
|
|
11158
11294
|
try {
|
|
@@ -11172,13 +11308,13 @@ async function cmdConnectorsMarketplace(subAction, rest, json) {
|
|
|
11172
11308
|
} else if (subAction === "validate") {
|
|
11173
11309
|
const targetPath = rest.filter((a) => !a.startsWith("--"))[0] ?? path12.join(process.cwd(), "marketplace.json");
|
|
11174
11310
|
const resolved = path12.resolve(targetPath);
|
|
11175
|
-
if (!
|
|
11311
|
+
if (!fs11.existsSync(resolved)) {
|
|
11176
11312
|
console.error(`File not found: ${resolved}`);
|
|
11177
11313
|
process.exit(1);
|
|
11178
11314
|
}
|
|
11179
11315
|
let parsed;
|
|
11180
11316
|
try {
|
|
11181
|
-
parsed = JSON.parse(
|
|
11317
|
+
parsed = JSON.parse(fs11.readFileSync(resolved, "utf8"));
|
|
11182
11318
|
} catch {
|
|
11183
11319
|
console.error(`Invalid JSON in ${resolved}`);
|
|
11184
11320
|
process.exit(1);
|
|
@@ -11379,10 +11515,10 @@ async function cmdSpace(action, rest, json) {
|
|
|
11379
11515
|
async function cmdLegacyBenchmark(action, rest, json) {
|
|
11380
11516
|
initLogger2();
|
|
11381
11517
|
const configPath = resolveConfigPath();
|
|
11382
|
-
const raw =
|
|
11383
|
-
const remnicCfg =
|
|
11384
|
-
const config =
|
|
11385
|
-
const orchestrator = new
|
|
11518
|
+
const raw = fs11.existsSync(configPath) ? JSON.parse(fs11.readFileSync(configPath, "utf8")) : {};
|
|
11519
|
+
const remnicCfg = resolveRemnicConfigRecord4(raw);
|
|
11520
|
+
const config = parseConfig4(remnicCfg);
|
|
11521
|
+
const orchestrator = new Orchestrator3(config);
|
|
11386
11522
|
const service = new EngramAccessService2(orchestrator);
|
|
11387
11523
|
const { runBenchSuite, loadBaseline, checkRegression } = await loadBenchModule();
|
|
11388
11524
|
const benchConfig = {
|
|
@@ -11623,8 +11759,13 @@ async function cmdBench(rest) {
|
|
|
11623
11759
|
} catch {
|
|
11624
11760
|
}
|
|
11625
11761
|
const writtenPaths = [];
|
|
11762
|
+
const pairedAnswerReplayCache = selectedWorkItems.some(
|
|
11763
|
+
(item) => item.benchmarkId === "locomo" && item.runtimeProfile === "baseline"
|
|
11764
|
+
) && selectedWorkItems.some(
|
|
11765
|
+
(item) => item.benchmarkId === "locomo" && item.runtimeProfile === "real"
|
|
11766
|
+
) ? /* @__PURE__ */ new Map() : void 0;
|
|
11626
11767
|
try {
|
|
11627
|
-
for (const { benchmarkId, runtimeProfile } of selectedWorkItems) {
|
|
11768
|
+
for (const { benchmarkId, runtimeProfile } of orderPairedLoCoMoWorkItems(selectedWorkItems)) {
|
|
11628
11769
|
const statusId = runtimeProfiles.length > 1 ? `${benchmarkId} [${runtimeProfile}]` : benchmarkId;
|
|
11629
11770
|
try {
|
|
11630
11771
|
await updateBenchmarkStarted(benchStatusPath, statusId);
|
|
@@ -11636,7 +11777,8 @@ async function cmdBench(rest) {
|
|
|
11636
11777
|
benchmarkId,
|
|
11637
11778
|
runtimeProfile,
|
|
11638
11779
|
benchStatusPath,
|
|
11639
|
-
taskSelector
|
|
11780
|
+
taskSelector,
|
|
11781
|
+
pairedAnswerReplayCache
|
|
11640
11782
|
);
|
|
11641
11783
|
if (handledByPackage.ok) {
|
|
11642
11784
|
if (handledByPackage.writtenPath) {
|
|
@@ -11772,7 +11914,7 @@ function readPid() {
|
|
|
11772
11914
|
function inferPort() {
|
|
11773
11915
|
try {
|
|
11774
11916
|
const configPath = resolveConfigPath();
|
|
11775
|
-
const raw = JSON.parse(
|
|
11917
|
+
const raw = JSON.parse(fs11.readFileSync(configPath, "utf8"));
|
|
11776
11918
|
return raw.server?.port ?? 4318;
|
|
11777
11919
|
} catch {
|
|
11778
11920
|
return 4318;
|
|
@@ -11867,13 +12009,13 @@ function daemonInstall() {
|
|
|
11867
12009
|
process.exit(1);
|
|
11868
12010
|
}
|
|
11869
12011
|
const vars = { HOME: home, NODE_PATH: nodePath, REMNIC_SERVER_BIN: serverBin };
|
|
11870
|
-
|
|
12012
|
+
fs11.mkdirSync(LOGS_DIR, { recursive: true });
|
|
11871
12013
|
if (isMacOS()) {
|
|
11872
12014
|
const templatePath = path12.resolve(import.meta.dirname, "../templates/launchd/ai.remnic.daemon.plist");
|
|
11873
|
-
const template =
|
|
12015
|
+
const template = fs11.readFileSync(templatePath, "utf8");
|
|
11874
12016
|
const plist = renderTemplate(template, vars);
|
|
11875
|
-
|
|
11876
|
-
|
|
12017
|
+
fs11.mkdirSync(path12.dirname(LAUNCHD_PLIST_PATH), { recursive: true });
|
|
12018
|
+
fs11.writeFileSync(LAUNCHD_PLIST_PATH, plist);
|
|
11877
12019
|
try {
|
|
11878
12020
|
launchdLoadPlist(LAUNCHD_PLIST_PATH);
|
|
11879
12021
|
} catch (err) {
|
|
@@ -11890,10 +12032,10 @@ function daemonInstall() {
|
|
|
11890
12032
|
console.log(` Logs: ${LOGS_DIR}/daemon.log`);
|
|
11891
12033
|
} else if (isLinux()) {
|
|
11892
12034
|
const templatePath = path12.resolve(import.meta.dirname, "../templates/systemd/remnic.service");
|
|
11893
|
-
const template =
|
|
12035
|
+
const template = fs11.readFileSync(templatePath, "utf8");
|
|
11894
12036
|
const unit = renderTemplate(template, vars);
|
|
11895
|
-
|
|
11896
|
-
|
|
12037
|
+
fs11.mkdirSync(path12.dirname(SYSTEMD_UNIT_PATH), { recursive: true });
|
|
12038
|
+
fs11.writeFileSync(SYSTEMD_UNIT_PATH, unit);
|
|
11897
12039
|
try {
|
|
11898
12040
|
childProcess2.execSync("systemctl --user daemon-reload", { stdio: "pipe" });
|
|
11899
12041
|
} catch (err) {
|
|
@@ -11929,7 +12071,7 @@ function daemonUninstall() {
|
|
|
11929
12071
|
} catch {
|
|
11930
12072
|
}
|
|
11931
12073
|
try {
|
|
11932
|
-
|
|
12074
|
+
fs11.unlinkSync(plistPath);
|
|
11933
12075
|
removed = true;
|
|
11934
12076
|
console.log(`Removed launchd service: ${plistPath}`);
|
|
11935
12077
|
} catch {
|
|
@@ -11949,7 +12091,7 @@ function daemonUninstall() {
|
|
|
11949
12091
|
let removed = false;
|
|
11950
12092
|
for (const unitPath of SYSTEMD_UNIT_PATHS) {
|
|
11951
12093
|
try {
|
|
11952
|
-
|
|
12094
|
+
fs11.unlinkSync(unitPath);
|
|
11953
12095
|
removed = true;
|
|
11954
12096
|
console.log(`Removed systemd service: ${unitPath}`);
|
|
11955
12097
|
} catch {
|
|
@@ -12016,13 +12158,13 @@ async function daemonStatus() {
|
|
|
12016
12158
|
console.log(` Port: ${port}`);
|
|
12017
12159
|
console.log(` Service: ${serviceInstalled ? "installed" : "not installed"}`);
|
|
12018
12160
|
console.log(` Platform: ${process.platform}`);
|
|
12019
|
-
console.log(` PID file: ${
|
|
12020
|
-
console.log(` Log file: ${
|
|
12161
|
+
console.log(` PID file: ${fs11.existsSync(PID_FILE) ? PID_FILE : LEGACY_PID_FILE}`);
|
|
12162
|
+
console.log(` Log file: ${fs11.existsSync(LOG_FILE) ? LOG_FILE : LEGACY_LOG_FILE}`);
|
|
12021
12163
|
try {
|
|
12022
12164
|
const configPath = resolveConfigPath();
|
|
12023
|
-
const raw =
|
|
12024
|
-
const remnicCfg =
|
|
12025
|
-
const config =
|
|
12165
|
+
const raw = fs11.existsSync(configPath) ? JSON.parse(fs11.readFileSync(configPath, "utf8")) : {};
|
|
12166
|
+
const remnicCfg = resolveRemnicConfigRecord4(raw);
|
|
12167
|
+
const config = parseConfig4(remnicCfg);
|
|
12026
12168
|
const extRoot = resolveExtensionsRoot(config);
|
|
12027
12169
|
const noopLog = { warn: () => {
|
|
12028
12170
|
}, debug: () => {
|
|
@@ -12061,9 +12203,9 @@ function daemonStart() {
|
|
|
12061
12203
|
return;
|
|
12062
12204
|
}
|
|
12063
12205
|
}
|
|
12064
|
-
|
|
12065
|
-
|
|
12066
|
-
const logStream =
|
|
12206
|
+
fs11.mkdirSync(PID_DIR, { recursive: true });
|
|
12207
|
+
fs11.mkdirSync(LOGS_DIR, { recursive: true });
|
|
12208
|
+
const logStream = fs11.openSync(LOG_FILE, "a");
|
|
12067
12209
|
const serverBin = resolveServerBin();
|
|
12068
12210
|
const isSource = serverBin.endsWith(".ts");
|
|
12069
12211
|
let cmd;
|
|
@@ -12085,7 +12227,7 @@ function daemonStart() {
|
|
|
12085
12227
|
}
|
|
12086
12228
|
});
|
|
12087
12229
|
child.unref();
|
|
12088
|
-
|
|
12230
|
+
fs11.writeFileSync(PID_FILE, String(child.pid));
|
|
12089
12231
|
console.log(`Started remnic server (pid ${child.pid})`);
|
|
12090
12232
|
console.log(` Log: ${LOG_FILE}`);
|
|
12091
12233
|
}
|
|
@@ -12119,11 +12261,11 @@ function daemonStop() {
|
|
|
12119
12261
|
console.log("Process not found (cleaning up PID file)");
|
|
12120
12262
|
}
|
|
12121
12263
|
try {
|
|
12122
|
-
|
|
12264
|
+
fs11.unlinkSync(PID_FILE);
|
|
12123
12265
|
} catch {
|
|
12124
12266
|
}
|
|
12125
12267
|
try {
|
|
12126
|
-
|
|
12268
|
+
fs11.unlinkSync(LEGACY_PID_FILE);
|
|
12127
12269
|
} catch {
|
|
12128
12270
|
}
|
|
12129
12271
|
}
|
|
@@ -12251,9 +12393,9 @@ async function promptYesNo(question, defaultYes = true) {
|
|
|
12251
12393
|
async function cmdBinary(rest) {
|
|
12252
12394
|
initLogger2();
|
|
12253
12395
|
const configPath = resolveConfigPath();
|
|
12254
|
-
const raw =
|
|
12255
|
-
const remnicCfg =
|
|
12256
|
-
const config =
|
|
12396
|
+
const raw = fs11.existsSync(configPath) ? JSON.parse(fs11.readFileSync(configPath, "utf8")) : {};
|
|
12397
|
+
const remnicCfg = resolveRemnicConfigRecord4(raw);
|
|
12398
|
+
const config = parseConfig4(remnicCfg);
|
|
12257
12399
|
const memoryDir = resolveMemoryDir();
|
|
12258
12400
|
const blConfig = {
|
|
12259
12401
|
enabled: config.binaryLifecycleEnabled,
|
|
@@ -12442,7 +12584,7 @@ async function cmdOpenclawInstall(opts) {
|
|
|
12442
12584
|
} else if (slotIsActiveLegacy) {
|
|
12443
12585
|
changes.push(` Slot left as "${REMNIC_OPENCLAW_LEGACY_PLUGIN_ID}" \u2014 re-run with --yes to activate the new entry`);
|
|
12444
12586
|
}
|
|
12445
|
-
if (!
|
|
12587
|
+
if (!fs11.existsSync(memoryDir)) changes.push(`+ Will create memory directory: ${memoryDir}`);
|
|
12446
12588
|
if (hasLegacy && migrateLegacy) {
|
|
12447
12589
|
changes.push(`~ Legacy '${REMNIC_OPENCLAW_LEGACY_PLUGIN_ID}' entry retained (safe to remove after verifying hooks fire)`);
|
|
12448
12590
|
}
|
|
@@ -12462,8 +12604,8 @@ async function cmdOpenclawInstall(opts) {
|
|
|
12462
12604
|
Resulting plugins.slots.memory: ${dryRunPlugins.slots?.memory ?? "(unset)"}`);
|
|
12463
12605
|
return;
|
|
12464
12606
|
}
|
|
12465
|
-
if (
|
|
12466
|
-
const st =
|
|
12607
|
+
if (fs11.existsSync(memoryDir)) {
|
|
12608
|
+
const st = fs11.statSync(memoryDir);
|
|
12467
12609
|
if (!st.isDirectory()) {
|
|
12468
12610
|
throw new Error(
|
|
12469
12611
|
`Cannot use ${memoryDir} as the memory directory \u2014 a file already exists at that path.
|
|
@@ -12471,12 +12613,12 @@ Remove it first and re-run, or choose a different path with --memory-dir.`
|
|
|
12471
12613
|
);
|
|
12472
12614
|
}
|
|
12473
12615
|
} else {
|
|
12474
|
-
|
|
12616
|
+
fs11.mkdirSync(memoryDir, { recursive: true });
|
|
12475
12617
|
console.log(`Created memory directory: ${memoryDir}`);
|
|
12476
12618
|
}
|
|
12477
12619
|
const configDir = path12.dirname(configPath);
|
|
12478
|
-
if (!
|
|
12479
|
-
|
|
12620
|
+
if (!fs11.existsSync(configDir)) {
|
|
12621
|
+
fs11.mkdirSync(configDir, { recursive: true });
|
|
12480
12622
|
}
|
|
12481
12623
|
atomicWriteFileSync(configPath, JSON.stringify(updatedConfig, null, 2) + "\n");
|
|
12482
12624
|
console.log("\nDone! Summary of changes:");
|
|
@@ -12648,15 +12790,15 @@ async function cmdOpenclawMigrateEngram(opts) {
|
|
|
12648
12790
|
}
|
|
12649
12791
|
function createOpenclawUpgradeBackupDir() {
|
|
12650
12792
|
const backupsRoot = path12.join(resolveHomeDir(), ".openclaw", "backups");
|
|
12651
|
-
|
|
12652
|
-
return
|
|
12793
|
+
fs11.mkdirSync(backupsRoot, { recursive: true });
|
|
12794
|
+
return fs11.mkdtempSync(path12.join(backupsRoot, `remnic-openclaw-upgrade-${formatOpenclawUpgradeStamp()}-`));
|
|
12653
12795
|
}
|
|
12654
12796
|
async function cmdTaxonomy(rest) {
|
|
12655
12797
|
initLogger2();
|
|
12656
12798
|
const configPath = resolveConfigPath();
|
|
12657
|
-
const raw =
|
|
12658
|
-
const remnicCfg =
|
|
12659
|
-
const config =
|
|
12799
|
+
const raw = fs11.existsSync(configPath) ? JSON.parse(fs11.readFileSync(configPath, "utf8")) : {};
|
|
12800
|
+
const remnicCfg = resolveRemnicConfigRecord4(raw);
|
|
12801
|
+
const config = parseConfig4(remnicCfg);
|
|
12660
12802
|
if (!config.taxonomyEnabled) {
|
|
12661
12803
|
console.error(
|
|
12662
12804
|
"Taxonomy is disabled in config (taxonomyEnabled = false). Enable it to use taxonomy commands."
|
|
@@ -12692,8 +12834,8 @@ async function cmdTaxonomy(rest) {
|
|
|
12692
12834
|
console.log(doc);
|
|
12693
12835
|
if (config.taxonomyAutoGenResolver) {
|
|
12694
12836
|
const resolverPath = path12.join(config.memoryDir, ".taxonomy", "RESOLVER.md");
|
|
12695
|
-
|
|
12696
|
-
|
|
12837
|
+
fs11.mkdirSync(path12.dirname(resolverPath), { recursive: true });
|
|
12838
|
+
fs11.writeFileSync(resolverPath, doc);
|
|
12697
12839
|
console.error(`Written: ${resolverPath}`);
|
|
12698
12840
|
}
|
|
12699
12841
|
break;
|
|
@@ -12739,7 +12881,7 @@ async function cmdTaxonomy(rest) {
|
|
|
12739
12881
|
if (config.taxonomyAutoGenResolver) {
|
|
12740
12882
|
const doc = generateResolverDocument(taxonomy);
|
|
12741
12883
|
const resolverPath = path12.join(config.memoryDir, ".taxonomy", "RESOLVER.md");
|
|
12742
|
-
|
|
12884
|
+
fs11.writeFileSync(resolverPath, doc);
|
|
12743
12885
|
console.error(`Regenerated: ${resolverPath}`);
|
|
12744
12886
|
}
|
|
12745
12887
|
break;
|
|
@@ -12770,7 +12912,7 @@ async function cmdTaxonomy(rest) {
|
|
|
12770
12912
|
if (config.taxonomyAutoGenResolver) {
|
|
12771
12913
|
const doc = generateResolverDocument(taxonomy);
|
|
12772
12914
|
const resolverPath = path12.join(config.memoryDir, ".taxonomy", "RESOLVER.md");
|
|
12773
|
-
|
|
12915
|
+
fs11.writeFileSync(resolverPath, doc);
|
|
12774
12916
|
console.error(`Regenerated: ${resolverPath}`);
|
|
12775
12917
|
}
|
|
12776
12918
|
break;
|
|
@@ -12961,12 +13103,12 @@ async function runTrainingExport(args, stdout = process.stdout) {
|
|
|
12961
13103
|
`Unknown training-export format "${args.format}". ${validList}`
|
|
12962
13104
|
);
|
|
12963
13105
|
}
|
|
12964
|
-
if (!
|
|
13106
|
+
if (!fs11.existsSync(args.memoryDir)) {
|
|
12965
13107
|
throw new Error(
|
|
12966
13108
|
`--memory-dir "${args.memoryDir}" does not exist. Provide the path to an existing memory directory.`
|
|
12967
13109
|
);
|
|
12968
13110
|
}
|
|
12969
|
-
if (!
|
|
13111
|
+
if (!fs11.statSync(args.memoryDir).isDirectory()) {
|
|
12970
13112
|
throw new Error(
|
|
12971
13113
|
`--memory-dir "${args.memoryDir}" is not a directory. Provide the path to a memory directory, not a file.`
|
|
12972
13114
|
);
|
|
@@ -13052,10 +13194,10 @@ async function runTrainingExport(args, stdout = process.stdout) {
|
|
|
13052
13194
|
}
|
|
13053
13195
|
const formatted = adapter.formatRecords(records);
|
|
13054
13196
|
const outDir = path12.dirname(args.output);
|
|
13055
|
-
|
|
13197
|
+
fs11.mkdirSync(outDir, { recursive: true });
|
|
13056
13198
|
const tmpPath = `${args.output}.tmp-${process.pid}-${Date.now()}`;
|
|
13057
|
-
|
|
13058
|
-
|
|
13199
|
+
fs11.writeFileSync(tmpPath, formatted, "utf-8");
|
|
13200
|
+
fs11.renameSync(tmpPath, args.output);
|
|
13059
13201
|
stdout.write(
|
|
13060
13202
|
`Exported ${records.length} records to ${args.output} (${adapter.name} format)
|
|
13061
13203
|
`
|
|
@@ -13224,7 +13366,7 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
13224
13366
|
}
|
|
13225
13367
|
}, 500);
|
|
13226
13368
|
};
|
|
13227
|
-
|
|
13369
|
+
fs11.watch(memoryDir, { recursive: true }, (_event, filename) => {
|
|
13228
13370
|
if (filename && filename.startsWith(".")) return;
|
|
13229
13371
|
rebuild();
|
|
13230
13372
|
});
|
|
@@ -13232,12 +13374,12 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
13232
13374
|
});
|
|
13233
13375
|
} else if (subAction === "validate") {
|
|
13234
13376
|
const treeDir = outputDir;
|
|
13235
|
-
if (!
|
|
13377
|
+
if (!fs11.existsSync(treeDir)) {
|
|
13236
13378
|
console.error(`Context tree not found at ${treeDir}. Run 'remnic tree generate' first.`);
|
|
13237
13379
|
process.exit(1);
|
|
13238
13380
|
}
|
|
13239
13381
|
const indexPath = path12.join(treeDir, "INDEX.md");
|
|
13240
|
-
if (!
|
|
13382
|
+
if (!fs11.existsSync(indexPath)) {
|
|
13241
13383
|
console.error(`INDEX.md missing in ${treeDir}. Tree may be corrupt \u2014 regenerate.`);
|
|
13242
13384
|
process.exit(1);
|
|
13243
13385
|
}
|
|
@@ -13407,10 +13549,10 @@ Other:
|
|
|
13407
13549
|
let wearablesService;
|
|
13408
13550
|
try {
|
|
13409
13551
|
const configPath = resolveConfigPath();
|
|
13410
|
-
const raw =
|
|
13411
|
-
const remnicCfg =
|
|
13412
|
-
const config =
|
|
13413
|
-
wearablesOrchestrator = new
|
|
13552
|
+
const raw = fs11.existsSync(configPath) ? JSON.parse(fs11.readFileSync(configPath, "utf8")) : {};
|
|
13553
|
+
const remnicCfg = resolveRemnicConfigRecord4(raw);
|
|
13554
|
+
const config = parseConfig4(remnicCfg);
|
|
13555
|
+
wearablesOrchestrator = new Orchestrator3(config);
|
|
13414
13556
|
await wearablesOrchestrator.initialize();
|
|
13415
13557
|
await wearablesOrchestrator.deferredReady;
|
|
13416
13558
|
wearablesService = wearablesOrchestrator.getWearablesService();
|
|
@@ -13425,6 +13567,9 @@ Other:
|
|
|
13425
13567
|
stdout: process.stdout,
|
|
13426
13568
|
stderr: process.stderr
|
|
13427
13569
|
});
|
|
13570
|
+
if (wearablesArgs[0] === "sync" && code === 0 && wearablesOrchestrator.config.meetings.enabled) {
|
|
13571
|
+
await (await wearablesOrchestrator.getMeetingsService()).flushBuilds();
|
|
13572
|
+
}
|
|
13428
13573
|
if (code !== 0) process.exitCode = code;
|
|
13429
13574
|
} catch (err) {
|
|
13430
13575
|
console.error(err instanceof Error ? err.message : String(err));
|
|
@@ -13442,6 +13587,10 @@ Other:
|
|
|
13442
13587
|
}
|
|
13443
13588
|
break;
|
|
13444
13589
|
}
|
|
13590
|
+
case "meetings": {
|
|
13591
|
+
await runMeetingsBinaryCommand(rest);
|
|
13592
|
+
break;
|
|
13593
|
+
}
|
|
13445
13594
|
case "import": {
|
|
13446
13595
|
if (rest.includes("--help") || rest.includes("-h") || rest.length === 0) {
|
|
13447
13596
|
console.log(IMPORT_USAGE);
|
|
@@ -13451,10 +13600,10 @@ Other:
|
|
|
13451
13600
|
const targetFactory = async () => {
|
|
13452
13601
|
if (!orchestratorSingleton) {
|
|
13453
13602
|
const configPath = resolveConfigPath();
|
|
13454
|
-
const raw =
|
|
13455
|
-
const remnicCfg =
|
|
13456
|
-
const config =
|
|
13457
|
-
orchestratorSingleton = new
|
|
13603
|
+
const raw = fs11.existsSync(configPath) ? JSON.parse(fs11.readFileSync(configPath, "utf8")) : {};
|
|
13604
|
+
const remnicCfg = resolveRemnicConfigRecord4(raw);
|
|
13605
|
+
const config = parseConfig4(remnicCfg);
|
|
13606
|
+
orchestratorSingleton = new Orchestrator3(config);
|
|
13458
13607
|
await orchestratorSingleton.initialize();
|
|
13459
13608
|
await orchestratorSingleton.deferredReady;
|
|
13460
13609
|
}
|
|
@@ -13482,6 +13631,14 @@ Other:
|
|
|
13482
13631
|
if (exitCode !== 0) process.exit(exitCode);
|
|
13483
13632
|
break;
|
|
13484
13633
|
}
|
|
13634
|
+
case "capture": {
|
|
13635
|
+
const exitCode = await cmdCapture(rest, {
|
|
13636
|
+
stdout: (line) => console.log(line),
|
|
13637
|
+
stderr: (line) => console.error(line)
|
|
13638
|
+
});
|
|
13639
|
+
if (exitCode !== 0) process.exit(exitCode);
|
|
13640
|
+
break;
|
|
13641
|
+
}
|
|
13485
13642
|
case "capsule": {
|
|
13486
13643
|
const subAction = rest[0] ?? "help";
|
|
13487
13644
|
const capsuleArgs = rest.slice(1);
|
|
@@ -13638,6 +13795,10 @@ Usage:
|
|
|
13638
13795
|
store day transcripts, trust-gated memory creation, speaker labels,
|
|
13639
13796
|
and per-user corrections. Run "remnic wearables help" for details.
|
|
13640
13797
|
Connectors install \xE0 la carte: npm install @remnic/connector-limitless
|
|
13798
|
+
remnic meetings <list|show|build>
|
|
13799
|
+
Retrospective meetings: list stored records, show one by id, or build
|
|
13800
|
+
(detect + fuse + store) a day's meetings from ingested audio + screen
|
|
13801
|
+
activity. Run "remnic meetings help" for details.
|
|
13641
13802
|
|
|
13642
13803
|
remnic doctor Run diagnostics
|
|
13643
13804
|
remnic config Show current config
|