@remnic/cli 9.65.1 → 9.65.2
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 +507 -437
- package/package.json +31 -31
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 fs18 from "fs";
|
|
22
22
|
import os3 from "os";
|
|
23
23
|
import path18 from "path";
|
|
24
24
|
import { createHash as createHash4 } from "crypto";
|
|
@@ -27,13 +27,13 @@ import * as childProcess2 from "child_process";
|
|
|
27
27
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
28
28
|
import { gzipSync } from "zlib";
|
|
29
29
|
import {
|
|
30
|
-
parseConfig as
|
|
30
|
+
parseConfig as parseConfig9,
|
|
31
31
|
isOpenaiApiKeyDisabled,
|
|
32
32
|
resolveEnvVars,
|
|
33
|
-
resolveRemnicConfigRecord as
|
|
33
|
+
resolveRemnicConfigRecord as resolveRemnicConfigRecord8,
|
|
34
34
|
Orchestrator as Orchestrator5,
|
|
35
35
|
EngramAccessService as EngramAccessService2,
|
|
36
|
-
initLogger as
|
|
36
|
+
initLogger as initLogger4,
|
|
37
37
|
onboard,
|
|
38
38
|
curate,
|
|
39
39
|
listReviewItems,
|
|
@@ -105,9 +105,7 @@ import {
|
|
|
105
105
|
discoverMemoryExtensions,
|
|
106
106
|
resolveExtensionsRoot,
|
|
107
107
|
coerceInstallExtension,
|
|
108
|
-
StorageManager as
|
|
109
|
-
computeProcedureStats,
|
|
110
|
-
formatProcedureStatsText,
|
|
108
|
+
StorageManager as StorageManager3,
|
|
111
109
|
parseXrayCliOptions,
|
|
112
110
|
renderXray,
|
|
113
111
|
extractWhoKnowsRawArgs,
|
|
@@ -119,6 +117,7 @@ import {
|
|
|
119
117
|
OFFLINE_SYNC_SNAPSHOT_BASE_MAX_BODY_BYTES,
|
|
120
118
|
applyOfflineSyncFileContentChunk as applyOfflineSyncFileContentChunk2,
|
|
121
119
|
applyOfflineSyncSnapshot,
|
|
120
|
+
runPromotionCandidatesCommand,
|
|
122
121
|
buildOfflineSyncChangesetFromSnapshot,
|
|
123
122
|
drainPendingLifecycleForOfflineSync,
|
|
124
123
|
compileOfflineSyncExcludeGlobs,
|
|
@@ -259,6 +258,200 @@ async function runExternalWikiBinaryCommand(rest) {
|
|
|
259
258
|
}
|
|
260
259
|
}
|
|
261
260
|
|
|
261
|
+
// src/commands/procedural.ts
|
|
262
|
+
import fs4 from "fs";
|
|
263
|
+
import {
|
|
264
|
+
StorageManager,
|
|
265
|
+
computeProcedureStats,
|
|
266
|
+
formatProcedureStatsText,
|
|
267
|
+
initLogger,
|
|
268
|
+
parseConfig as parseConfig4,
|
|
269
|
+
resolveRemnicConfigRecord as resolveRemnicConfigRecord4,
|
|
270
|
+
runProcedureLibraryMaintenance
|
|
271
|
+
} from "@remnic/core";
|
|
272
|
+
|
|
273
|
+
// src/cli-args.ts
|
|
274
|
+
function resolveFlag(args, flag) {
|
|
275
|
+
const idx = args.indexOf(flag);
|
|
276
|
+
if (idx === -1 || idx + 1 >= args.length) return void 0;
|
|
277
|
+
const value = args[idx + 1];
|
|
278
|
+
return isOptionToken(value) ? void 0 : value;
|
|
279
|
+
}
|
|
280
|
+
function isOptionToken(value) {
|
|
281
|
+
if (!value.startsWith("-")) return false;
|
|
282
|
+
if (/^-\d/.test(value) || /^-\.\d/.test(value)) return false;
|
|
283
|
+
return true;
|
|
284
|
+
}
|
|
285
|
+
function hasFlag(args, flag) {
|
|
286
|
+
return args.indexOf(flag) !== -1;
|
|
287
|
+
}
|
|
288
|
+
var TAXONOMY_RESOLVE_BOOLEAN_FLAGS = /* @__PURE__ */ new Set(["--json"]);
|
|
289
|
+
var TAXONOMY_RESOLVE_VALUE_FLAGS = /* @__PURE__ */ new Set(["--category"]);
|
|
290
|
+
function stripResolveFlags(args, booleanFlags = TAXONOMY_RESOLVE_BOOLEAN_FLAGS, valueFlags = TAXONOMY_RESOLVE_VALUE_FLAGS) {
|
|
291
|
+
return parseTaxonomyResolveArgs(args, booleanFlags, valueFlags).textParts;
|
|
292
|
+
}
|
|
293
|
+
function parseTaxonomyResolveArgs(args, booleanFlags = TAXONOMY_RESOLVE_BOOLEAN_FLAGS, valueFlags = TAXONOMY_RESOLVE_VALUE_FLAGS) {
|
|
294
|
+
const textParts = [];
|
|
295
|
+
const values = {};
|
|
296
|
+
const booleans = /* @__PURE__ */ new Set();
|
|
297
|
+
let literalText = false;
|
|
298
|
+
for (let i = 0; i < args.length; i++) {
|
|
299
|
+
const arg = args[i];
|
|
300
|
+
if (literalText) {
|
|
301
|
+
textParts.push(arg);
|
|
302
|
+
continue;
|
|
303
|
+
}
|
|
304
|
+
if (arg === "--") {
|
|
305
|
+
literalText = true;
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
308
|
+
if (arg.startsWith("--")) {
|
|
309
|
+
if (booleanFlags.has(arg)) {
|
|
310
|
+
booleans.add(arg);
|
|
311
|
+
continue;
|
|
312
|
+
}
|
|
313
|
+
if (valueFlags.has(arg)) {
|
|
314
|
+
const value = args[i + 1];
|
|
315
|
+
if (value === void 0 || value.startsWith("--")) {
|
|
316
|
+
throw new Error(`${arg} requires a value`);
|
|
317
|
+
}
|
|
318
|
+
values[arg] = value;
|
|
319
|
+
i++;
|
|
320
|
+
continue;
|
|
321
|
+
}
|
|
322
|
+
throw new Error(`Unknown flag: ${arg}`);
|
|
323
|
+
}
|
|
324
|
+
textParts.push(arg);
|
|
325
|
+
}
|
|
326
|
+
return { textParts, values, booleans };
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// src/path-utils.ts
|
|
330
|
+
function resolveHomeDir() {
|
|
331
|
+
return process.env.HOME ?? process.env.USERPROFILE ?? "~";
|
|
332
|
+
}
|
|
333
|
+
function expandTilde(p) {
|
|
334
|
+
if (p === "~" || p.startsWith("~/") || p.startsWith("~\\")) {
|
|
335
|
+
return resolveHomeDir() + p.slice(1);
|
|
336
|
+
}
|
|
337
|
+
const home = resolveHomeDir();
|
|
338
|
+
if (p === "$HOME" || p.startsWith("$HOME/") || p.startsWith("$HOME\\")) {
|
|
339
|
+
return home + p.slice(5);
|
|
340
|
+
}
|
|
341
|
+
if (p === "${HOME}" || p.startsWith("${HOME}/") || p.startsWith("${HOME}\\")) {
|
|
342
|
+
return home + p.slice(7);
|
|
343
|
+
}
|
|
344
|
+
return p;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// src/commands/procedural.ts
|
|
348
|
+
async function runProceduralBinaryCommand(rest) {
|
|
349
|
+
initLogger();
|
|
350
|
+
const subcommand = rest[0];
|
|
351
|
+
if (!subcommand || subcommand === "--help" || subcommand === "-h") {
|
|
352
|
+
console.log(`remnic procedural \u2014 Procedural memory operations (issue #567)
|
|
353
|
+
|
|
354
|
+
Usage:
|
|
355
|
+
remnic procedural stats [--format json|text] [--memory-dir <path>]
|
|
356
|
+
remnic procedural maintain [--apply] [--format json|text] [--memory-dir <path>]
|
|
357
|
+
|
|
358
|
+
Subcommands:
|
|
359
|
+
stats Print counts by status + recent activity + active config.
|
|
360
|
+
maintain Run library-health maintenance (issue #2370): shadow
|
|
361
|
+
report of merge / repair-flag / retire proposals.
|
|
362
|
+
--apply executes them (requires
|
|
363
|
+
procedural.maintenance.enabled in config).
|
|
364
|
+
|
|
365
|
+
Shared with:
|
|
366
|
+
GET /engram/v1/procedural/stats
|
|
367
|
+
MCP remnic.procedural_stats (alias engram.procedural_stats)
|
|
368
|
+
MCP remnic.procedure_library_maintenance (alias engram.procedure_library_maintenance)`);
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
if (subcommand !== "stats" && subcommand !== "maintain") {
|
|
372
|
+
console.error(
|
|
373
|
+
`Unknown procedural subcommand "${subcommand}". Run \`remnic procedural --help\` for usage.`
|
|
374
|
+
);
|
|
375
|
+
process.exit(1);
|
|
376
|
+
}
|
|
377
|
+
const args = rest.slice(1);
|
|
378
|
+
const formatPresent = hasFlag(args, "--format");
|
|
379
|
+
const formatRaw = resolveFlag(args, "--format");
|
|
380
|
+
if (formatPresent && (formatRaw === void 0 || formatRaw === null)) {
|
|
381
|
+
console.error("--format requires a value. Use `--format json` or `--format text`.");
|
|
382
|
+
process.exit(1);
|
|
383
|
+
}
|
|
384
|
+
const format = (() => {
|
|
385
|
+
if (!formatPresent || formatRaw === void 0 || formatRaw === null) return "text";
|
|
386
|
+
const normalized = String(formatRaw).trim().toLowerCase();
|
|
387
|
+
if (normalized !== "text" && normalized !== "json") {
|
|
388
|
+
console.error(`Invalid --format "${formatRaw}". Allowed: text, json.`);
|
|
389
|
+
process.exit(1);
|
|
390
|
+
}
|
|
391
|
+
return normalized;
|
|
392
|
+
})();
|
|
393
|
+
const memoryDirPresent = hasFlag(args, "--memory-dir");
|
|
394
|
+
const memoryDirOverride = resolveFlag(args, "--memory-dir");
|
|
395
|
+
if (memoryDirPresent && (memoryDirOverride === void 0 || memoryDirOverride === null)) {
|
|
396
|
+
console.error("--memory-dir requires a path. Omit the flag to use the resolved default.");
|
|
397
|
+
process.exit(1);
|
|
398
|
+
}
|
|
399
|
+
const configPath = resolveConfigPath();
|
|
400
|
+
const raw = fs4.existsSync(configPath) ? JSON.parse(fs4.readFileSync(configPath, "utf8")) : {};
|
|
401
|
+
const config = parseConfig4(resolveRemnicConfigRecord4(raw));
|
|
402
|
+
const memoryDir = expandTilde(
|
|
403
|
+
typeof memoryDirOverride === "string" && memoryDirOverride.length > 0 ? memoryDirOverride : config.memoryDir ?? resolveMemoryDir()
|
|
404
|
+
);
|
|
405
|
+
const storage = new StorageManager(memoryDir);
|
|
406
|
+
if (subcommand === "maintain") {
|
|
407
|
+
const report2 = await runProcedureLibraryMaintenance({
|
|
408
|
+
memoryDir,
|
|
409
|
+
storage,
|
|
410
|
+
config,
|
|
411
|
+
apply: hasFlag(args, "--apply")
|
|
412
|
+
});
|
|
413
|
+
if (format === "json") {
|
|
414
|
+
process.stdout.write(JSON.stringify(report2, null, 2) + "\n");
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
process.stdout.write(formatProcedureMaintenanceText(report2));
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
const report = await computeProcedureStats({ storage, config });
|
|
421
|
+
if (format === "json") {
|
|
422
|
+
process.stdout.write(JSON.stringify(report, null, 2) + "\n");
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
process.stdout.write(formatProcedureStatsText(report));
|
|
426
|
+
}
|
|
427
|
+
function formatProcedureMaintenanceText(report) {
|
|
428
|
+
const lines = [
|
|
429
|
+
`Procedure library maintenance (schema v${report.schemaVersion}, ${report.mode})`,
|
|
430
|
+
` generated: ${report.generatedAt}`,
|
|
431
|
+
` scanned: ${report.scannedProcedures}`
|
|
432
|
+
];
|
|
433
|
+
if (report.skippedReason) {
|
|
434
|
+
lines.push(` skipped: ${report.skippedReason}`);
|
|
435
|
+
}
|
|
436
|
+
lines.push(` proposed: ${report.proposed.length}`);
|
|
437
|
+
lines.push(` applied: ${report.appliedCount}`);
|
|
438
|
+
for (const action of report.proposed) {
|
|
439
|
+
lines.push("");
|
|
440
|
+
lines.push(` [${action.action}] ${action.reasonCode}`);
|
|
441
|
+
lines.push(` ids: ${action.memoryIds.join(", ")}`);
|
|
442
|
+
if (action.canonicalId) {
|
|
443
|
+
lines.push(` canonical: ${action.canonicalId}`);
|
|
444
|
+
}
|
|
445
|
+
lines.push(` reason: ${action.reason}`);
|
|
446
|
+
for (const ev of action.evidence) {
|
|
447
|
+
lines.push(
|
|
448
|
+
` ${ev.memoryId}: mw_success=${ev.mwSuccess} mw_fail=${ev.mwFail} lastAccessed=${ev.lastAccessed ?? "(none)"}`
|
|
449
|
+
);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
return lines.join("\n") + "\n";
|
|
453
|
+
}
|
|
454
|
+
|
|
262
455
|
// src/optional-module-loader.ts
|
|
263
456
|
function isSpecifierNotFoundError(err, specifier) {
|
|
264
457
|
if (!err || typeof err !== "object") {
|
|
@@ -309,13 +502,13 @@ async function loadWecloneExportModule() {
|
|
|
309
502
|
}
|
|
310
503
|
|
|
311
504
|
// src/converge.ts
|
|
312
|
-
import * as
|
|
505
|
+
import * as fs6 from "fs";
|
|
313
506
|
import { createHash as createHash3 } from "crypto";
|
|
314
507
|
import * as path2 from "path";
|
|
315
508
|
import {
|
|
316
509
|
CONVERGE_CONFLICT_POLICIES,
|
|
317
510
|
DEFAULT_CONVERGE_CONFLICT_POLICY,
|
|
318
|
-
parseConfig as
|
|
511
|
+
parseConfig as parseConfig5,
|
|
319
512
|
buildOfflineSyncSnapshotFromBase,
|
|
320
513
|
applyOfflineSyncFileContentChunk,
|
|
321
514
|
isInternalRemnicStatePath as isInternalRemnicStatePath3,
|
|
@@ -341,12 +534,12 @@ import {
|
|
|
341
534
|
|
|
342
535
|
// src/offline-storage-io.ts
|
|
343
536
|
import { createDecipheriv, createHash } from "crypto";
|
|
344
|
-
import
|
|
537
|
+
import fs5 from "fs";
|
|
345
538
|
import { lstat, mkdtemp, readdir, rm } from "fs/promises";
|
|
346
539
|
import path from "path";
|
|
347
540
|
import {
|
|
348
541
|
OFFLINE_SYNC_FILE_CONTENT_TRANSFER_CHUNK_BYTES,
|
|
349
|
-
StorageManager,
|
|
542
|
+
StorageManager as StorageManager2,
|
|
350
543
|
createSupportPassportPrivateFileExclusion
|
|
351
544
|
} from "@remnic/core";
|
|
352
545
|
import { OFFLINE_DECRYPT_STAGING_DIR_PREFIX } from "@remnic/core/offline-sync-exclude-globs";
|
|
@@ -391,7 +584,7 @@ async function filterOfflineSyncBaseFiles(memoryDir, files, excludeFile) {
|
|
|
391
584
|
return files.filter((_file, index) => excluded[index] === false);
|
|
392
585
|
}
|
|
393
586
|
async function createConfiguredOfflineStorage(memoryDir, secureStoreEncryptOnWrite = true) {
|
|
394
|
-
const storage = new
|
|
587
|
+
const storage = new StorageManager2(memoryDir);
|
|
395
588
|
const header = await readHeader(memoryDir);
|
|
396
589
|
let secureStoreKey = null;
|
|
397
590
|
let secureStoreRequired = false;
|
|
@@ -416,7 +609,7 @@ async function createOfflineStorageForPath(memoryDir, filePath, configured, secu
|
|
|
416
609
|
if (storageRoot !== memoryRoot && !storageRoot.startsWith(`${memoryRoot}${path.sep}`)) {
|
|
417
610
|
throw new Error(`lifecycle ledger path is outside the offline memory directory: ${filePath}`);
|
|
418
611
|
}
|
|
419
|
-
const storage = new
|
|
612
|
+
const storage = new StorageManager2(storageRoot);
|
|
420
613
|
if (configured.secureStoreRequired) {
|
|
421
614
|
storage.setSecureStoreRequired(true);
|
|
422
615
|
}
|
|
@@ -503,7 +696,7 @@ async function* readOfflineSyncFileChunks(options) {
|
|
|
503
696
|
});
|
|
504
697
|
}
|
|
505
698
|
async function readFilePrefix(filePath, length) {
|
|
506
|
-
const handle = await
|
|
699
|
+
const handle = await fs5.promises.open(filePath, "r");
|
|
507
700
|
try {
|
|
508
701
|
const out = Buffer.alloc(length);
|
|
509
702
|
const { bytesRead } = await handle.read(out, 0, length, 0);
|
|
@@ -513,7 +706,7 @@ async function readFilePrefix(filePath, length) {
|
|
|
513
706
|
}
|
|
514
707
|
}
|
|
515
708
|
async function* readPlainOfflineFileChunks(filePath, chunkSize) {
|
|
516
|
-
const stream =
|
|
709
|
+
const stream = fs5.createReadStream(filePath, { highWaterMark: chunkSize });
|
|
517
710
|
for await (const chunk of stream) {
|
|
518
711
|
yield Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
519
712
|
}
|
|
@@ -550,9 +743,9 @@ async function* readEncryptedOfflineFileChunks(options) {
|
|
|
550
743
|
});
|
|
551
744
|
decipher.setAuthTag(authTag);
|
|
552
745
|
decipher.setAAD(Buffer.concat([secureStoreEnvelopeHeaderAad(salt), aad]));
|
|
553
|
-
const output =
|
|
746
|
+
const output = fs5.createWriteStream(tempPath, { mode: 384 });
|
|
554
747
|
try {
|
|
555
|
-
const stream =
|
|
748
|
+
const stream = fs5.createReadStream(options.filePath, {
|
|
556
749
|
start: MAGIC_HEADER_SIZE + ENVELOPE_HEADER_SIZE,
|
|
557
750
|
highWaterMark: options.chunkSize
|
|
558
751
|
});
|
|
@@ -1162,7 +1355,7 @@ async function readLocalTombstoneEvidence(rootDir) {
|
|
|
1162
1355
|
for (const relativePath of TOMBSTONE_PATHS) {
|
|
1163
1356
|
let content;
|
|
1164
1357
|
try {
|
|
1165
|
-
content = await
|
|
1358
|
+
content = await fs6.promises.readFile(path2.join(rootDir, relativePath), "utf-8");
|
|
1166
1359
|
} catch (error) {
|
|
1167
1360
|
if (error.code === "ENOENT") continue;
|
|
1168
1361
|
throw error;
|
|
@@ -1177,7 +1370,7 @@ async function discoverCursorNamespaces(memoryDir, peerUrl) {
|
|
|
1177
1370
|
const cursorDir = path2.join(path2.resolve(memoryDir), ".remnic", "state", "converge-cursors");
|
|
1178
1371
|
let entries;
|
|
1179
1372
|
try {
|
|
1180
|
-
entries = await
|
|
1373
|
+
entries = await fs6.promises.readdir(cursorDir, { withFileTypes: true });
|
|
1181
1374
|
} catch (error) {
|
|
1182
1375
|
if (error.code === "ENOENT") return [];
|
|
1183
1376
|
throw error;
|
|
@@ -1253,7 +1446,7 @@ async function computeConvergePlan(options = {}) {
|
|
|
1253
1446
|
let config = options.config;
|
|
1254
1447
|
if (!config) {
|
|
1255
1448
|
try {
|
|
1256
|
-
config =
|
|
1449
|
+
config = parseConfig5({});
|
|
1257
1450
|
} catch {
|
|
1258
1451
|
}
|
|
1259
1452
|
}
|
|
@@ -1504,7 +1697,7 @@ async function executeConvergeApply(options = {}) {
|
|
|
1504
1697
|
let config = options.config;
|
|
1505
1698
|
if (!config) {
|
|
1506
1699
|
try {
|
|
1507
|
-
config =
|
|
1700
|
+
config = parseConfig5({});
|
|
1508
1701
|
} catch {
|
|
1509
1702
|
}
|
|
1510
1703
|
}
|
|
@@ -1667,7 +1860,7 @@ async function executeConvergeApply(options = {}) {
|
|
|
1667
1860
|
if (current.sha256 !== entry.localSha256) {
|
|
1668
1861
|
throw new Error(`local file changed during push: ${localPath}`);
|
|
1669
1862
|
}
|
|
1670
|
-
const stat2 = await
|
|
1863
|
+
const stat2 = await fs6.promises.stat(filePath);
|
|
1671
1864
|
let chunks;
|
|
1672
1865
|
let chunkOffset = 0;
|
|
1673
1866
|
const resetChunks = async () => {
|
|
@@ -1944,7 +2137,7 @@ function formatConvergeApplyReport(result) {
|
|
|
1944
2137
|
lines.push(formatConvergeReport(result.plan));
|
|
1945
2138
|
return lines.join("\n");
|
|
1946
2139
|
}
|
|
1947
|
-
async function cmdConverge(action, rest, json, config =
|
|
2140
|
+
async function cmdConverge(action, rest, json, config = parseConfig5({})) {
|
|
1948
2141
|
if (action === "help" || action === "--help" || action === "-h" || rest.includes("--help") || rest.includes("-h")) {
|
|
1949
2142
|
console.log(`Usage: remnic converge <plan|apply> [options]
|
|
1950
2143
|
|
|
@@ -2150,8 +2343,8 @@ function renderReplayResult(result, targetNamespace, format) {
|
|
|
2150
2343
|
}
|
|
2151
2344
|
|
|
2152
2345
|
// src/quarantine-replay.ts
|
|
2153
|
-
import * as
|
|
2154
|
-
import { EngramAccessService, Orchestrator as Orchestrator3, initLogger, parseConfig as
|
|
2346
|
+
import * as fs7 from "fs";
|
|
2347
|
+
import { EngramAccessService, Orchestrator as Orchestrator3, initLogger as initLogger2, parseConfig as parseConfig6, resolveRemnicConfigRecord as resolveRemnicConfigRecord5 } from "@remnic/core";
|
|
2155
2348
|
import { WriteQuarantineStore } from "@remnic/core/write-quarantine.js";
|
|
2156
2349
|
function valueFlag(args, flag) {
|
|
2157
2350
|
const occurrences = args.filter((a) => a === flag).length;
|
|
@@ -2195,12 +2388,12 @@ async function runQuarantineReplay(rest, format, resolveConfigPath2) {
|
|
|
2195
2388
|
process.exitCode = 2;
|
|
2196
2389
|
return;
|
|
2197
2390
|
}
|
|
2198
|
-
|
|
2391
|
+
initLogger2();
|
|
2199
2392
|
let orchestrator;
|
|
2200
2393
|
try {
|
|
2201
2394
|
const configPath = resolveConfigPath2();
|
|
2202
|
-
const raw =
|
|
2203
|
-
const config =
|
|
2395
|
+
const raw = fs7.existsSync(configPath) ? JSON.parse(fs7.readFileSync(configPath, "utf8")) : {};
|
|
2396
|
+
const config = parseConfig6(resolveRemnicConfigRecord5(raw));
|
|
2204
2397
|
orchestrator = new Orchestrator3(config);
|
|
2205
2398
|
await orchestrator.initialize();
|
|
2206
2399
|
await orchestrator.deferredReady;
|
|
@@ -2231,15 +2424,15 @@ async function runQuarantineReplay(rest, format, resolveConfigPath2) {
|
|
|
2231
2424
|
}
|
|
2232
2425
|
|
|
2233
2426
|
// src/offline-impression-rotation.ts
|
|
2234
|
-
import
|
|
2235
|
-
import { parseConfig as
|
|
2427
|
+
import fs8 from "fs";
|
|
2428
|
+
import { parseConfig as parseConfig7, resolveRemnicConfigRecord as resolveRemnicConfigRecord6, drainPendingImpressionsForOfflineSync } from "@remnic/core";
|
|
2236
2429
|
import { LastRecallStore } from "@remnic/core/recall-state";
|
|
2237
2430
|
function parseConfigQuietly(raw) {
|
|
2238
2431
|
const originalWarn = console.warn;
|
|
2239
2432
|
console.warn = () => {
|
|
2240
2433
|
};
|
|
2241
2434
|
try {
|
|
2242
|
-
return
|
|
2435
|
+
return parseConfig7(resolveRemnicConfigRecord6(raw));
|
|
2243
2436
|
} finally {
|
|
2244
2437
|
console.warn = originalWarn;
|
|
2245
2438
|
}
|
|
@@ -2253,7 +2446,7 @@ var OFFLINE_CONFIG_KEYS = [
|
|
|
2253
2446
|
function pickOfflineConfigRecord(raw) {
|
|
2254
2447
|
let resolved;
|
|
2255
2448
|
try {
|
|
2256
|
-
resolved =
|
|
2449
|
+
resolved = resolveRemnicConfigRecord6(raw);
|
|
2257
2450
|
} catch {
|
|
2258
2451
|
resolved = raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
|
|
2259
2452
|
}
|
|
@@ -2266,7 +2459,7 @@ function pickOfflineConfigRecord(raw) {
|
|
|
2266
2459
|
function resolveOfflineImpressionRotation(configPath) {
|
|
2267
2460
|
let raw;
|
|
2268
2461
|
try {
|
|
2269
|
-
raw =
|
|
2462
|
+
raw = fs8.existsSync(configPath) ? JSON.parse(fs8.readFileSync(configPath, "utf8")) : {};
|
|
2270
2463
|
} catch {
|
|
2271
2464
|
throw new Error(
|
|
2272
2465
|
`cannot read recall-impression rotation from ${configPath}: config file could not be read as JSON`
|
|
@@ -2524,12 +2717,12 @@ function assertBenchModuleFreshForDevelopment() {
|
|
|
2524
2717
|
}
|
|
2525
2718
|
|
|
2526
2719
|
// src/cmd-security.ts
|
|
2527
|
-
import
|
|
2720
|
+
import fs9 from "fs";
|
|
2528
2721
|
import {
|
|
2529
2722
|
Orchestrator as Orchestrator4,
|
|
2530
|
-
parseConfig as
|
|
2531
|
-
initLogger as
|
|
2532
|
-
resolveRemnicConfigRecord as
|
|
2723
|
+
parseConfig as parseConfig8,
|
|
2724
|
+
initLogger as initLogger3,
|
|
2725
|
+
resolveRemnicConfigRecord as resolveRemnicConfigRecord7,
|
|
2533
2726
|
runAuditMemoryCliCommand,
|
|
2534
2727
|
formatAuditMemoryReport
|
|
2535
2728
|
} from "@remnic/core";
|
|
@@ -2542,10 +2735,10 @@ async function cmdSecurity(rest) {
|
|
|
2542
2735
|
process.exitCode = 1;
|
|
2543
2736
|
return;
|
|
2544
2737
|
}
|
|
2545
|
-
|
|
2738
|
+
initLogger3();
|
|
2546
2739
|
const configPath = resolveConfigPath();
|
|
2547
|
-
const raw =
|
|
2548
|
-
const config =
|
|
2740
|
+
const raw = fs9.existsSync(configPath) ? JSON.parse(fs9.readFileSync(configPath, "utf8")) : {};
|
|
2741
|
+
const config = parseConfig8(resolveRemnicConfigRecord7(raw));
|
|
2549
2742
|
const orchestrator = new Orchestrator4(config);
|
|
2550
2743
|
await orchestrator.initialize();
|
|
2551
2744
|
try {
|
|
@@ -2569,7 +2762,7 @@ async function cmdSecurity(rest) {
|
|
|
2569
2762
|
}
|
|
2570
2763
|
|
|
2571
2764
|
// src/daemon-service-candidates.ts
|
|
2572
|
-
import
|
|
2765
|
+
import fs10 from "fs";
|
|
2573
2766
|
import path5 from "path";
|
|
2574
2767
|
var LAUNCHD_LABEL = "ai.remnic.daemon";
|
|
2575
2768
|
var LEGACY_REMNIC_SERVER_LAUNCHD_LABEL = "ai.remnic.server";
|
|
@@ -2591,7 +2784,7 @@ function systemdUnitPaths(homeDir) {
|
|
|
2591
2784
|
function anyFileExists(paths) {
|
|
2592
2785
|
return paths.some((candidate) => {
|
|
2593
2786
|
try {
|
|
2594
|
-
return
|
|
2787
|
+
return fs10.statSync(candidate).isFile();
|
|
2595
2788
|
} catch {
|
|
2596
2789
|
return false;
|
|
2597
2790
|
}
|
|
@@ -2603,7 +2796,7 @@ function commandNames(command) {
|
|
|
2603
2796
|
}
|
|
2604
2797
|
function isRunnableNodeScript(filePath) {
|
|
2605
2798
|
try {
|
|
2606
|
-
const text =
|
|
2799
|
+
const text = fs10.readFileSync(filePath, "utf8").slice(0, 4096);
|
|
2607
2800
|
const firstLine = text.split(/\r?\n/, 1)[0] ?? "";
|
|
2608
2801
|
if (/^#!.*\bnode\b/.test(firstLine)) return true;
|
|
2609
2802
|
if (firstLine.startsWith("#!")) return false;
|
|
@@ -2616,7 +2809,7 @@ function isRunnableNodeScript(filePath) {
|
|
|
2616
2809
|
function resolveShimNodeScript(filePath) {
|
|
2617
2810
|
let text;
|
|
2618
2811
|
try {
|
|
2619
|
-
text =
|
|
2812
|
+
text = fs10.readFileSync(filePath, "utf8").slice(0, 16384);
|
|
2620
2813
|
} catch {
|
|
2621
2814
|
return void 0;
|
|
2622
2815
|
}
|
|
@@ -2628,8 +2821,8 @@ function resolveShimNodeScript(filePath) {
|
|
|
2628
2821
|
const candidate = raw.replaceAll("${basedir}", basedir).replaceAll("$basedir", basedir).replaceAll("\\ ", " ");
|
|
2629
2822
|
const resolved = path5.isAbsolute(candidate) ? candidate : path5.resolve(basedir, candidate);
|
|
2630
2823
|
try {
|
|
2631
|
-
if (
|
|
2632
|
-
return
|
|
2824
|
+
if (fs10.statSync(resolved).isFile() && isRunnableNodeScript(resolved)) {
|
|
2825
|
+
return fs10.realpathSync(resolved);
|
|
2633
2826
|
}
|
|
2634
2827
|
} catch {
|
|
2635
2828
|
}
|
|
@@ -2637,7 +2830,7 @@ function resolveShimNodeScript(filePath) {
|
|
|
2637
2830
|
return void 0;
|
|
2638
2831
|
}
|
|
2639
2832
|
function resolveRunnableNodeScript(filePath) {
|
|
2640
|
-
const realPath =
|
|
2833
|
+
const realPath = fs10.realpathSync(filePath);
|
|
2641
2834
|
if (isRunnableNodeScript(realPath)) return realPath;
|
|
2642
2835
|
return resolveShimNodeScript(realPath);
|
|
2643
2836
|
}
|
|
@@ -2647,9 +2840,9 @@ function findCommandOnPath(command, pathEnv = process.env.PATH ?? "") {
|
|
|
2647
2840
|
for (const name of commandNames(command)) {
|
|
2648
2841
|
const candidate = path5.join(dir, name);
|
|
2649
2842
|
try {
|
|
2650
|
-
const stat2 =
|
|
2843
|
+
const stat2 = fs10.statSync(candidate);
|
|
2651
2844
|
if (!stat2.isFile()) continue;
|
|
2652
|
-
if (process.platform !== "win32")
|
|
2845
|
+
if (process.platform !== "win32") fs10.accessSync(candidate, fs10.constants.X_OK);
|
|
2653
2846
|
const runnable = resolveRunnableNodeScript(candidate);
|
|
2654
2847
|
if (runnable) return runnable;
|
|
2655
2848
|
} catch {
|
|
@@ -3049,24 +3242,6 @@ function collectBenchmarks(argv) {
|
|
|
3049
3242
|
return benchmarks;
|
|
3050
3243
|
}
|
|
3051
3244
|
|
|
3052
|
-
// src/path-utils.ts
|
|
3053
|
-
function resolveHomeDir() {
|
|
3054
|
-
return process.env.HOME ?? process.env.USERPROFILE ?? "~";
|
|
3055
|
-
}
|
|
3056
|
-
function expandTilde(p) {
|
|
3057
|
-
if (p === "~" || p.startsWith("~/") || p.startsWith("~\\")) {
|
|
3058
|
-
return resolveHomeDir() + p.slice(1);
|
|
3059
|
-
}
|
|
3060
|
-
const home = resolveHomeDir();
|
|
3061
|
-
if (p === "$HOME" || p.startsWith("$HOME/") || p.startsWith("$HOME\\")) {
|
|
3062
|
-
return home + p.slice(5);
|
|
3063
|
-
}
|
|
3064
|
-
if (p === "${HOME}" || p.startsWith("${HOME}/") || p.startsWith("${HOME}\\")) {
|
|
3065
|
-
return home + p.slice(7);
|
|
3066
|
-
}
|
|
3067
|
-
return p;
|
|
3068
|
-
}
|
|
3069
|
-
|
|
3070
3245
|
// src/bench-args-research.ts
|
|
3071
3246
|
import path6 from "path";
|
|
3072
3247
|
function readPositiveInteger(args, flag) {
|
|
@@ -4140,7 +4315,7 @@ function finalizeBenchStatus(filePath) {
|
|
|
4140
4315
|
}
|
|
4141
4316
|
|
|
4142
4317
|
// src/bench-fallback.ts
|
|
4143
|
-
import
|
|
4318
|
+
import fs11 from "fs";
|
|
4144
4319
|
import path9 from "path";
|
|
4145
4320
|
var FALLBACK_RESULTS_DIRNAME = "fallback-runs";
|
|
4146
4321
|
function buildBenchRunnerArgs(parsed, benchmarkId, outputDir) {
|
|
@@ -4212,7 +4387,7 @@ function createFallbackBenchOutputDir(resultsDir, benchmarkId, pid, startedAtMs
|
|
|
4212
4387
|
);
|
|
4213
4388
|
}
|
|
4214
4389
|
function resolveFallbackBenchResultPath(outputDir) {
|
|
4215
|
-
const entries =
|
|
4390
|
+
const entries = fs11.readdirSync(outputDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name).sort();
|
|
4216
4391
|
if (entries.length === 0) {
|
|
4217
4392
|
throw new Error(`Fallback benchmark runner did not write a JSON result artifact in ${outputDir}`);
|
|
4218
4393
|
}
|
|
@@ -4220,7 +4395,7 @@ function resolveFallbackBenchResultPath(outputDir) {
|
|
|
4220
4395
|
}
|
|
4221
4396
|
|
|
4222
4397
|
// src/openclaw-upgrade-swap.ts
|
|
4223
|
-
import
|
|
4398
|
+
import fs12 from "fs";
|
|
4224
4399
|
import path10 from "path";
|
|
4225
4400
|
function describeError(error) {
|
|
4226
4401
|
return error instanceof Error ? error.message : String(error);
|
|
@@ -4232,7 +4407,7 @@ function createSiblingTempFilePath(targetPath, label) {
|
|
|
4232
4407
|
function resolveAtomicWriteMode(targetPath, explicitMode) {
|
|
4233
4408
|
if (explicitMode !== void 0) return explicitMode;
|
|
4234
4409
|
try {
|
|
4235
|
-
return
|
|
4410
|
+
return fs12.statSync(targetPath).mode & 4095;
|
|
4236
4411
|
} catch (error) {
|
|
4237
4412
|
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
4238
4413
|
return 384;
|
|
@@ -4242,8 +4417,8 @@ function resolveAtomicWriteMode(targetPath, explicitMode) {
|
|
|
4242
4417
|
}
|
|
4243
4418
|
function resolveAtomicReplacementPath(targetPath) {
|
|
4244
4419
|
try {
|
|
4245
|
-
if (
|
|
4246
|
-
return
|
|
4420
|
+
if (fs12.lstatSync(targetPath).isSymbolicLink()) {
|
|
4421
|
+
return fs12.realpathSync(targetPath);
|
|
4247
4422
|
}
|
|
4248
4423
|
} catch (error) {
|
|
4249
4424
|
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
@@ -4260,7 +4435,7 @@ function createSiblingSwapPath(targetDir, label) {
|
|
|
4260
4435
|
function cleanupDisplacedDirectoryBestEffort(displacedDir, context) {
|
|
4261
4436
|
if (!displacedDir) return void 0;
|
|
4262
4437
|
try {
|
|
4263
|
-
|
|
4438
|
+
fs12.rmSync(displacedDir, { recursive: true, force: true });
|
|
4264
4439
|
return void 0;
|
|
4265
4440
|
} catch (error) {
|
|
4266
4441
|
return `Warning: ${context}, but failed to remove the displaced plugin copy at ${displacedDir}: ${describeError(error)}`;
|
|
@@ -4268,43 +4443,43 @@ function cleanupDisplacedDirectoryBestEffort(displacedDir, context) {
|
|
|
4268
4443
|
}
|
|
4269
4444
|
function atomicWriteFileSync(targetPath, data, options = {}) {
|
|
4270
4445
|
const resolvedTargetPath = resolveAtomicReplacementPath(targetPath);
|
|
4271
|
-
|
|
4446
|
+
fs12.mkdirSync(path10.dirname(resolvedTargetPath), { recursive: true });
|
|
4272
4447
|
const tempPath = createSiblingTempFilePath(resolvedTargetPath, "write");
|
|
4273
4448
|
const mode = resolveAtomicWriteMode(resolvedTargetPath, options.mode);
|
|
4274
4449
|
try {
|
|
4275
4450
|
if (options.hooks?.writeTempFileSync) {
|
|
4276
4451
|
options.hooks.writeTempFileSync(tempPath);
|
|
4277
4452
|
} else {
|
|
4278
|
-
|
|
4453
|
+
fs12.writeFileSync(tempPath, data, { mode });
|
|
4279
4454
|
}
|
|
4280
|
-
|
|
4281
|
-
const renameTempFileSync = options.hooks?.renameTempFileSync ??
|
|
4455
|
+
fs12.chmodSync(tempPath, mode);
|
|
4456
|
+
const renameTempFileSync = options.hooks?.renameTempFileSync ?? fs12.renameSync;
|
|
4282
4457
|
renameTempFileSync(tempPath, resolvedTargetPath);
|
|
4283
4458
|
} catch (error) {
|
|
4284
|
-
|
|
4459
|
+
fs12.rmSync(tempPath, { force: true });
|
|
4285
4460
|
throw error;
|
|
4286
4461
|
}
|
|
4287
4462
|
}
|
|
4288
4463
|
function atomicCopyFileSync(sourcePath, targetPath, options = {}) {
|
|
4289
|
-
if (!
|
|
4464
|
+
if (!fs12.existsSync(sourcePath)) return;
|
|
4290
4465
|
const resolvedTargetPath = resolveAtomicReplacementPath(targetPath);
|
|
4291
|
-
|
|
4466
|
+
fs12.mkdirSync(path10.dirname(resolvedTargetPath), { recursive: true });
|
|
4292
4467
|
const tempPath = createSiblingTempFilePath(resolvedTargetPath, "copy");
|
|
4293
|
-
const mode =
|
|
4468
|
+
const mode = fs12.statSync(sourcePath).mode & 4095;
|
|
4294
4469
|
try {
|
|
4295
|
-
const copyTempFileSync = options.hooks?.copyTempFileSync ??
|
|
4470
|
+
const copyTempFileSync = options.hooks?.copyTempFileSync ?? fs12.copyFileSync;
|
|
4296
4471
|
copyTempFileSync(sourcePath, tempPath);
|
|
4297
|
-
|
|
4298
|
-
const renameTempFileSync = options.hooks?.renameTempFileSync ??
|
|
4472
|
+
fs12.chmodSync(tempPath, mode);
|
|
4473
|
+
const renameTempFileSync = options.hooks?.renameTempFileSync ?? fs12.renameSync;
|
|
4299
4474
|
renameTempFileSync(tempPath, resolvedTargetPath);
|
|
4300
4475
|
} catch (error) {
|
|
4301
|
-
|
|
4476
|
+
fs12.rmSync(tempPath, { force: true });
|
|
4302
4477
|
throw error;
|
|
4303
4478
|
}
|
|
4304
4479
|
}
|
|
4305
4480
|
function cleanupRollbackDirectory(rollbackDir) {
|
|
4306
4481
|
if (!rollbackDir) return;
|
|
4307
|
-
|
|
4482
|
+
fs12.rmSync(rollbackDir, { recursive: true, force: true });
|
|
4308
4483
|
}
|
|
4309
4484
|
function cleanupRollbackDirectoryBestEffort(rollbackDir) {
|
|
4310
4485
|
if (!rollbackDir) return void 0;
|
|
@@ -4316,20 +4491,20 @@ function cleanupRollbackDirectoryBestEffort(rollbackDir) {
|
|
|
4316
4491
|
}
|
|
4317
4492
|
}
|
|
4318
4493
|
function restoreDirectoryFromRollback(targetDir, rollbackDir) {
|
|
4319
|
-
if (!
|
|
4494
|
+
if (!fs12.existsSync(rollbackDir)) {
|
|
4320
4495
|
throw new Error(`Rollback directory is missing: ${rollbackDir}`);
|
|
4321
4496
|
}
|
|
4322
|
-
|
|
4323
|
-
const displacedDir =
|
|
4497
|
+
fs12.mkdirSync(path10.dirname(targetDir), { recursive: true });
|
|
4498
|
+
const displacedDir = fs12.existsSync(targetDir) ? createSiblingSwapPath(targetDir, "rollback-restore") : void 0;
|
|
4324
4499
|
if (displacedDir) {
|
|
4325
|
-
|
|
4500
|
+
fs12.renameSync(targetDir, displacedDir);
|
|
4326
4501
|
}
|
|
4327
4502
|
try {
|
|
4328
|
-
|
|
4503
|
+
fs12.renameSync(rollbackDir, targetDir);
|
|
4329
4504
|
} catch (restoreError) {
|
|
4330
|
-
if (displacedDir &&
|
|
4505
|
+
if (displacedDir && fs12.existsSync(displacedDir)) {
|
|
4331
4506
|
try {
|
|
4332
|
-
|
|
4507
|
+
fs12.renameSync(displacedDir, targetDir);
|
|
4333
4508
|
} catch (revertError) {
|
|
4334
4509
|
throw new AggregateError(
|
|
4335
4510
|
[restoreError, revertError],
|
|
@@ -4345,23 +4520,23 @@ function restoreDirectoryFromRollback(targetDir, rollbackDir) {
|
|
|
4345
4520
|
return cleanupDisplacedDirectoryBestEffort(displacedDir, `restored the previous plugin copy into ${targetDir}`);
|
|
4346
4521
|
}
|
|
4347
4522
|
function restoreDirectoryFromBackup(targetDir, backupDir) {
|
|
4348
|
-
if (!
|
|
4523
|
+
if (!fs12.existsSync(backupDir)) {
|
|
4349
4524
|
throw new Error(`Plugin backup directory is missing: ${backupDir}`);
|
|
4350
4525
|
}
|
|
4351
|
-
|
|
4526
|
+
fs12.mkdirSync(path10.dirname(targetDir), { recursive: true });
|
|
4352
4527
|
const stagedDir = createSiblingSwapPath(targetDir, "backup-restore");
|
|
4353
|
-
const displacedDir =
|
|
4354
|
-
|
|
4528
|
+
const displacedDir = fs12.existsSync(targetDir) ? createSiblingSwapPath(targetDir, "pre-backup-restore") : void 0;
|
|
4529
|
+
fs12.cpSync(backupDir, stagedDir, { recursive: true });
|
|
4355
4530
|
if (displacedDir) {
|
|
4356
|
-
|
|
4531
|
+
fs12.renameSync(targetDir, displacedDir);
|
|
4357
4532
|
}
|
|
4358
4533
|
try {
|
|
4359
|
-
|
|
4534
|
+
fs12.renameSync(stagedDir, targetDir);
|
|
4360
4535
|
} catch (restoreError) {
|
|
4361
|
-
|
|
4362
|
-
if (displacedDir &&
|
|
4536
|
+
fs12.rmSync(targetDir, { recursive: true, force: true });
|
|
4537
|
+
if (displacedDir && fs12.existsSync(displacedDir)) {
|
|
4363
4538
|
try {
|
|
4364
|
-
|
|
4539
|
+
fs12.renameSync(displacedDir, targetDir);
|
|
4365
4540
|
} catch (revertError) {
|
|
4366
4541
|
throw new AggregateError(
|
|
4367
4542
|
[restoreError, revertError],
|
|
@@ -4369,7 +4544,7 @@ function restoreDirectoryFromBackup(targetDir, backupDir) {
|
|
|
4369
4544
|
);
|
|
4370
4545
|
}
|
|
4371
4546
|
}
|
|
4372
|
-
|
|
4547
|
+
fs12.rmSync(stagedDir, { recursive: true, force: true });
|
|
4373
4548
|
throw new Error(
|
|
4374
4549
|
`Failed to restore the plugin backup into ${targetDir}. The durable backup remains preserved at ${backupDir}.`,
|
|
4375
4550
|
{ cause: restoreError }
|
|
@@ -4394,7 +4569,7 @@ function rollbackOpenclawUpgrade({
|
|
|
4394
4569
|
let configRemovalAttempted = false;
|
|
4395
4570
|
let pluginRestored = false;
|
|
4396
4571
|
try {
|
|
4397
|
-
if (rollbackDir &&
|
|
4572
|
+
if (rollbackDir && fs12.existsSync(rollbackDir)) {
|
|
4398
4573
|
const cleanupWarning = restoreDirectoryFromRollback(pluginDir, rollbackDir);
|
|
4399
4574
|
notes.push(`Restored previous plugin from rollback copy at ${rollbackDir}`);
|
|
4400
4575
|
if (cleanupWarning) notes.push(cleanupWarning);
|
|
@@ -4404,7 +4579,7 @@ function rollbackOpenclawUpgrade({
|
|
|
4404
4579
|
rollbackRestoreError = error instanceof Error ? error.message : String(error);
|
|
4405
4580
|
}
|
|
4406
4581
|
try {
|
|
4407
|
-
if (!pluginRestored && pluginBackupDir &&
|
|
4582
|
+
if (!pluginRestored && pluginBackupDir && fs12.existsSync(pluginBackupDir)) {
|
|
4408
4583
|
const cleanupWarning = restoreDirectoryFromBackup(pluginDir, pluginBackupDir);
|
|
4409
4584
|
if (rollbackRestoreError) {
|
|
4410
4585
|
notes.push(`Rollback copy restore failed; restored previous plugin from durable backup at ${pluginBackupDir}`);
|
|
@@ -4429,12 +4604,12 @@ function rollbackOpenclawUpgrade({
|
|
|
4429
4604
|
notes.push("No previous plugin copy was available for automatic restore");
|
|
4430
4605
|
}
|
|
4431
4606
|
try {
|
|
4432
|
-
if (configBackupPath &&
|
|
4607
|
+
if (configBackupPath && fs12.existsSync(configBackupPath)) {
|
|
4433
4608
|
restoreFileFromBackup(configPath, configBackupPath);
|
|
4434
4609
|
notes.push(`Restored OpenClaw config from backup at ${configBackupPath}`);
|
|
4435
|
-
} else if (removeConfigIfUnbacked &&
|
|
4610
|
+
} else if (removeConfigIfUnbacked && fs12.existsSync(configPath)) {
|
|
4436
4611
|
configRemovalAttempted = true;
|
|
4437
|
-
|
|
4612
|
+
fs12.rmSync(configPath, { force: true });
|
|
4438
4613
|
notes.push("Removed OpenClaw config created during the failed upgrade");
|
|
4439
4614
|
}
|
|
4440
4615
|
} catch (error) {
|
|
@@ -4487,7 +4662,7 @@ Run this manually when you're ready:
|
|
|
4487
4662
|
|
|
4488
4663
|
// src/openclaw-managed-upgrade-loader.ts
|
|
4489
4664
|
import { execFileSync } from "child_process";
|
|
4490
|
-
import
|
|
4665
|
+
import fs13 from "fs";
|
|
4491
4666
|
import os from "os";
|
|
4492
4667
|
import path11 from "path";
|
|
4493
4668
|
import { fileURLToPath as fileURLToPath3, pathToFileURL as pathToFileURL2 } from "url";
|
|
@@ -4563,7 +4738,7 @@ function buildOpenclawManagedUpgradePackageSpec(version = "latest") {
|
|
|
4563
4738
|
function readCliAdapterRange() {
|
|
4564
4739
|
const moduleDir = path11.dirname(fileURLToPath3(import.meta.url));
|
|
4565
4740
|
const manifestPath = path11.resolve(moduleDir, "../package.json");
|
|
4566
|
-
const manifest = JSON.parse(
|
|
4741
|
+
const manifest = JSON.parse(fs13.readFileSync(manifestPath, "utf8"));
|
|
4567
4742
|
if (manifest.name !== "@remnic/cli") {
|
|
4568
4743
|
throw new Error(`Invalid @remnic/cli package manifest at ${manifestPath}.`);
|
|
4569
4744
|
}
|
|
@@ -4607,7 +4782,7 @@ async function loadOpenclawManagedUpgradeModule(packageSpec, hooks = {}) {
|
|
|
4607
4782
|
const adapterMissing = isSpecifierNotFoundError(error, OPENCLAW_PLUGIN_PACKAGE) || isSpecifierNotFoundError(error, MANAGED_UPGRADE_SPECIFIER) || isManagedUpgradeSubpathMissing(error);
|
|
4608
4783
|
if (!adapterMissing) throw error;
|
|
4609
4784
|
}
|
|
4610
|
-
const temporaryRoot =
|
|
4785
|
+
const temporaryRoot = fs13.mkdtempSync(path11.join(os.tmpdir(), "remnic-openclaw-upgrade-"));
|
|
4611
4786
|
try {
|
|
4612
4787
|
const toolingPackageSpec = `${OPENCLAW_PLUGIN_PACKAGE}@${readCliAdapterRange()}`;
|
|
4613
4788
|
const installArgs = [
|
|
@@ -4622,12 +4797,12 @@ async function loadOpenclawManagedUpgradeModule(packageSpec, hooks = {}) {
|
|
|
4622
4797
|
];
|
|
4623
4798
|
(hooks.runNpmInstall ?? runNpmInstall)(installArgs);
|
|
4624
4799
|
const resolverPath = path11.join(temporaryRoot, "load-managed-upgrade.mjs");
|
|
4625
|
-
|
|
4800
|
+
fs13.writeFileSync(resolverPath, `export * from ${JSON.stringify(MANAGED_UPGRADE_SPECIFIER)};
|
|
4626
4801
|
`, "utf8");
|
|
4627
4802
|
return await importModule(pathToFileURL2(resolverPath).href);
|
|
4628
4803
|
} finally {
|
|
4629
4804
|
try {
|
|
4630
|
-
|
|
4805
|
+
fs13.rmSync(temporaryRoot, { recursive: true, force: true });
|
|
4631
4806
|
} catch (error) {
|
|
4632
4807
|
const detail = error instanceof Error ? error.message : String(error);
|
|
4633
4808
|
console.warn(`Could not remove temporary managed upgrade project at ${temporaryRoot}: ${detail}`);
|
|
@@ -4636,13 +4811,13 @@ async function loadOpenclawManagedUpgradeModule(packageSpec, hooks = {}) {
|
|
|
4636
4811
|
}
|
|
4637
4812
|
|
|
4638
4813
|
// src/remote-daemon.ts
|
|
4639
|
-
import
|
|
4814
|
+
import fs14 from "fs";
|
|
4640
4815
|
function readCompatEnv(primary, legacy) {
|
|
4641
4816
|
return process.env[primary] ?? process.env[legacy];
|
|
4642
4817
|
}
|
|
4643
4818
|
function readRemnicConfigRecord(configPath) {
|
|
4644
4819
|
try {
|
|
4645
|
-
const parsed = JSON.parse(
|
|
4820
|
+
const parsed = JSON.parse(fs14.readFileSync(configPath, "utf8"));
|
|
4646
4821
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
4647
4822
|
return parsed;
|
|
4648
4823
|
}
|
|
@@ -4871,7 +5046,7 @@ async function remoteRecallXray(daemon, request) {
|
|
|
4871
5046
|
}
|
|
4872
5047
|
|
|
4873
5048
|
// src/daemon-service.ts
|
|
4874
|
-
import
|
|
5049
|
+
import fs15 from "fs";
|
|
4875
5050
|
import path12 from "path";
|
|
4876
5051
|
import * as childProcess from "child_process";
|
|
4877
5052
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
@@ -4883,7 +5058,7 @@ function launchdUnloadPlist(plistPath, processApi = childProcess) {
|
|
|
4883
5058
|
processApi.execFileSync("launchctl", ["unload", plistPath], { stdio: "pipe" });
|
|
4884
5059
|
}
|
|
4885
5060
|
function resolveServerBinDetails(options = {}) {
|
|
4886
|
-
const existsSync4 = options.existsSync ??
|
|
5061
|
+
const existsSync4 = options.existsSync ?? fs15.existsSync;
|
|
4887
5062
|
const findCommandOnPath2 = options.findCommandOnPath ?? findCommandOnPath;
|
|
4888
5063
|
const moduleDir = options.moduleDir ?? thisModuleDir;
|
|
4889
5064
|
const packageResolve = options.packageResolve ?? resolveImportSpecifier;
|
|
@@ -4942,8 +5117,8 @@ function resolveServerBin(options = {}) {
|
|
|
4942
5117
|
return resolveServerBinDetails(options).path;
|
|
4943
5118
|
}
|
|
4944
5119
|
function readVerifiedDaemonPid(options) {
|
|
4945
|
-
const readFileSync4 = options.readFileSync ??
|
|
4946
|
-
const unlinkSync = options.unlinkSync ??
|
|
5120
|
+
const readFileSync4 = options.readFileSync ?? fs15.readFileSync;
|
|
5121
|
+
const unlinkSync = options.unlinkSync ?? fs15.unlinkSync;
|
|
4947
5122
|
const processKill = options.processKill ?? process.kill;
|
|
4948
5123
|
const platform = options.platform ?? process.platform;
|
|
4949
5124
|
const execFileSync4 = options.execFileSync ?? ((command, args, execOptions) => childProcess.execFileSync(command, args, execOptions));
|
|
@@ -5043,8 +5218,8 @@ function removePidFileBestEffort(file, unlinkSync) {
|
|
|
5043
5218
|
}
|
|
5044
5219
|
}
|
|
5045
5220
|
function inspectLaunchdPlist(plistPath, options = {}) {
|
|
5046
|
-
const existsSync4 = options.existsSync ??
|
|
5047
|
-
const readFileSync4 = options.readFileSync ??
|
|
5221
|
+
const existsSync4 = options.existsSync ?? fs15.existsSync;
|
|
5222
|
+
const readFileSync4 = options.readFileSync ?? fs15.readFileSync;
|
|
5048
5223
|
if (!existsSync4(plistPath)) {
|
|
5049
5224
|
return {
|
|
5050
5225
|
installed: false,
|
|
@@ -5168,62 +5343,6 @@ function unescapeXml(input) {
|
|
|
5168
5343
|
return input.replaceAll(""", '"').replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">").replaceAll("&", "&");
|
|
5169
5344
|
}
|
|
5170
5345
|
|
|
5171
|
-
// src/cli-args.ts
|
|
5172
|
-
function resolveFlag(args, flag) {
|
|
5173
|
-
const idx = args.indexOf(flag);
|
|
5174
|
-
if (idx === -1 || idx + 1 >= args.length) return void 0;
|
|
5175
|
-
const value = args[idx + 1];
|
|
5176
|
-
return isOptionToken(value) ? void 0 : value;
|
|
5177
|
-
}
|
|
5178
|
-
function isOptionToken(value) {
|
|
5179
|
-
if (!value.startsWith("-")) return false;
|
|
5180
|
-
if (/^-\d/.test(value) || /^-\.\d/.test(value)) return false;
|
|
5181
|
-
return true;
|
|
5182
|
-
}
|
|
5183
|
-
function hasFlag(args, flag) {
|
|
5184
|
-
return args.indexOf(flag) !== -1;
|
|
5185
|
-
}
|
|
5186
|
-
var TAXONOMY_RESOLVE_BOOLEAN_FLAGS = /* @__PURE__ */ new Set(["--json"]);
|
|
5187
|
-
var TAXONOMY_RESOLVE_VALUE_FLAGS = /* @__PURE__ */ new Set(["--category"]);
|
|
5188
|
-
function stripResolveFlags(args, booleanFlags = TAXONOMY_RESOLVE_BOOLEAN_FLAGS, valueFlags = TAXONOMY_RESOLVE_VALUE_FLAGS) {
|
|
5189
|
-
return parseTaxonomyResolveArgs(args, booleanFlags, valueFlags).textParts;
|
|
5190
|
-
}
|
|
5191
|
-
function parseTaxonomyResolveArgs(args, booleanFlags = TAXONOMY_RESOLVE_BOOLEAN_FLAGS, valueFlags = TAXONOMY_RESOLVE_VALUE_FLAGS) {
|
|
5192
|
-
const textParts = [];
|
|
5193
|
-
const values = {};
|
|
5194
|
-
const booleans = /* @__PURE__ */ new Set();
|
|
5195
|
-
let literalText = false;
|
|
5196
|
-
for (let i = 0; i < args.length; i++) {
|
|
5197
|
-
const arg = args[i];
|
|
5198
|
-
if (literalText) {
|
|
5199
|
-
textParts.push(arg);
|
|
5200
|
-
continue;
|
|
5201
|
-
}
|
|
5202
|
-
if (arg === "--") {
|
|
5203
|
-
literalText = true;
|
|
5204
|
-
continue;
|
|
5205
|
-
}
|
|
5206
|
-
if (arg.startsWith("--")) {
|
|
5207
|
-
if (booleanFlags.has(arg)) {
|
|
5208
|
-
booleans.add(arg);
|
|
5209
|
-
continue;
|
|
5210
|
-
}
|
|
5211
|
-
if (valueFlags.has(arg)) {
|
|
5212
|
-
const value = args[i + 1];
|
|
5213
|
-
if (value === void 0 || value.startsWith("--")) {
|
|
5214
|
-
throw new Error(`${arg} requires a value`);
|
|
5215
|
-
}
|
|
5216
|
-
values[arg] = value;
|
|
5217
|
-
i++;
|
|
5218
|
-
continue;
|
|
5219
|
-
}
|
|
5220
|
-
throw new Error(`Unknown flag: ${arg}`);
|
|
5221
|
-
}
|
|
5222
|
-
textParts.push(arg);
|
|
5223
|
-
}
|
|
5224
|
-
return { textParts, values, booleans };
|
|
5225
|
-
}
|
|
5226
|
-
|
|
5227
5346
|
// src/parse-connector-config.ts
|
|
5228
5347
|
function parseConfigAssignment(raw, flag) {
|
|
5229
5348
|
const eqIdx = raw.indexOf("=");
|
|
@@ -5278,7 +5397,7 @@ function stripConfigArgv(args) {
|
|
|
5278
5397
|
}
|
|
5279
5398
|
|
|
5280
5399
|
// src/import-dispatch.ts
|
|
5281
|
-
import
|
|
5400
|
+
import fs16 from "fs";
|
|
5282
5401
|
import {
|
|
5283
5402
|
runImporter,
|
|
5284
5403
|
validateImportBatchSize,
|
|
@@ -5792,7 +5911,7 @@ async function cmdImport(rest, targetFactory, disposeTarget, ioOverrides = {}) {
|
|
|
5792
5911
|
let materializedTarget;
|
|
5793
5912
|
let materializePromise;
|
|
5794
5913
|
const io = {
|
|
5795
|
-
readFile: ioOverrides.readFile ?? (async (p) =>
|
|
5914
|
+
readFile: ioOverrides.readFile ?? (async (p) => fs16.promises.readFile(p, "utf-8")),
|
|
5796
5915
|
loadAdapter: ioOverrides.loadAdapter ?? (async (name) => (await loadImporterModule(name)).adapter),
|
|
5797
5916
|
runImporter: ioOverrides.runImporter ?? runImporter,
|
|
5798
5917
|
getWriteTarget: async () => {
|
|
@@ -5905,7 +6024,7 @@ async function cmdCapture(rest, io) {
|
|
|
5905
6024
|
}
|
|
5906
6025
|
|
|
5907
6026
|
// src/import-lossless-claw-cmd.ts
|
|
5908
|
-
import
|
|
6027
|
+
import fs17 from "fs";
|
|
5909
6028
|
import path14 from "path";
|
|
5910
6029
|
import {
|
|
5911
6030
|
applyLcmSchema,
|
|
@@ -6017,15 +6136,15 @@ async function loadImportLosslessClawModule() {
|
|
|
6017
6136
|
|
|
6018
6137
|
// src/import-lossless-claw-cmd.ts
|
|
6019
6138
|
function assertDirectoryOrAbsent(p, label) {
|
|
6020
|
-
if (
|
|
6139
|
+
if (fs17.existsSync(p) && !fs17.statSync(p).isDirectory()) {
|
|
6021
6140
|
throw new Error(`${label} is not a directory: ${p}`);
|
|
6022
6141
|
}
|
|
6023
6142
|
}
|
|
6024
6143
|
function assertFile(p, label) {
|
|
6025
|
-
if (!
|
|
6144
|
+
if (!fs17.existsSync(p)) {
|
|
6026
6145
|
throw new Error(`${label} does not exist: ${p}`);
|
|
6027
6146
|
}
|
|
6028
|
-
if (!
|
|
6147
|
+
if (!fs17.statSync(p).isFile()) {
|
|
6029
6148
|
throw new Error(`${label} is not a file: ${p}`);
|
|
6030
6149
|
}
|
|
6031
6150
|
}
|
|
@@ -6057,7 +6176,7 @@ async function cmdImportLosslessClaw(argv, io, deps = {}) {
|
|
|
6057
6176
|
try {
|
|
6058
6177
|
if (parsed.dryRun) {
|
|
6059
6178
|
const lcmPath = path14.join(memoryDir, "state", "lcm.sqlite");
|
|
6060
|
-
if (
|
|
6179
|
+
if (fs17.existsSync(lcmPath)) {
|
|
6061
6180
|
destDb = mod.openExistingLcmDatabaseReadOnly(lcmPath);
|
|
6062
6181
|
} else {
|
|
6063
6182
|
destDb = mod.openInMemoryDestinationDatabase();
|
|
@@ -7409,7 +7528,7 @@ async function resolveAllBenchmarks() {
|
|
|
7409
7528
|
if (packageBenchmarks) {
|
|
7410
7529
|
return packageBenchmarks.filter((entry) => entry.runnerAvailable).map((entry) => entry.id);
|
|
7411
7530
|
}
|
|
7412
|
-
if (!
|
|
7531
|
+
if (!fs18.existsSync(EVAL_RUNNER_PATH)) {
|
|
7413
7532
|
return [];
|
|
7414
7533
|
}
|
|
7415
7534
|
return BENCHMARK_CATALOG.filter((entry) => entry.category !== "ingestion").map((entry) => entry.id);
|
|
@@ -7457,7 +7576,7 @@ async function runBenchViaFallback(parsed, benchmarkId, runtimeProfile) {
|
|
|
7457
7576
|
`Fallback benchmark runner does not support provider-backed, gateway, or thinking/timeout flags (${unsupportedOptions.join(", ")}). Build/install @remnic/bench to use those options.`
|
|
7458
7577
|
);
|
|
7459
7578
|
}
|
|
7460
|
-
if (!
|
|
7579
|
+
if (!fs18.existsSync(EVAL_RUNNER_PATH)) {
|
|
7461
7580
|
console.error(
|
|
7462
7581
|
"Benchmark runner not found. Expected eval runner at evals/run.ts or a phase-1 @remnic/bench runtime export."
|
|
7463
7582
|
);
|
|
@@ -7467,7 +7586,7 @@ async function runBenchViaFallback(parsed, benchmarkId, runtimeProfile) {
|
|
|
7467
7586
|
path18.join(CLI_REPO_ROOT, "node_modules", ".bin", "tsx"),
|
|
7468
7587
|
path18.join(CLI_REPO_ROOT, "packages", "remnic-cli", "node_modules", ".bin", "tsx")
|
|
7469
7588
|
];
|
|
7470
|
-
const tsxCmd = tsxCandidates.find((candidate) =>
|
|
7589
|
+
const tsxCmd = tsxCandidates.find((candidate) => fs18.existsSync(candidate)) ?? "tsx";
|
|
7471
7590
|
const fallbackOutputDir = createFallbackBenchOutputDir(
|
|
7472
7591
|
parsed.resultsDir ?? resolveBenchOutputDir(),
|
|
7473
7592
|
benchmarkId,
|
|
@@ -7612,9 +7731,9 @@ var PERSONAMEM_COMPLETION_MARKER = path18.join(
|
|
|
7612
7731
|
);
|
|
7613
7732
|
function resolveRealpathWithinDataset(datasetPath, relativePath) {
|
|
7614
7733
|
try {
|
|
7615
|
-
const datasetRoot =
|
|
7734
|
+
const datasetRoot = fs18.realpathSync(datasetPath);
|
|
7616
7735
|
const candidatePath = path18.resolve(datasetRoot, relativePath);
|
|
7617
|
-
const candidateRealPath =
|
|
7736
|
+
const candidateRealPath = fs18.realpathSync(candidatePath);
|
|
7618
7737
|
const relativeToRoot = path18.relative(datasetRoot, candidateRealPath);
|
|
7619
7738
|
if (relativeToRoot.startsWith("..") || path18.isAbsolute(relativeToRoot)) {
|
|
7620
7739
|
return null;
|
|
@@ -7673,14 +7792,14 @@ function parseCsvRows(raw) {
|
|
|
7673
7792
|
function isPersonaMemDatasetComplete(datasetPath) {
|
|
7674
7793
|
try {
|
|
7675
7794
|
const completionMarkerPath = path18.join(datasetPath, PERSONAMEM_COMPLETION_MARKER);
|
|
7676
|
-
if (
|
|
7795
|
+
if (fs18.statSync(completionMarkerPath).isFile()) {
|
|
7677
7796
|
return true;
|
|
7678
7797
|
}
|
|
7679
7798
|
} catch {
|
|
7680
7799
|
}
|
|
7681
7800
|
const datasetFile = PERSONAMEM_DATASET_FILE_CANDIDATES.find((candidate) => {
|
|
7682
7801
|
try {
|
|
7683
|
-
return
|
|
7802
|
+
return fs18.statSync(path18.join(datasetPath, candidate)).isFile();
|
|
7684
7803
|
} catch {
|
|
7685
7804
|
return false;
|
|
7686
7805
|
}
|
|
@@ -7689,7 +7808,7 @@ function isPersonaMemDatasetComplete(datasetPath) {
|
|
|
7689
7808
|
return false;
|
|
7690
7809
|
}
|
|
7691
7810
|
try {
|
|
7692
|
-
const rows = parseCsvRows(
|
|
7811
|
+
const rows = parseCsvRows(fs18.readFileSync(path18.join(datasetPath, datasetFile), "utf8"));
|
|
7693
7812
|
if (rows.length < 2) {
|
|
7694
7813
|
return false;
|
|
7695
7814
|
}
|
|
@@ -7704,7 +7823,7 @@ function isPersonaMemDatasetComplete(datasetPath) {
|
|
|
7704
7823
|
}
|
|
7705
7824
|
return historyPaths.every((relativePath) => {
|
|
7706
7825
|
const resolvedPath = resolveRealpathWithinDataset(datasetPath, relativePath);
|
|
7707
|
-
return resolvedPath !== null &&
|
|
7826
|
+
return resolvedPath !== null && fs18.statSync(resolvedPath).isFile();
|
|
7708
7827
|
});
|
|
7709
7828
|
} catch {
|
|
7710
7829
|
return false;
|
|
@@ -7712,7 +7831,7 @@ function isPersonaMemDatasetComplete(datasetPath) {
|
|
|
7712
7831
|
}
|
|
7713
7832
|
function hasDatasetFile(datasetPath, relativePath) {
|
|
7714
7833
|
try {
|
|
7715
|
-
return
|
|
7834
|
+
return fs18.statSync(path18.join(datasetPath, relativePath)).isFile();
|
|
7716
7835
|
} catch {
|
|
7717
7836
|
return false;
|
|
7718
7837
|
}
|
|
@@ -7732,10 +7851,10 @@ function memoryAgentBenchDatasetHasRecSysSamples(datasetPath) {
|
|
|
7732
7851
|
return candidateFilenames.some((filename) => {
|
|
7733
7852
|
const filePath = path18.join(datasetPath, filename);
|
|
7734
7853
|
try {
|
|
7735
|
-
if (!
|
|
7854
|
+
if (!fs18.statSync(filePath).isFile()) {
|
|
7736
7855
|
return false;
|
|
7737
7856
|
}
|
|
7738
|
-
const raw =
|
|
7857
|
+
const raw = fs18.readFileSync(filePath, "utf8");
|
|
7739
7858
|
return /"source"\s*:\s*"recsys[_-]/i.test(raw);
|
|
7740
7859
|
} catch {
|
|
7741
7860
|
return false;
|
|
@@ -7751,7 +7870,7 @@ function isMemoryAgentBenchDatasetComplete(datasetPath) {
|
|
|
7751
7870
|
function isDatasetDownloaded(datasetPath, benchmarkId) {
|
|
7752
7871
|
let stats;
|
|
7753
7872
|
try {
|
|
7754
|
-
stats =
|
|
7873
|
+
stats = fs18.statSync(datasetPath);
|
|
7755
7874
|
} catch {
|
|
7756
7875
|
return false;
|
|
7757
7876
|
}
|
|
@@ -7761,7 +7880,7 @@ function isDatasetDownloaded(datasetPath, benchmarkId) {
|
|
|
7761
7880
|
const marker = DOWNLOADED_DATASET_MARKERS[benchmarkId];
|
|
7762
7881
|
if (!marker) {
|
|
7763
7882
|
try {
|
|
7764
|
-
return
|
|
7883
|
+
return fs18.readdirSync(datasetPath).length > 0;
|
|
7765
7884
|
} catch {
|
|
7766
7885
|
return false;
|
|
7767
7886
|
}
|
|
@@ -7769,7 +7888,7 @@ function isDatasetDownloaded(datasetPath, benchmarkId) {
|
|
|
7769
7888
|
if (marker.allOf) {
|
|
7770
7889
|
const hasAllRequiredFiles = marker.allOf.every((name) => {
|
|
7771
7890
|
try {
|
|
7772
|
-
return
|
|
7891
|
+
return fs18.statSync(path18.join(datasetPath, name)).isFile();
|
|
7773
7892
|
} catch {
|
|
7774
7893
|
return false;
|
|
7775
7894
|
}
|
|
@@ -7781,7 +7900,7 @@ function isDatasetDownloaded(datasetPath, benchmarkId) {
|
|
|
7781
7900
|
if (marker.anyOf) {
|
|
7782
7901
|
const hasMarkerFile = marker.anyOf.some((name) => {
|
|
7783
7902
|
try {
|
|
7784
|
-
return
|
|
7903
|
+
return fs18.statSync(path18.join(datasetPath, name)).isFile();
|
|
7785
7904
|
} catch {
|
|
7786
7905
|
return false;
|
|
7787
7906
|
}
|
|
@@ -7799,7 +7918,7 @@ function isDatasetDownloaded(datasetPath, benchmarkId) {
|
|
|
7799
7918
|
}
|
|
7800
7919
|
if (marker.ext) {
|
|
7801
7920
|
try {
|
|
7802
|
-
return
|
|
7921
|
+
return fs18.readdirSync(datasetPath).some(
|
|
7803
7922
|
(name) => name.endsWith(marker.ext) && !marker.exclude?.includes(name)
|
|
7804
7923
|
);
|
|
7805
7924
|
} catch {
|
|
@@ -7811,7 +7930,7 @@ function isDatasetDownloaded(datasetPath, benchmarkId) {
|
|
|
7811
7930
|
async function launchBenchUi(resultsDir) {
|
|
7812
7931
|
const benchUiDir = path18.join(CLI_REPO_ROOT, "packages", "bench-ui");
|
|
7813
7932
|
const pnpmCmd = process.platform === "win32" ? "pnpm.cmd" : "pnpm";
|
|
7814
|
-
if (!
|
|
7933
|
+
if (!fs18.existsSync(path18.join(benchUiDir, "package.json"))) {
|
|
7815
7934
|
console.error("ERROR: @remnic/bench-ui is not available in this checkout.");
|
|
7816
7935
|
process.exit(1);
|
|
7817
7936
|
}
|
|
@@ -7849,13 +7968,13 @@ function listDownloadableBenchmarks() {
|
|
|
7849
7968
|
}
|
|
7850
7969
|
function resolveDatasetDownloadScriptPath() {
|
|
7851
7970
|
const bundled = path18.join(CLI_MODULE_DIR, "assets", "download-datasets.sh");
|
|
7852
|
-
if (
|
|
7971
|
+
if (fs18.existsSync(bundled)) {
|
|
7853
7972
|
return bundled;
|
|
7854
7973
|
}
|
|
7855
7974
|
return path18.join(CLI_REPO_ROOT, "evals", "scripts", "download-datasets.sh");
|
|
7856
7975
|
}
|
|
7857
7976
|
function isRepoCheckout() {
|
|
7858
|
-
return
|
|
7977
|
+
return fs18.existsSync(path18.join(CLI_REPO_ROOT, "pnpm-workspace.yaml")) && fs18.existsSync(path18.join(CLI_REPO_ROOT, "evals", "scripts", "download-datasets.sh"));
|
|
7859
7978
|
}
|
|
7860
7979
|
function runDatasetDownloadScript(scriptPath, benchmarkId, datasetRoot, jsonMode) {
|
|
7861
7980
|
const stdio = jsonMode ? ["inherit", process.stderr, "inherit"] : "inherit";
|
|
@@ -8168,8 +8287,8 @@ async function exportBenchPackageResult(parsed) {
|
|
|
8168
8287
|
...reportCardProvenance ? { reportCardProvenance } : {}
|
|
8169
8288
|
});
|
|
8170
8289
|
if (parsed.output) {
|
|
8171
|
-
|
|
8172
|
-
|
|
8290
|
+
fs18.mkdirSync(path18.dirname(parsed.output), { recursive: true });
|
|
8291
|
+
fs18.writeFileSync(parsed.output, rendered);
|
|
8173
8292
|
console.log(`Exported ${summary.id} as ${parsed.format} to ${parsed.output}`);
|
|
8174
8293
|
return;
|
|
8175
8294
|
}
|
|
@@ -8214,7 +8333,7 @@ async function manageBenchDatasets(parsed) {
|
|
|
8214
8333
|
process.exit(1);
|
|
8215
8334
|
}
|
|
8216
8335
|
const scriptPath = resolveDatasetDownloadScriptPath();
|
|
8217
|
-
if (!
|
|
8336
|
+
if (!fs18.existsSync(scriptPath)) {
|
|
8218
8337
|
console.error(`ERROR: dataset download script not found: ${scriptPath}`);
|
|
8219
8338
|
process.exit(1);
|
|
8220
8339
|
}
|
|
@@ -8414,7 +8533,7 @@ async function calibrateBenchJudges(parsed, rawArgs) {
|
|
|
8414
8533
|
);
|
|
8415
8534
|
process.exit(1);
|
|
8416
8535
|
}
|
|
8417
|
-
const sourceResultSha256 = createHash4("sha256").update(
|
|
8536
|
+
const sourceResultSha256 = createHash4("sha256").update(fs18.readFileSync(latest.path)).digest("hex");
|
|
8418
8537
|
const expandedManifestPath = expandTilde(manifestPath);
|
|
8419
8538
|
if (!bench.resolveLocalLabJudgeProviderConfig) {
|
|
8420
8539
|
console.error(
|
|
@@ -8829,7 +8948,7 @@ function loadPinnedLoCoMoTaskSelector(parsed) {
|
|
|
8829
8948
|
}
|
|
8830
8949
|
let decoded;
|
|
8831
8950
|
try {
|
|
8832
|
-
decoded = JSON.parse(
|
|
8951
|
+
decoded = JSON.parse(fs18.readFileSync(parsed.taskIdsFile, "utf8"));
|
|
8833
8952
|
} catch (error) {
|
|
8834
8953
|
throw new Error(
|
|
8835
8954
|
`Unable to read --task-ids-file ${parsed.taskIdsFile}: ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -9504,7 +9623,7 @@ function resolveBenchReproDatasetDir(datasetDir) {
|
|
|
9504
9623
|
return void 0;
|
|
9505
9624
|
}
|
|
9506
9625
|
try {
|
|
9507
|
-
return
|
|
9626
|
+
return fs18.realpathSync(datasetDir);
|
|
9508
9627
|
} catch {
|
|
9509
9628
|
return datasetDir;
|
|
9510
9629
|
}
|
|
@@ -9558,13 +9677,13 @@ async function writeBenchReproManifestForPackageRun(args) {
|
|
|
9558
9677
|
}
|
|
9559
9678
|
function loadStandaloneConvergeCommandConfig() {
|
|
9560
9679
|
const configPath = resolveConfigPath();
|
|
9561
|
-
const raw =
|
|
9562
|
-
return
|
|
9680
|
+
const raw = fs18.existsSync(configPath) ? JSON.parse(fs18.readFileSync(configPath, "utf8")) : {};
|
|
9681
|
+
return parseConfig9(resolveRemnicConfigRecord8(raw));
|
|
9563
9682
|
}
|
|
9564
9683
|
function parseConvergePluginConfig(value) {
|
|
9565
9684
|
if (value === null || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
9566
9685
|
if (Object.keys(value).length === 0) return void 0;
|
|
9567
|
-
return
|
|
9686
|
+
return parseConfig9(resolveRemnicConfigRecord8(value));
|
|
9568
9687
|
}
|
|
9569
9688
|
function loadConvergeCommandConfig() {
|
|
9570
9689
|
if (readCompatEnv("REMNIC_CONFIG_PATH", "ENGRAM_CONFIG_PATH")) {
|
|
@@ -9587,13 +9706,13 @@ function resolveConfigPath(cliPath) {
|
|
|
9587
9706
|
path18.join(resolveHomeDir(), ".config", "engram", "config.json")
|
|
9588
9707
|
];
|
|
9589
9708
|
for (const candidate of candidates) {
|
|
9590
|
-
if (
|
|
9709
|
+
if (fs18.existsSync(candidate)) return candidate;
|
|
9591
9710
|
}
|
|
9592
9711
|
return path18.join(resolveHomeDir(), ".config", "remnic", "config.json");
|
|
9593
9712
|
}
|
|
9594
9713
|
function resolveExistingBenchRemnicConfigPath(cliPath) {
|
|
9595
9714
|
const configPath = resolveConfigPath(cliPath);
|
|
9596
|
-
if (
|
|
9715
|
+
if (fs18.existsSync(configPath)) {
|
|
9597
9716
|
return configPath;
|
|
9598
9717
|
}
|
|
9599
9718
|
if (cliPath) {
|
|
@@ -9603,7 +9722,7 @@ function resolveExistingBenchRemnicConfigPath(cliPath) {
|
|
|
9603
9722
|
}
|
|
9604
9723
|
function resolveExistingBenchOpenclawConfigPath(cliPath) {
|
|
9605
9724
|
const configPath = resolveOpenclawConfigPath(cliPath);
|
|
9606
|
-
if (
|
|
9725
|
+
if (fs18.existsSync(configPath)) {
|
|
9607
9726
|
return configPath;
|
|
9608
9727
|
}
|
|
9609
9728
|
if (cliPath) {
|
|
@@ -9710,8 +9829,8 @@ function resolveMemoryDir() {
|
|
|
9710
9829
|
const envMemoryDir = readCompatEnv("REMNIC_MEMORY_DIR", "ENGRAM_MEMORY_DIR");
|
|
9711
9830
|
if (envMemoryDir) return normalizeMemoryDirPath(envMemoryDir);
|
|
9712
9831
|
const configPath = resolveConfigPath();
|
|
9713
|
-
const raw =
|
|
9714
|
-
const remnicCfg =
|
|
9832
|
+
const raw = fs18.existsSync(configPath) ? JSON.parse(fs18.readFileSync(configPath, "utf8")) : {};
|
|
9833
|
+
const remnicCfg = resolveRemnicConfigRecord8(raw);
|
|
9715
9834
|
if (typeof remnicCfg.memoryDir === "string" && remnicCfg.memoryDir.length > 0) {
|
|
9716
9835
|
return normalizeMemoryDirPath(remnicCfg.memoryDir);
|
|
9717
9836
|
}
|
|
@@ -9719,18 +9838,18 @@ function resolveMemoryDir() {
|
|
|
9719
9838
|
const standalonePath = path18.join(home, ".remnic", "memory");
|
|
9720
9839
|
const legacyStandalonePath = path18.join(home, ".engram", "memory");
|
|
9721
9840
|
const openclawPath = path18.join(resolveOpenclawStateDir(), "workspace", "memory", "local");
|
|
9722
|
-
if (
|
|
9723
|
-
if (
|
|
9841
|
+
if (fs18.existsSync(standalonePath)) return standalonePath;
|
|
9842
|
+
if (fs18.existsSync(legacyStandalonePath)) return legacyStandalonePath;
|
|
9724
9843
|
return openclawPath;
|
|
9725
9844
|
})();
|
|
9726
9845
|
const manifestPath = getManifestPath();
|
|
9727
|
-
if (
|
|
9846
|
+
if (fs18.existsSync(manifestPath)) {
|
|
9728
9847
|
try {
|
|
9729
9848
|
const active = getActiveSpace();
|
|
9730
9849
|
if (active?.memoryDir) {
|
|
9731
9850
|
const activeMemoryDir = normalizeMemoryDirPath(active.memoryDir);
|
|
9732
|
-
if (!
|
|
9733
|
-
|
|
9851
|
+
if (!fs18.existsSync(activeMemoryDir)) {
|
|
9852
|
+
fs18.mkdirSync(activeMemoryDir, { recursive: true });
|
|
9734
9853
|
}
|
|
9735
9854
|
return activeMemoryDir;
|
|
9736
9855
|
}
|
|
@@ -9779,13 +9898,13 @@ function resolveOpenclawConfigPath(cliPath) {
|
|
|
9779
9898
|
const envPath = process.env.OPENCLAW_CONFIG_PATH || process.env.OPENCLAW_ENGRAM_CONFIG_PATH;
|
|
9780
9899
|
if (envPath) return path18.resolve(expandTilde(envPath));
|
|
9781
9900
|
for (const candidate of DEFAULT_OPENCLAW_CONFIG_PATHS_FOR_DOCTOR) {
|
|
9782
|
-
if (
|
|
9901
|
+
if (fs18.existsSync(candidate)) return candidate;
|
|
9783
9902
|
}
|
|
9784
9903
|
return path18.join(resolveOpenclawStateDir(), "openclaw.json");
|
|
9785
9904
|
}
|
|
9786
9905
|
function readOpenclawConfig(configPath) {
|
|
9787
|
-
if (!
|
|
9788
|
-
const raw =
|
|
9906
|
+
if (!fs18.existsSync(configPath)) return {};
|
|
9907
|
+
const raw = fs18.readFileSync(configPath, "utf-8");
|
|
9789
9908
|
let parsed;
|
|
9790
9909
|
try {
|
|
9791
9910
|
parsed = JSON.parse(raw);
|
|
@@ -9887,9 +10006,9 @@ function formatOpenclawUpgradeStamp(now = /* @__PURE__ */ new Date()) {
|
|
|
9887
10006
|
return `${yyyy}${mm}${dd}-${hh}${min}${ss}`;
|
|
9888
10007
|
}
|
|
9889
10008
|
function backupPathIfPresent(sourcePath, backupPath) {
|
|
9890
|
-
if (!
|
|
9891
|
-
|
|
9892
|
-
|
|
10009
|
+
if (!fs18.existsSync(sourcePath)) return false;
|
|
10010
|
+
fs18.mkdirSync(path18.dirname(backupPath), { recursive: true });
|
|
10011
|
+
fs18.cpSync(sourcePath, backupPath, { recursive: true });
|
|
9893
10012
|
return true;
|
|
9894
10013
|
}
|
|
9895
10014
|
function restartOpenclawGateway() {
|
|
@@ -9908,7 +10027,7 @@ function restartOpenclawGateway() {
|
|
|
9908
10027
|
}
|
|
9909
10028
|
function cmdInit() {
|
|
9910
10029
|
const configPath = path18.join(process.cwd(), "remnic.config.json");
|
|
9911
|
-
if (
|
|
10030
|
+
if (fs18.existsSync(configPath)) {
|
|
9912
10031
|
console.log(`Config already exists: ${configPath}`);
|
|
9913
10032
|
return;
|
|
9914
10033
|
}
|
|
@@ -9924,7 +10043,7 @@ function cmdInit() {
|
|
|
9924
10043
|
authToken: "${REMNIC_AUTH_TOKEN}"
|
|
9925
10044
|
}
|
|
9926
10045
|
};
|
|
9927
|
-
|
|
10046
|
+
fs18.writeFileSync(configPath, JSON.stringify(template, null, 2) + "\n");
|
|
9928
10047
|
console.log(`Created ${configPath}`);
|
|
9929
10048
|
console.log("\nSet these environment variables:");
|
|
9930
10049
|
console.log(" export OPENAI_API_KEY=sk-...");
|
|
@@ -10344,11 +10463,11 @@ async function cmdQuery(queryText, json, explain) {
|
|
|
10344
10463
|
printQueryResult(result, json);
|
|
10345
10464
|
return;
|
|
10346
10465
|
}
|
|
10347
|
-
|
|
10466
|
+
initLogger4();
|
|
10348
10467
|
const configPath = resolveConfigPath();
|
|
10349
|
-
const raw =
|
|
10350
|
-
const remnicCfg =
|
|
10351
|
-
const config =
|
|
10468
|
+
const raw = fs18.existsSync(configPath) ? JSON.parse(fs18.readFileSync(configPath, "utf8")) : {};
|
|
10469
|
+
const remnicCfg = resolveRemnicConfigRecord8(raw);
|
|
10470
|
+
const config = parseConfig9(remnicCfg);
|
|
10352
10471
|
const orchestrator = new Orchestrator5(config);
|
|
10353
10472
|
await orchestrator.initialize();
|
|
10354
10473
|
const service = new EngramAccessService2(orchestrator);
|
|
@@ -10524,11 +10643,11 @@ async function cmdXray(rest) {
|
|
|
10524
10643
|
await runXrayCommand(rest, xrayCliIo((request) => remoteRecallXray(remote, request)));
|
|
10525
10644
|
return;
|
|
10526
10645
|
}
|
|
10527
|
-
|
|
10646
|
+
initLogger4();
|
|
10528
10647
|
const configPath = resolveConfigPath();
|
|
10529
|
-
const raw =
|
|
10530
|
-
const remnicCfg =
|
|
10531
|
-
const config =
|
|
10648
|
+
const raw = fs18.existsSync(configPath) ? JSON.parse(fs18.readFileSync(configPath, "utf8")) : {};
|
|
10649
|
+
const remnicCfg = resolveRemnicConfigRecord8(raw);
|
|
10650
|
+
const config = parseConfig9(remnicCfg);
|
|
10532
10651
|
const orchestrator = new Orchestrator5(config);
|
|
10533
10652
|
await orchestrator.initialize();
|
|
10534
10653
|
await orchestrator.deferredReady;
|
|
@@ -10556,36 +10675,45 @@ async function runWhoKnowsCommand(rest, io) {
|
|
|
10556
10675
|
});
|
|
10557
10676
|
io.stdout(renderWhoKnows(result, parsed.json));
|
|
10558
10677
|
}
|
|
10559
|
-
async function
|
|
10560
|
-
|
|
10561
|
-
parseWhoKnowsCliOptions(topic, options);
|
|
10562
|
-
if (resolveRemoteDaemon(resolveConfigPath())) {
|
|
10563
|
-
throw new Error("who-knows: remote daemon mode is not supported yet; run with a local config");
|
|
10564
|
-
}
|
|
10565
|
-
initLogger3();
|
|
10678
|
+
async function withLocalService(fn) {
|
|
10679
|
+
initLogger4();
|
|
10566
10680
|
const configPath = resolveConfigPath();
|
|
10567
|
-
const raw =
|
|
10568
|
-
const
|
|
10569
|
-
const orchestrator = new Orchestrator5(config);
|
|
10681
|
+
const raw = fs18.existsSync(configPath) ? JSON.parse(fs18.readFileSync(configPath, "utf8")) : {};
|
|
10682
|
+
const orchestrator = new Orchestrator5(parseConfig9(resolveRemnicConfigRecord8(raw)));
|
|
10570
10683
|
await orchestrator.initialize();
|
|
10571
10684
|
await orchestrator.deferredReady;
|
|
10572
10685
|
const service = new EngramAccessService2(orchestrator);
|
|
10573
10686
|
try {
|
|
10574
|
-
await
|
|
10575
|
-
whoKnows: (request) => service.whoKnows(request),
|
|
10576
|
-
stdout: (line) => console.log(line)
|
|
10577
|
-
});
|
|
10687
|
+
return await fn(service, orchestrator);
|
|
10578
10688
|
} finally {
|
|
10579
10689
|
orchestrator.abortDeferredInit();
|
|
10580
10690
|
await orchestrator.destroy();
|
|
10581
10691
|
}
|
|
10582
10692
|
}
|
|
10693
|
+
async function cmdWhoKnows(rest) {
|
|
10694
|
+
const { topic, options } = extractWhoKnowsRawArgs(rest);
|
|
10695
|
+
parseWhoKnowsCliOptions(topic, options);
|
|
10696
|
+
if (resolveRemoteDaemon(resolveConfigPath())) {
|
|
10697
|
+
throw new Error("who-knows: remote daemon mode is not supported yet; run with a local config");
|
|
10698
|
+
}
|
|
10699
|
+
await withLocalService((service) => runWhoKnowsCommand(rest, {
|
|
10700
|
+
whoKnows: (request) => service.whoKnows(request),
|
|
10701
|
+
stdout: (line) => console.log(line)
|
|
10702
|
+
}));
|
|
10703
|
+
}
|
|
10704
|
+
async function cmdPromotionCandidates(rest) {
|
|
10705
|
+
if (resolveRemoteDaemon(resolveConfigPath())) throw new Error("promotion-candidates: remote daemon mode is not supported yet; run with a local config");
|
|
10706
|
+
await withLocalService((service) => runPromotionCandidatesCommand(rest, {
|
|
10707
|
+
promotionCandidates: (request) => service.promotionCandidates(request),
|
|
10708
|
+
stdout: (line) => console.log(line)
|
|
10709
|
+
}));
|
|
10710
|
+
}
|
|
10583
10711
|
async function cmdVersions(rest) {
|
|
10584
|
-
|
|
10712
|
+
initLogger4();
|
|
10585
10713
|
const configPath = resolveConfigPath();
|
|
10586
|
-
const raw =
|
|
10587
|
-
const remnicCfg =
|
|
10588
|
-
const config =
|
|
10714
|
+
const raw = fs18.existsSync(configPath) ? JSON.parse(fs18.readFileSync(configPath, "utf8")) : {};
|
|
10715
|
+
const remnicCfg = resolveRemnicConfigRecord8(raw);
|
|
10716
|
+
const config = parseConfig9(remnicCfg);
|
|
10589
10717
|
if (!config.versioningEnabled) {
|
|
10590
10718
|
console.error("Page versioning is disabled (versioningEnabled = false).");
|
|
10591
10719
|
process.exit(1);
|
|
@@ -10697,11 +10825,11 @@ Options:
|
|
|
10697
10825
|
}
|
|
10698
10826
|
}
|
|
10699
10827
|
async function cmdEnrich(rest) {
|
|
10700
|
-
|
|
10828
|
+
initLogger4();
|
|
10701
10829
|
const configPath = resolveConfigPath();
|
|
10702
|
-
const raw =
|
|
10703
|
-
const remnicCfg =
|
|
10704
|
-
const config =
|
|
10830
|
+
const raw = fs18.existsSync(configPath) ? JSON.parse(fs18.readFileSync(configPath, "utf8")) : {};
|
|
10831
|
+
const remnicCfg = resolveRemnicConfigRecord8(raw);
|
|
10832
|
+
const config = parseConfig9(remnicCfg);
|
|
10705
10833
|
const subcommand = rest[0];
|
|
10706
10834
|
if (subcommand === "audit") {
|
|
10707
10835
|
const memoryDir2 = expandTilde(config.memoryDir);
|
|
@@ -10890,80 +11018,12 @@ Registered providers:`);
|
|
|
10890
11018
|
${totalPersisted} candidate(s) persisted to memory store.`);
|
|
10891
11019
|
}
|
|
10892
11020
|
}
|
|
10893
|
-
async function cmdProcedural(rest) {
|
|
10894
|
-
initLogger3();
|
|
10895
|
-
const subcommand = rest[0];
|
|
10896
|
-
if (!subcommand || subcommand === "--help" || subcommand === "-h") {
|
|
10897
|
-
console.log(`remnic procedural \u2014 Procedural memory operations (issue #567)
|
|
10898
|
-
|
|
10899
|
-
Usage:
|
|
10900
|
-
remnic procedural stats [--format json|text] [--memory-dir <path>]
|
|
10901
|
-
|
|
10902
|
-
Subcommands:
|
|
10903
|
-
stats Print counts by status + recent activity + active config.
|
|
10904
|
-
|
|
10905
|
-
Shared with:
|
|
10906
|
-
GET /engram/v1/procedural/stats
|
|
10907
|
-
MCP remnic.procedural_stats (alias engram.procedural_stats)`);
|
|
10908
|
-
return;
|
|
10909
|
-
}
|
|
10910
|
-
if (subcommand !== "stats") {
|
|
10911
|
-
console.error(
|
|
10912
|
-
`Unknown procedural subcommand "${subcommand}". Run \`remnic procedural --help\` for usage.`
|
|
10913
|
-
);
|
|
10914
|
-
process.exit(1);
|
|
10915
|
-
}
|
|
10916
|
-
const args = rest.slice(1);
|
|
10917
|
-
const formatPresent = hasFlag(args, "--format");
|
|
10918
|
-
const formatRaw = resolveFlag(args, "--format");
|
|
10919
|
-
if (formatPresent && (formatRaw === void 0 || formatRaw === null)) {
|
|
10920
|
-
console.error(
|
|
10921
|
-
"--format requires a value. Use `--format json` or `--format text`."
|
|
10922
|
-
);
|
|
10923
|
-
process.exit(1);
|
|
10924
|
-
}
|
|
10925
|
-
const format = (() => {
|
|
10926
|
-
if (!formatPresent || formatRaw === void 0 || formatRaw === null) {
|
|
10927
|
-
return "text";
|
|
10928
|
-
}
|
|
10929
|
-
const normalized = String(formatRaw).trim().toLowerCase();
|
|
10930
|
-
if (normalized !== "text" && normalized !== "json") {
|
|
10931
|
-
console.error(
|
|
10932
|
-
`Invalid --format "${formatRaw}". Allowed: text, json.`
|
|
10933
|
-
);
|
|
10934
|
-
process.exit(1);
|
|
10935
|
-
}
|
|
10936
|
-
return normalized;
|
|
10937
|
-
})();
|
|
10938
|
-
const memoryDirPresent = hasFlag(args, "--memory-dir");
|
|
10939
|
-
const memoryDirOverride = resolveFlag(args, "--memory-dir");
|
|
10940
|
-
if (memoryDirPresent && (memoryDirOverride === void 0 || memoryDirOverride === null)) {
|
|
10941
|
-
console.error(
|
|
10942
|
-
"--memory-dir requires a path. Omit the flag to use the resolved default."
|
|
10943
|
-
);
|
|
10944
|
-
process.exit(1);
|
|
10945
|
-
}
|
|
10946
|
-
const configPath = resolveConfigPath();
|
|
10947
|
-
const raw = fs17.existsSync(configPath) ? JSON.parse(fs17.readFileSync(configPath, "utf8")) : {};
|
|
10948
|
-
const remnicCfg = resolveRemnicConfigRecord7(raw);
|
|
10949
|
-
const config = parseConfig8(remnicCfg);
|
|
10950
|
-
const memoryDir = expandTilde(
|
|
10951
|
-
typeof memoryDirOverride === "string" && memoryDirOverride.length > 0 ? memoryDirOverride : config.memoryDir ?? resolveMemoryDir()
|
|
10952
|
-
);
|
|
10953
|
-
const storage = new StorageManager2(memoryDir);
|
|
10954
|
-
const report = await computeProcedureStats({ storage, config });
|
|
10955
|
-
if (format === "json") {
|
|
10956
|
-
process.stdout.write(JSON.stringify(report, null, 2) + "\n");
|
|
10957
|
-
return;
|
|
10958
|
-
}
|
|
10959
|
-
process.stdout.write(formatProcedureStatsText(report));
|
|
10960
|
-
}
|
|
10961
11021
|
async function cmdExtensions(action, rest) {
|
|
10962
|
-
|
|
11022
|
+
initLogger4();
|
|
10963
11023
|
const configPath = resolveConfigPath();
|
|
10964
|
-
const raw =
|
|
10965
|
-
const remnicCfg =
|
|
10966
|
-
const config =
|
|
11024
|
+
const raw = fs18.existsSync(configPath) ? JSON.parse(fs18.readFileSync(configPath, "utf8")) : {};
|
|
11025
|
+
const remnicCfg = resolveRemnicConfigRecord8(raw);
|
|
11026
|
+
const config = parseConfig9(remnicCfg);
|
|
10967
11027
|
const root = resolveExtensionsRoot(config);
|
|
10968
11028
|
const noopLog = { warn: () => {
|
|
10969
11029
|
}, debug: () => {
|
|
@@ -11012,7 +11072,7 @@ Root: ${root}`);
|
|
|
11012
11072
|
const extensions = await discoverMemoryExtensions(root, warnLog);
|
|
11013
11073
|
let entries = [];
|
|
11014
11074
|
try {
|
|
11015
|
-
entries =
|
|
11075
|
+
entries = fs18.readdirSync(root);
|
|
11016
11076
|
} catch {
|
|
11017
11077
|
console.log(`Extensions root does not exist: ${root}`);
|
|
11018
11078
|
process.exitCode = 0;
|
|
@@ -11023,7 +11083,7 @@ Root: ${root}`);
|
|
|
11023
11083
|
for (const entry of entries) {
|
|
11024
11084
|
const entryPath = path18.join(root, entry);
|
|
11025
11085
|
try {
|
|
11026
|
-
if (!
|
|
11086
|
+
if (!fs18.statSync(entryPath).isDirectory()) continue;
|
|
11027
11087
|
} catch {
|
|
11028
11088
|
continue;
|
|
11029
11089
|
}
|
|
@@ -11053,11 +11113,11 @@ Root: ${root}`);
|
|
|
11053
11113
|
}
|
|
11054
11114
|
}
|
|
11055
11115
|
async function cmdBriefing(rest) {
|
|
11056
|
-
|
|
11116
|
+
initLogger4();
|
|
11057
11117
|
const configPath = resolveConfigPath();
|
|
11058
|
-
const raw =
|
|
11059
|
-
const remnicCfg =
|
|
11060
|
-
const config =
|
|
11118
|
+
const raw = fs18.existsSync(configPath) ? JSON.parse(fs18.readFileSync(configPath, "utf8")) : {};
|
|
11119
|
+
const remnicCfg = resolveRemnicConfigRecord8(raw);
|
|
11120
|
+
const config = parseConfig9(remnicCfg);
|
|
11061
11121
|
if (!config.briefing.enabled) {
|
|
11062
11122
|
console.error("Briefing is disabled in config (briefing.enabled = false).");
|
|
11063
11123
|
process.exit(1);
|
|
@@ -11135,10 +11195,10 @@ async function cmdBriefing(rest) {
|
|
|
11135
11195
|
if (save) {
|
|
11136
11196
|
try {
|
|
11137
11197
|
const saveDir = resolveBriefingSaveDir(config.briefing.saveDir);
|
|
11138
|
-
|
|
11198
|
+
fs18.mkdirSync(saveDir, { recursive: true });
|
|
11139
11199
|
const filename = briefingFilename(new Date(result.window.to), format);
|
|
11140
11200
|
const filePath = path18.join(saveDir, filename);
|
|
11141
|
-
|
|
11201
|
+
fs18.writeFileSync(filePath, payload + (payload.endsWith("\n") ? "" : "\n"));
|
|
11142
11202
|
console.error(`Saved briefing: ${filePath}`);
|
|
11143
11203
|
} catch (err) {
|
|
11144
11204
|
console.error(`Failed to save briefing: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -11156,7 +11216,7 @@ async function cmdDoctor() {
|
|
|
11156
11216
|
detail: `${nodeVersion} (requires >= 22.12.0)`
|
|
11157
11217
|
});
|
|
11158
11218
|
const configPath = resolveConfigPath();
|
|
11159
|
-
const configExists =
|
|
11219
|
+
const configExists = fs18.existsSync(configPath);
|
|
11160
11220
|
checks.push({ name: "Config file", ok: configExists, detail: configPath });
|
|
11161
11221
|
let standaloneConfig;
|
|
11162
11222
|
let standaloneConfigError;
|
|
@@ -11164,11 +11224,11 @@ async function cmdDoctor() {
|
|
|
11164
11224
|
let configuredNs = { invalid: false };
|
|
11165
11225
|
if (configExists) {
|
|
11166
11226
|
try {
|
|
11167
|
-
const raw = JSON.parse(
|
|
11168
|
-
const remnicCfg =
|
|
11227
|
+
const raw = JSON.parse(fs18.readFileSync(configPath, "utf8"));
|
|
11228
|
+
const remnicCfg = resolveRemnicConfigRecord8(raw);
|
|
11169
11229
|
standaloneOpenaiApiKeyExplicitlyFalse = isOpenaiApiKeyDisabled(remnicCfg.openaiApiKey);
|
|
11170
11230
|
configuredNs = readConfiguredNamespace(remnicCfg);
|
|
11171
|
-
standaloneConfig =
|
|
11231
|
+
standaloneConfig = parseConfig9(remnicCfg);
|
|
11172
11232
|
} catch (err) {
|
|
11173
11233
|
standaloneConfigError = err instanceof Error ? err.message : String(err);
|
|
11174
11234
|
}
|
|
@@ -11177,10 +11237,10 @@ async function cmdDoctor() {
|
|
|
11177
11237
|
try {
|
|
11178
11238
|
memoryDir = resolveMemoryDir();
|
|
11179
11239
|
} catch {
|
|
11180
|
-
memoryDir =
|
|
11240
|
+
memoryDir = parseConfig9({}).memoryDir;
|
|
11181
11241
|
}
|
|
11182
11242
|
try {
|
|
11183
|
-
|
|
11243
|
+
fs18.mkdirSync(memoryDir, { recursive: true });
|
|
11184
11244
|
checks.push({ name: "Memory directory", ok: true, detail: memoryDir });
|
|
11185
11245
|
} catch {
|
|
11186
11246
|
checks.push({ name: "Memory directory", ok: false, detail: `cannot create ${memoryDir}` });
|
|
@@ -11209,7 +11269,7 @@ async function cmdDoctor() {
|
|
|
11209
11269
|
});
|
|
11210
11270
|
if (nsPolicyCheck) checks.push(nsPolicyCheck);
|
|
11211
11271
|
const openclawConfigPath = resolveOpenclawConfigPath();
|
|
11212
|
-
const openclawConfigExists =
|
|
11272
|
+
const openclawConfigExists = fs18.existsSync(openclawConfigPath);
|
|
11213
11273
|
let openclawConfig = {};
|
|
11214
11274
|
let openclawConfigValid = false;
|
|
11215
11275
|
let openclawPluginModeConfigured = false;
|
|
@@ -11217,7 +11277,7 @@ async function cmdDoctor() {
|
|
|
11217
11277
|
let activeOpenclawEntryConfig = null;
|
|
11218
11278
|
if (openclawConfigExists) {
|
|
11219
11279
|
try {
|
|
11220
|
-
const parsed = JSON.parse(
|
|
11280
|
+
const parsed = JSON.parse(fs18.readFileSync(openclawConfigPath, "utf-8"));
|
|
11221
11281
|
if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
|
|
11222
11282
|
openclawConfig = parsed;
|
|
11223
11283
|
openclawConfigValid = true;
|
|
@@ -11297,9 +11357,9 @@ async function cmdDoctor() {
|
|
|
11297
11357
|
let memDirOk = false;
|
|
11298
11358
|
let memDirDetail = `${resolvedMemDir} (not found)`;
|
|
11299
11359
|
let memDirRemediation = `Run \`remnic openclaw install --memory-dir "${resolvedMemDir}"\` to create the directory.`;
|
|
11300
|
-
if (
|
|
11360
|
+
if (fs18.existsSync(resolvedMemDir)) {
|
|
11301
11361
|
try {
|
|
11302
|
-
const stat2 =
|
|
11362
|
+
const stat2 = fs18.statSync(resolvedMemDir);
|
|
11303
11363
|
if (stat2.isDirectory()) {
|
|
11304
11364
|
memDirOk = true;
|
|
11305
11365
|
memDirDetail = resolvedMemDir;
|
|
@@ -11454,12 +11514,12 @@ async function cmdDoctor() {
|
|
|
11454
11514
|
}
|
|
11455
11515
|
function cmdConfig() {
|
|
11456
11516
|
const configPath = resolveConfigPath();
|
|
11457
|
-
if (!
|
|
11517
|
+
if (!fs18.existsSync(configPath)) {
|
|
11458
11518
|
console.log("No config file found. Run `remnic init` to create one.");
|
|
11459
11519
|
return;
|
|
11460
11520
|
}
|
|
11461
11521
|
console.log(`Config: ${configPath}`);
|
|
11462
|
-
const rawConfig =
|
|
11522
|
+
const rawConfig = fs18.readFileSync(configPath, "utf8");
|
|
11463
11523
|
const redacted = rawConfig.replace(
|
|
11464
11524
|
/("(?:openaiApiKey|localLlmApiKey|authToken|apiKey|remoteSearchApiKey|meilisearchApiKey|opikApiKey)"\s*:\s*")([^"]*)(")/g,
|
|
11465
11525
|
"$1[REDACTED]$3"
|
|
@@ -11563,13 +11623,13 @@ async function cmdReview(action, rest) {
|
|
|
11563
11623
|
console.error("Usage: remnic review <approve|dismiss|flag> <id>");
|
|
11564
11624
|
process.exit(1);
|
|
11565
11625
|
}
|
|
11566
|
-
const storage = new
|
|
11626
|
+
const storage = new StorageManager3(memoryDir);
|
|
11567
11627
|
const configPath = resolveConfigPath();
|
|
11568
11628
|
let tombstonesConfig = null;
|
|
11569
11629
|
try {
|
|
11570
|
-
const rawCfg =
|
|
11571
|
-
const remnicCfg =
|
|
11572
|
-
const config =
|
|
11630
|
+
const rawCfg = fs18.existsSync(configPath) ? JSON.parse(fs18.readFileSync(configPath, "utf8")) : {};
|
|
11631
|
+
const remnicCfg = resolveRemnicConfigRecord8(rawCfg);
|
|
11632
|
+
const config = parseConfig9(remnicCfg);
|
|
11573
11633
|
tombstonesConfig = {
|
|
11574
11634
|
enabled: config.tombstonesEnabled,
|
|
11575
11635
|
semanticMatch: config.tombstonesSemanticMatch,
|
|
@@ -12311,7 +12371,7 @@ async function pushOfflineFileContent(args) {
|
|
|
12311
12371
|
}
|
|
12312
12372
|
async function pushOfflineFileContentFromChunkReader(args) {
|
|
12313
12373
|
const filePath = resolveOfflineDirectHydrationPath(args.memoryDir, args.file.path);
|
|
12314
|
-
const stat2 =
|
|
12374
|
+
const stat2 = fs18.statSync(filePath);
|
|
12315
12375
|
if (stat2.mtimeMs !== args.file.mtimeMs) {
|
|
12316
12376
|
throw new Error(`local file changed while pushing offline content: ${args.file.path}`);
|
|
12317
12377
|
}
|
|
@@ -12802,7 +12862,7 @@ function advanceOfflineBaseFilesForSuccessfulPush(options) {
|
|
|
12802
12862
|
return [...next.values()].sort((left, right) => left.path.localeCompare(right.path));
|
|
12803
12863
|
}
|
|
12804
12864
|
async function runOfflineSyncOnce(options) {
|
|
12805
|
-
|
|
12865
|
+
fs18.mkdirSync(options.memoryDir, { recursive: true });
|
|
12806
12866
|
let activeStatePath = options.statePath;
|
|
12807
12867
|
let priorState = await readOfflineSyncState(activeStatePath);
|
|
12808
12868
|
let syncNamespace = options.namespace ?? priorState?.namespace;
|
|
@@ -13435,7 +13495,7 @@ Environment fallbacks:
|
|
|
13435
13495
|
const configPath = resolveConfigPath();
|
|
13436
13496
|
let config;
|
|
13437
13497
|
try {
|
|
13438
|
-
const rawConfig =
|
|
13498
|
+
const rawConfig = fs18.existsSync(configPath) ? JSON.parse(fs18.readFileSync(configPath, "utf8")) : {};
|
|
13439
13499
|
config = parseConfigQuietly(pickOfflineConfigRecord(rawConfig));
|
|
13440
13500
|
} catch {
|
|
13441
13501
|
throw new Error(
|
|
@@ -13450,7 +13510,7 @@ Environment fallbacks:
|
|
|
13450
13510
|
const statePath = statePathExplicit ? path18.resolve(expandTilde(stateOverride)) : remoteUrl !== void 0 ? defaultOfflineSyncStatePath(memoryDir, remoteUrl, namespace) : void 0;
|
|
13451
13511
|
if (action === "prepare") {
|
|
13452
13512
|
if (!remoteUrl || !token || !statePath) throw new Error("offline prepare requires remote URL and token");
|
|
13453
|
-
|
|
13513
|
+
fs18.mkdirSync(memoryDir, { recursive: true });
|
|
13454
13514
|
const remoteSnapshot = await fetchOfflineSnapshot({
|
|
13455
13515
|
remoteUrl,
|
|
13456
13516
|
token,
|
|
@@ -13549,7 +13609,7 @@ Environment fallbacks:
|
|
|
13549
13609
|
return;
|
|
13550
13610
|
}
|
|
13551
13611
|
if (action === "status") {
|
|
13552
|
-
|
|
13612
|
+
fs18.mkdirSync(memoryDir, { recursive: true });
|
|
13553
13613
|
const state = statePath ? await readOfflineSyncState(statePath) : null;
|
|
13554
13614
|
if (state && remoteUrl && statePath) {
|
|
13555
13615
|
assertOfflineStateMatches({
|
|
@@ -13687,7 +13747,7 @@ function cmdDedup(json) {
|
|
|
13687
13747
|
function readInstalledConnectorConfig(configPath, fallback) {
|
|
13688
13748
|
if (!configPath) return fallback;
|
|
13689
13749
|
try {
|
|
13690
|
-
const parsed = JSON.parse(
|
|
13750
|
+
const parsed = JSON.parse(fs18.readFileSync(configPath, "utf8"));
|
|
13691
13751
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return fallback;
|
|
13692
13752
|
const { token: _token, ...config } = parsed;
|
|
13693
13753
|
return config;
|
|
@@ -13865,7 +13925,7 @@ async function cmdConnectors(action, rest, json) {
|
|
|
13865
13925
|
const pub = factory();
|
|
13866
13926
|
const available = await pub.isHostAvailable();
|
|
13867
13927
|
const extRoot = available ? await pub.resolveExtensionRoot() : "(host not installed)";
|
|
13868
|
-
const extensionExists = available && extRoot ?
|
|
13928
|
+
const extensionExists = available && extRoot ? fs18.existsSync(extRoot) : false;
|
|
13869
13929
|
publisherChecks.push({
|
|
13870
13930
|
name: `Publisher: ${targetHostId}`,
|
|
13871
13931
|
ok: !available || extensionExists,
|
|
@@ -13939,7 +13999,7 @@ async function cmdConnectors(action, rest, json) {
|
|
|
13939
13999
|
let connectorsCfg;
|
|
13940
14000
|
const configPath = resolveConfigPath();
|
|
13941
14001
|
try {
|
|
13942
|
-
const raw =
|
|
14002
|
+
const raw = fs18.existsSync(configPath) ? JSON.parse(fs18.readFileSync(configPath, "utf8")) : {};
|
|
13943
14003
|
connectorsCfg = parseConfigQuietly(raw).connectors;
|
|
13944
14004
|
} catch {
|
|
13945
14005
|
process.stderr.write(
|
|
@@ -14013,11 +14073,11 @@ async function cmdConnectors(action, rest, json) {
|
|
|
14013
14073
|
process.exitCode = 2;
|
|
14014
14074
|
return;
|
|
14015
14075
|
}
|
|
14016
|
-
|
|
14076
|
+
initLogger4();
|
|
14017
14077
|
const configPath = resolveConfigPath();
|
|
14018
|
-
const raw =
|
|
14019
|
-
const remnicCfg =
|
|
14020
|
-
const config =
|
|
14078
|
+
const raw = fs18.existsSync(configPath) ? JSON.parse(fs18.readFileSync(configPath, "utf8")) : {};
|
|
14079
|
+
const remnicCfg = resolveRemnicConfigRecord8(raw);
|
|
14080
|
+
const config = parseConfig9(remnicCfg);
|
|
14021
14081
|
const orchestrator = new Orchestrator5(config);
|
|
14022
14082
|
try {
|
|
14023
14083
|
await orchestrator.initialize();
|
|
@@ -14140,9 +14200,9 @@ async function cmdConnectorsMarketplace(subAction, rest, json) {
|
|
|
14140
14200
|
console.error(`connectors marketplace: ${err instanceof Error ? err.message : String(err)}`);
|
|
14141
14201
|
process.exit(1);
|
|
14142
14202
|
}
|
|
14143
|
-
const rawConfig =
|
|
14144
|
-
const pluginConfig =
|
|
14145
|
-
const config =
|
|
14203
|
+
const rawConfig = fs18.existsSync(configPath) ? JSON.parse(fs18.readFileSync(configPath, "utf8")) : {};
|
|
14204
|
+
const pluginConfig = resolveRemnicConfigRecord8(rawConfig);
|
|
14205
|
+
const config = parseConfig9(pluginConfig);
|
|
14146
14206
|
if (subAction === "generate") {
|
|
14147
14207
|
let outputDir;
|
|
14148
14208
|
try {
|
|
@@ -14162,13 +14222,13 @@ async function cmdConnectorsMarketplace(subAction, rest, json) {
|
|
|
14162
14222
|
} else if (subAction === "validate") {
|
|
14163
14223
|
const targetPath = rest.filter((a) => !a.startsWith("--"))[0] ?? path18.join(process.cwd(), "marketplace.json");
|
|
14164
14224
|
const resolved = path18.resolve(targetPath);
|
|
14165
|
-
if (!
|
|
14225
|
+
if (!fs18.existsSync(resolved)) {
|
|
14166
14226
|
console.error(`File not found: ${resolved}`);
|
|
14167
14227
|
process.exit(1);
|
|
14168
14228
|
}
|
|
14169
14229
|
let parsed;
|
|
14170
14230
|
try {
|
|
14171
|
-
parsed = JSON.parse(
|
|
14231
|
+
parsed = JSON.parse(fs18.readFileSync(resolved, "utf8"));
|
|
14172
14232
|
} catch {
|
|
14173
14233
|
console.error(`Invalid JSON in ${resolved}`);
|
|
14174
14234
|
process.exit(1);
|
|
@@ -14339,12 +14399,14 @@ async function cmdSpace(action, rest, json) {
|
|
|
14339
14399
|
}
|
|
14340
14400
|
const result = await promoteSpace(sourceId, targetId, {
|
|
14341
14401
|
force: rest.includes("--force"),
|
|
14342
|
-
forceOverwrite: rest.includes("--force-overwrite")
|
|
14402
|
+
forceOverwrite: rest.includes("--force-overwrite"),
|
|
14403
|
+
allowUserSubject: rest.includes("--allow-user-subject")
|
|
14343
14404
|
});
|
|
14344
14405
|
if (json) {
|
|
14345
14406
|
console.log(JSON.stringify(result, null, 2));
|
|
14346
14407
|
} else {
|
|
14347
14408
|
console.log(`Promoted ${result.memoriesPromoted} memories`);
|
|
14409
|
+
if (result.subjectWarnings && result.subjectWarnings.length > 0) console.log(`Subject-guard warnings: ${result.subjectWarnings.length} (see --json)`);
|
|
14348
14410
|
if (result.conflicts.length > 0) console.log(`Conflicts: ${result.conflicts.length}`);
|
|
14349
14411
|
console.log(`Duration: ${result.durationMs}ms`);
|
|
14350
14412
|
}
|
|
@@ -14367,11 +14429,11 @@ async function cmdSpace(action, rest, json) {
|
|
|
14367
14429
|
}
|
|
14368
14430
|
}
|
|
14369
14431
|
async function cmdLegacyBenchmark(action, rest, json) {
|
|
14370
|
-
|
|
14432
|
+
initLogger4();
|
|
14371
14433
|
const configPath = resolveConfigPath();
|
|
14372
|
-
const raw =
|
|
14373
|
-
const remnicCfg =
|
|
14374
|
-
const config =
|
|
14434
|
+
const raw = fs18.existsSync(configPath) ? JSON.parse(fs18.readFileSync(configPath, "utf8")) : {};
|
|
14435
|
+
const remnicCfg = resolveRemnicConfigRecord8(raw);
|
|
14436
|
+
const config = parseConfig9(remnicCfg);
|
|
14375
14437
|
const orchestrator = new Orchestrator5(config);
|
|
14376
14438
|
const service = new EngramAccessService2(orchestrator);
|
|
14377
14439
|
const { runBenchSuite, loadBaseline, checkRegression } = await loadBenchModule();
|
|
@@ -14774,7 +14836,7 @@ function readPid() {
|
|
|
14774
14836
|
function inferPort() {
|
|
14775
14837
|
try {
|
|
14776
14838
|
const configPath = resolveConfigPath();
|
|
14777
|
-
const raw = JSON.parse(
|
|
14839
|
+
const raw = JSON.parse(fs18.readFileSync(configPath, "utf8"));
|
|
14778
14840
|
return raw.server?.port ?? 4318;
|
|
14779
14841
|
} catch {
|
|
14780
14842
|
return 4318;
|
|
@@ -14869,13 +14931,13 @@ function daemonInstall() {
|
|
|
14869
14931
|
process.exit(1);
|
|
14870
14932
|
}
|
|
14871
14933
|
const vars = { HOME: home, NODE_PATH: nodePath, REMNIC_SERVER_BIN: serverBin };
|
|
14872
|
-
|
|
14934
|
+
fs18.mkdirSync(LOGS_DIR, { recursive: true });
|
|
14873
14935
|
if (isMacOS()) {
|
|
14874
14936
|
const templatePath = path18.resolve(import.meta.dirname, "../templates/launchd/ai.remnic.daemon.plist");
|
|
14875
|
-
const template =
|
|
14937
|
+
const template = fs18.readFileSync(templatePath, "utf8");
|
|
14876
14938
|
const plist = renderTemplate(template, vars);
|
|
14877
|
-
|
|
14878
|
-
|
|
14939
|
+
fs18.mkdirSync(path18.dirname(LAUNCHD_PLIST_PATH), { recursive: true });
|
|
14940
|
+
fs18.writeFileSync(LAUNCHD_PLIST_PATH, plist);
|
|
14879
14941
|
try {
|
|
14880
14942
|
launchdLoadPlist(LAUNCHD_PLIST_PATH);
|
|
14881
14943
|
} catch (err) {
|
|
@@ -14892,10 +14954,10 @@ function daemonInstall() {
|
|
|
14892
14954
|
console.log(` Logs: ${LOGS_DIR}/daemon.log`);
|
|
14893
14955
|
} else if (isLinux()) {
|
|
14894
14956
|
const templatePath = path18.resolve(import.meta.dirname, "../templates/systemd/remnic.service");
|
|
14895
|
-
const template =
|
|
14957
|
+
const template = fs18.readFileSync(templatePath, "utf8");
|
|
14896
14958
|
const unit = renderTemplate(template, vars);
|
|
14897
|
-
|
|
14898
|
-
|
|
14959
|
+
fs18.mkdirSync(path18.dirname(SYSTEMD_UNIT_PATH), { recursive: true });
|
|
14960
|
+
fs18.writeFileSync(SYSTEMD_UNIT_PATH, unit);
|
|
14899
14961
|
try {
|
|
14900
14962
|
childProcess2.execSync("systemctl --user daemon-reload", { stdio: "pipe" });
|
|
14901
14963
|
} catch (err) {
|
|
@@ -14931,7 +14993,7 @@ function daemonUninstall() {
|
|
|
14931
14993
|
} catch {
|
|
14932
14994
|
}
|
|
14933
14995
|
try {
|
|
14934
|
-
|
|
14996
|
+
fs18.unlinkSync(plistPath);
|
|
14935
14997
|
removed = true;
|
|
14936
14998
|
console.log(`Removed launchd service: ${plistPath}`);
|
|
14937
14999
|
} catch {
|
|
@@ -14951,7 +15013,7 @@ function daemonUninstall() {
|
|
|
14951
15013
|
let removed = false;
|
|
14952
15014
|
for (const unitPath of SYSTEMD_UNIT_PATHS) {
|
|
14953
15015
|
try {
|
|
14954
|
-
|
|
15016
|
+
fs18.unlinkSync(unitPath);
|
|
14955
15017
|
removed = true;
|
|
14956
15018
|
console.log(`Removed systemd service: ${unitPath}`);
|
|
14957
15019
|
} catch {
|
|
@@ -15018,13 +15080,13 @@ async function daemonStatus() {
|
|
|
15018
15080
|
console.log(` Port: ${port}`);
|
|
15019
15081
|
console.log(` Service: ${serviceInstalled ? "installed" : "not installed"}`);
|
|
15020
15082
|
console.log(` Platform: ${process.platform}`);
|
|
15021
|
-
console.log(` PID file: ${
|
|
15022
|
-
console.log(` Log file: ${
|
|
15083
|
+
console.log(` PID file: ${fs18.existsSync(PID_FILE) ? PID_FILE : LEGACY_PID_FILE}`);
|
|
15084
|
+
console.log(` Log file: ${fs18.existsSync(LOG_FILE) ? LOG_FILE : LEGACY_LOG_FILE}`);
|
|
15023
15085
|
try {
|
|
15024
15086
|
const configPath = resolveConfigPath();
|
|
15025
|
-
const raw =
|
|
15026
|
-
const remnicCfg =
|
|
15027
|
-
const config =
|
|
15087
|
+
const raw = fs18.existsSync(configPath) ? JSON.parse(fs18.readFileSync(configPath, "utf8")) : {};
|
|
15088
|
+
const remnicCfg = resolveRemnicConfigRecord8(raw);
|
|
15089
|
+
const config = parseConfig9(remnicCfg);
|
|
15028
15090
|
const extRoot = resolveExtensionsRoot(config);
|
|
15029
15091
|
const noopLog = { warn: () => {
|
|
15030
15092
|
}, debug: () => {
|
|
@@ -15063,9 +15125,9 @@ function daemonStart() {
|
|
|
15063
15125
|
return;
|
|
15064
15126
|
}
|
|
15065
15127
|
}
|
|
15066
|
-
|
|
15067
|
-
|
|
15068
|
-
const logStream =
|
|
15128
|
+
fs18.mkdirSync(PID_DIR, { recursive: true });
|
|
15129
|
+
fs18.mkdirSync(LOGS_DIR, { recursive: true });
|
|
15130
|
+
const logStream = fs18.openSync(LOG_FILE, "a");
|
|
15069
15131
|
const serverBin = resolveServerBin();
|
|
15070
15132
|
const isSource = serverBin.endsWith(".ts");
|
|
15071
15133
|
let cmd;
|
|
@@ -15087,7 +15149,7 @@ function daemonStart() {
|
|
|
15087
15149
|
}
|
|
15088
15150
|
});
|
|
15089
15151
|
child.unref();
|
|
15090
|
-
|
|
15152
|
+
fs18.writeFileSync(PID_FILE, String(child.pid));
|
|
15091
15153
|
console.log(`Started remnic server (pid ${child.pid})`);
|
|
15092
15154
|
console.log(` Log: ${LOG_FILE}`);
|
|
15093
15155
|
}
|
|
@@ -15121,11 +15183,11 @@ function daemonStop() {
|
|
|
15121
15183
|
console.log("Process not found (cleaning up PID file)");
|
|
15122
15184
|
}
|
|
15123
15185
|
try {
|
|
15124
|
-
|
|
15186
|
+
fs18.unlinkSync(PID_FILE);
|
|
15125
15187
|
} catch {
|
|
15126
15188
|
}
|
|
15127
15189
|
try {
|
|
15128
|
-
|
|
15190
|
+
fs18.unlinkSync(LEGACY_PID_FILE);
|
|
15129
15191
|
} catch {
|
|
15130
15192
|
}
|
|
15131
15193
|
}
|
|
@@ -15251,11 +15313,11 @@ async function promptYesNo(question, defaultYes = true) {
|
|
|
15251
15313
|
});
|
|
15252
15314
|
}
|
|
15253
15315
|
async function cmdBinary(rest) {
|
|
15254
|
-
|
|
15316
|
+
initLogger4();
|
|
15255
15317
|
const configPath = resolveConfigPath();
|
|
15256
|
-
const raw =
|
|
15257
|
-
const remnicCfg =
|
|
15258
|
-
const config =
|
|
15318
|
+
const raw = fs18.existsSync(configPath) ? JSON.parse(fs18.readFileSync(configPath, "utf8")) : {};
|
|
15319
|
+
const remnicCfg = resolveRemnicConfigRecord8(raw);
|
|
15320
|
+
const config = parseConfig9(remnicCfg);
|
|
15259
15321
|
const memoryDir = resolveMemoryDir();
|
|
15260
15322
|
const blConfig = {
|
|
15261
15323
|
enabled: config.binaryLifecycleEnabled,
|
|
@@ -15444,7 +15506,7 @@ async function cmdOpenclawInstall(opts) {
|
|
|
15444
15506
|
} else if (slotIsActiveLegacy) {
|
|
15445
15507
|
changes.push(` Slot left as "${REMNIC_OPENCLAW_LEGACY_PLUGIN_ID}" \u2014 re-run with --yes to activate the new entry`);
|
|
15446
15508
|
}
|
|
15447
|
-
if (!
|
|
15509
|
+
if (!fs18.existsSync(memoryDir)) changes.push(`+ Will create memory directory: ${memoryDir}`);
|
|
15448
15510
|
if (hasLegacy && migrateLegacy) {
|
|
15449
15511
|
changes.push(`~ Legacy '${REMNIC_OPENCLAW_LEGACY_PLUGIN_ID}' entry retained (safe to remove after verifying hooks fire)`);
|
|
15450
15512
|
}
|
|
@@ -15464,8 +15526,8 @@ async function cmdOpenclawInstall(opts) {
|
|
|
15464
15526
|
Resulting plugins.slots.memory: ${dryRunPlugins.slots?.memory ?? "(unset)"}`);
|
|
15465
15527
|
return;
|
|
15466
15528
|
}
|
|
15467
|
-
if (
|
|
15468
|
-
const st =
|
|
15529
|
+
if (fs18.existsSync(memoryDir)) {
|
|
15530
|
+
const st = fs18.statSync(memoryDir);
|
|
15469
15531
|
if (!st.isDirectory()) {
|
|
15470
15532
|
throw new Error(
|
|
15471
15533
|
`Cannot use ${memoryDir} as the memory directory \u2014 a file already exists at that path.
|
|
@@ -15473,12 +15535,12 @@ Remove it first and re-run, or choose a different path with --memory-dir.`
|
|
|
15473
15535
|
);
|
|
15474
15536
|
}
|
|
15475
15537
|
} else {
|
|
15476
|
-
|
|
15538
|
+
fs18.mkdirSync(memoryDir, { recursive: true });
|
|
15477
15539
|
console.log(`Created memory directory: ${memoryDir}`);
|
|
15478
15540
|
}
|
|
15479
15541
|
const configDir = path18.dirname(configPath);
|
|
15480
|
-
if (!
|
|
15481
|
-
|
|
15542
|
+
if (!fs18.existsSync(configDir)) {
|
|
15543
|
+
fs18.mkdirSync(configDir, { recursive: true });
|
|
15482
15544
|
}
|
|
15483
15545
|
atomicWriteFileSync(configPath, JSON.stringify(updatedConfig, null, 2) + "\n");
|
|
15484
15546
|
console.log("\nDone! Summary of changes:");
|
|
@@ -15507,7 +15569,7 @@ async function cmdOpenclawUpgrade(opts) {
|
|
|
15507
15569
|
const legacyPluginDirForBackup = opts.legacyPluginDirForBackup ? resolveOpenclawLegacyPluginDir(opts.legacyPluginDirForBackup) : void 0;
|
|
15508
15570
|
const fallbackMemoryDir = path18.join(resolveOpenclawStateDir(), "workspace", "memory", "local");
|
|
15509
15571
|
const packageSpec = buildOpenclawManagedUpgradePackageSpec(opts.version);
|
|
15510
|
-
const configExistedBefore =
|
|
15572
|
+
const configExistedBefore = fs18.existsSync(configPath);
|
|
15511
15573
|
const existingConfig = readOpenclawConfig(configPath);
|
|
15512
15574
|
const { entries, slots } = parseOpenclawPluginState(existingConfig, configPath);
|
|
15513
15575
|
const preservedMemoryDir = opts.memoryDir ? path18.resolve(expandTilde(opts.memoryDir)) : resolveCurrentOpenclawMemoryDir(entries, slots, fallbackMemoryDir);
|
|
@@ -15732,15 +15794,15 @@ async function cmdOpenclawMigrateEngram(opts) {
|
|
|
15732
15794
|
}
|
|
15733
15795
|
function createOpenclawUpgradeBackupDir() {
|
|
15734
15796
|
const backupsRoot = path18.join(resolveOpenclawStateDir(), "backups");
|
|
15735
|
-
|
|
15736
|
-
return
|
|
15797
|
+
fs18.mkdirSync(backupsRoot, { recursive: true });
|
|
15798
|
+
return fs18.mkdtempSync(path18.join(backupsRoot, `remnic-openclaw-upgrade-${formatOpenclawUpgradeStamp()}-`));
|
|
15737
15799
|
}
|
|
15738
15800
|
async function cmdTaxonomy(rest) {
|
|
15739
|
-
|
|
15801
|
+
initLogger4();
|
|
15740
15802
|
const configPath = resolveConfigPath();
|
|
15741
|
-
const raw =
|
|
15742
|
-
const remnicCfg =
|
|
15743
|
-
const config =
|
|
15803
|
+
const raw = fs18.existsSync(configPath) ? JSON.parse(fs18.readFileSync(configPath, "utf8")) : {};
|
|
15804
|
+
const remnicCfg = resolveRemnicConfigRecord8(raw);
|
|
15805
|
+
const config = parseConfig9(remnicCfg);
|
|
15744
15806
|
if (!config.taxonomyEnabled) {
|
|
15745
15807
|
console.error(
|
|
15746
15808
|
"Taxonomy is disabled in config (taxonomyEnabled = false). Enable it to use taxonomy commands."
|
|
@@ -15776,8 +15838,8 @@ async function cmdTaxonomy(rest) {
|
|
|
15776
15838
|
console.log(doc);
|
|
15777
15839
|
if (config.taxonomyAutoGenResolver) {
|
|
15778
15840
|
const resolverPath = path18.join(config.memoryDir, ".taxonomy", "RESOLVER.md");
|
|
15779
|
-
|
|
15780
|
-
|
|
15841
|
+
fs18.mkdirSync(path18.dirname(resolverPath), { recursive: true });
|
|
15842
|
+
fs18.writeFileSync(resolverPath, doc);
|
|
15781
15843
|
console.error(`Written: ${resolverPath}`);
|
|
15782
15844
|
}
|
|
15783
15845
|
break;
|
|
@@ -15823,7 +15885,7 @@ async function cmdTaxonomy(rest) {
|
|
|
15823
15885
|
if (config.taxonomyAutoGenResolver) {
|
|
15824
15886
|
const doc = generateResolverDocument(taxonomy);
|
|
15825
15887
|
const resolverPath = path18.join(config.memoryDir, ".taxonomy", "RESOLVER.md");
|
|
15826
|
-
|
|
15888
|
+
fs18.writeFileSync(resolverPath, doc);
|
|
15827
15889
|
console.error(`Regenerated: ${resolverPath}`);
|
|
15828
15890
|
}
|
|
15829
15891
|
break;
|
|
@@ -15854,7 +15916,7 @@ async function cmdTaxonomy(rest) {
|
|
|
15854
15916
|
if (config.taxonomyAutoGenResolver) {
|
|
15855
15917
|
const doc = generateResolverDocument(taxonomy);
|
|
15856
15918
|
const resolverPath = path18.join(config.memoryDir, ".taxonomy", "RESOLVER.md");
|
|
15857
|
-
|
|
15919
|
+
fs18.writeFileSync(resolverPath, doc);
|
|
15858
15920
|
console.error(`Regenerated: ${resolverPath}`);
|
|
15859
15921
|
}
|
|
15860
15922
|
break;
|
|
@@ -16045,12 +16107,12 @@ async function runTrainingExport(args, stdout = process.stdout) {
|
|
|
16045
16107
|
`Unknown training-export format "${args.format}". ${validList}`
|
|
16046
16108
|
);
|
|
16047
16109
|
}
|
|
16048
|
-
if (!
|
|
16110
|
+
if (!fs18.existsSync(args.memoryDir)) {
|
|
16049
16111
|
throw new Error(
|
|
16050
16112
|
`--memory-dir "${args.memoryDir}" does not exist. Provide the path to an existing memory directory.`
|
|
16051
16113
|
);
|
|
16052
16114
|
}
|
|
16053
|
-
if (!
|
|
16115
|
+
if (!fs18.statSync(args.memoryDir).isDirectory()) {
|
|
16054
16116
|
throw new Error(
|
|
16055
16117
|
`--memory-dir "${args.memoryDir}" is not a directory. Provide the path to a memory directory, not a file.`
|
|
16056
16118
|
);
|
|
@@ -16136,10 +16198,10 @@ async function runTrainingExport(args, stdout = process.stdout) {
|
|
|
16136
16198
|
}
|
|
16137
16199
|
const formatted = adapter.formatRecords(records);
|
|
16138
16200
|
const outDir = path18.dirname(args.output);
|
|
16139
|
-
|
|
16201
|
+
fs18.mkdirSync(outDir, { recursive: true });
|
|
16140
16202
|
const tmpPath = `${args.output}.tmp-${process.pid}-${Date.now()}`;
|
|
16141
|
-
|
|
16142
|
-
|
|
16203
|
+
fs18.writeFileSync(tmpPath, formatted, "utf-8");
|
|
16204
|
+
fs18.renameSync(tmpPath, args.output);
|
|
16143
16205
|
stdout.write(
|
|
16144
16206
|
`Exported ${records.length} records to ${args.output} (${adapter.name} format)
|
|
16145
16207
|
`
|
|
@@ -16191,6 +16253,9 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
16191
16253
|
case "who-knows":
|
|
16192
16254
|
await cmdWhoKnows(rest);
|
|
16193
16255
|
break;
|
|
16256
|
+
case "promotion-candidates":
|
|
16257
|
+
await cmdPromotionCandidates(rest);
|
|
16258
|
+
break;
|
|
16194
16259
|
case "security":
|
|
16195
16260
|
await cmdSecurity(rest);
|
|
16196
16261
|
break;
|
|
@@ -16314,7 +16379,7 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
16314
16379
|
}
|
|
16315
16380
|
}, 500);
|
|
16316
16381
|
};
|
|
16317
|
-
|
|
16382
|
+
fs18.watch(memoryDir, { recursive: true }, (_event, filename) => {
|
|
16318
16383
|
if (filename && filename.startsWith(".")) return;
|
|
16319
16384
|
rebuild();
|
|
16320
16385
|
});
|
|
@@ -16322,12 +16387,12 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
16322
16387
|
});
|
|
16323
16388
|
} else if (subAction === "validate") {
|
|
16324
16389
|
const treeDir = outputDir;
|
|
16325
|
-
if (!
|
|
16390
|
+
if (!fs18.existsSync(treeDir)) {
|
|
16326
16391
|
console.error(`Context tree not found at ${treeDir}. Run 'remnic tree generate' first.`);
|
|
16327
16392
|
process.exit(1);
|
|
16328
16393
|
}
|
|
16329
16394
|
const indexPath = path18.join(treeDir, "INDEX.md");
|
|
16330
|
-
if (!
|
|
16395
|
+
if (!fs18.existsSync(indexPath)) {
|
|
16331
16396
|
console.error(`INDEX.md missing in ${treeDir}. Tree may be corrupt \u2014 regenerate.`);
|
|
16332
16397
|
process.exit(1);
|
|
16333
16398
|
}
|
|
@@ -16449,7 +16514,7 @@ Options:
|
|
|
16449
16514
|
break;
|
|
16450
16515
|
}
|
|
16451
16516
|
case "procedural": {
|
|
16452
|
-
await
|
|
16517
|
+
await runProceduralBinaryCommand(rest);
|
|
16453
16518
|
break;
|
|
16454
16519
|
}
|
|
16455
16520
|
case "extensions": {
|
|
@@ -16509,9 +16574,9 @@ Other:
|
|
|
16509
16574
|
let wearablesService;
|
|
16510
16575
|
try {
|
|
16511
16576
|
const configPath = resolveConfigPath();
|
|
16512
|
-
const raw =
|
|
16513
|
-
const remnicCfg =
|
|
16514
|
-
const config =
|
|
16577
|
+
const raw = fs18.existsSync(configPath) ? JSON.parse(fs18.readFileSync(configPath, "utf8")) : {};
|
|
16578
|
+
const remnicCfg = resolveRemnicConfigRecord8(raw);
|
|
16579
|
+
const config = parseConfig9(remnicCfg);
|
|
16515
16580
|
wearablesOrchestrator = new Orchestrator5(config);
|
|
16516
16581
|
await wearablesOrchestrator.initialize();
|
|
16517
16582
|
await wearablesOrchestrator.deferredReady;
|
|
@@ -16567,9 +16632,9 @@ Other:
|
|
|
16567
16632
|
const targetFactory = async () => {
|
|
16568
16633
|
if (!orchestratorSingleton) {
|
|
16569
16634
|
const configPath = resolveConfigPath();
|
|
16570
|
-
const raw =
|
|
16571
|
-
const remnicCfg =
|
|
16572
|
-
const config =
|
|
16635
|
+
const raw = fs18.existsSync(configPath) ? JSON.parse(fs18.readFileSync(configPath, "utf8")) : {};
|
|
16636
|
+
const remnicCfg = resolveRemnicConfigRecord8(raw);
|
|
16637
|
+
const config = parseConfig9(remnicCfg);
|
|
16573
16638
|
orchestratorSingleton = new Orchestrator5(config);
|
|
16574
16639
|
await orchestratorSingleton.initialize();
|
|
16575
16640
|
await orchestratorSingleton.deferredReady;
|
|
@@ -16821,6 +16886,11 @@ Usage:
|
|
|
16821
16886
|
Print procedural memory stats (counts + recency + config). Mirrors
|
|
16822
16887
|
GET /engram/v1/procedural/stats and remnic.procedural_stats MCP tool
|
|
16823
16888
|
(issue #567).
|
|
16889
|
+
remnic procedural maintain [--apply] [--format json|text] [--memory-dir <path>]
|
|
16890
|
+
Run procedure library-health maintenance (issue #2370): shadow report of
|
|
16891
|
+
merge / repair-flag / retire proposals from outcome telemetry; --apply
|
|
16892
|
+
executes them (requires procedural.maintenance.enabled). Mirrors the
|
|
16893
|
+
remnic.procedure_library_maintenance MCP tool.
|
|
16824
16894
|
remnic training:export --format <name> --output <path> [options]
|
|
16825
16895
|
Export memories as a fine-tuning dataset (issue #459). Run
|
|
16826
16896
|
'remnic training:export --help' for the full option list.
|