@remnic/cli 9.65.1 → 9.65.3
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 +660 -450
- 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 fs19 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 parseConfig10,
|
|
31
31
|
isOpenaiApiKeyDisabled,
|
|
32
32
|
resolveEnvVars,
|
|
33
|
-
resolveRemnicConfigRecord as
|
|
34
|
-
Orchestrator as
|
|
33
|
+
resolveRemnicConfigRecord as resolveRemnicConfigRecord9,
|
|
34
|
+
Orchestrator as Orchestrator6,
|
|
35
35
|
EngramAccessService as EngramAccessService2,
|
|
36
|
-
initLogger as
|
|
36
|
+
initLogger as initLogger5,
|
|
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,330 @@ 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
|
+
|
|
455
|
+
// src/commands/drift.ts
|
|
456
|
+
import fs5 from "fs";
|
|
457
|
+
import {
|
|
458
|
+
Orchestrator as Orchestrator3,
|
|
459
|
+
initLogger as initLogger2,
|
|
460
|
+
parseConfig as parseConfig5,
|
|
461
|
+
resolveRemnicConfigRecord as resolveRemnicConfigRecord5,
|
|
462
|
+
runPreferenceDriftScan
|
|
463
|
+
} from "@remnic/core";
|
|
464
|
+
async function runDriftBinaryCommand(rest) {
|
|
465
|
+
initLogger2();
|
|
466
|
+
const subcommand = rest[0];
|
|
467
|
+
if (!subcommand || subcommand === "--help" || subcommand === "-h") {
|
|
468
|
+
console.log(`remnic drift \u2014 Preference drift detection (issue #2371)
|
|
469
|
+
|
|
470
|
+
Usage:
|
|
471
|
+
remnic drift scan [--apply] [--namespace <ns>] [--format json|text] [--memory-dir <path>]
|
|
472
|
+
|
|
473
|
+
Subcommands:
|
|
474
|
+
scan Classify aging preference memories as corroborated /
|
|
475
|
+
stale / drifted from recent evidence. Reports only by
|
|
476
|
+
default. --apply stamps lastCorroborated / driftState
|
|
477
|
+
and opens one review item per drifted preference
|
|
478
|
+
(requires driftDetection.enabled in config). Never
|
|
479
|
+
auto-deletes and never auto-supersedes.
|
|
480
|
+
|
|
481
|
+
Shared with:
|
|
482
|
+
MCP remnic.preference_drift_scan (alias engram.preference_drift_scan)
|
|
483
|
+
|
|
484
|
+
Resolve a drifted item with the existing review surface:
|
|
485
|
+
remnic.review_list / remnic.review_resolve, verbs: keep, supersede, archive`);
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
488
|
+
if (subcommand !== "scan") {
|
|
489
|
+
console.error(`Unknown drift subcommand "${subcommand}". Run \`remnic drift --help\` for usage.`);
|
|
490
|
+
process.exit(1);
|
|
491
|
+
}
|
|
492
|
+
const args = rest.slice(1);
|
|
493
|
+
const formatPresent = hasFlag(args, "--format");
|
|
494
|
+
const formatRaw = resolveFlag(args, "--format");
|
|
495
|
+
if (formatPresent && (formatRaw === void 0 || formatRaw === null)) {
|
|
496
|
+
console.error("--format requires a value. Use `--format json` or `--format text`.");
|
|
497
|
+
process.exit(1);
|
|
498
|
+
}
|
|
499
|
+
const format = (() => {
|
|
500
|
+
if (!formatPresent || formatRaw === void 0 || formatRaw === null) return "text";
|
|
501
|
+
const normalized = String(formatRaw).trim().toLowerCase();
|
|
502
|
+
if (normalized !== "text" && normalized !== "json") {
|
|
503
|
+
console.error(`Invalid --format "${formatRaw}". Allowed: text, json.`);
|
|
504
|
+
process.exit(1);
|
|
505
|
+
}
|
|
506
|
+
return normalized;
|
|
507
|
+
})();
|
|
508
|
+
const memoryDirPresent = hasFlag(args, "--memory-dir");
|
|
509
|
+
const memoryDirOverride = resolveFlag(args, "--memory-dir");
|
|
510
|
+
if (memoryDirPresent && (memoryDirOverride === void 0 || memoryDirOverride === null)) {
|
|
511
|
+
console.error("--memory-dir requires a path. Omit the flag to use the resolved default.");
|
|
512
|
+
process.exit(1);
|
|
513
|
+
}
|
|
514
|
+
const namespacePresent = hasFlag(args, "--namespace");
|
|
515
|
+
const namespaceOverride = resolveFlag(args, "--namespace");
|
|
516
|
+
if (namespacePresent && (namespaceOverride === void 0 || namespaceOverride === null)) {
|
|
517
|
+
console.error("--namespace requires a value. Omit the flag to scan the default namespace.");
|
|
518
|
+
process.exit(1);
|
|
519
|
+
}
|
|
520
|
+
const configPath = resolveConfigPath();
|
|
521
|
+
const raw = fs5.existsSync(configPath) ? JSON.parse(fs5.readFileSync(configPath, "utf8")) : {};
|
|
522
|
+
const config = parseConfig5(resolveRemnicConfigRecord5(raw));
|
|
523
|
+
const memoryDirOverridden = typeof memoryDirOverride === "string" && memoryDirOverride.length > 0;
|
|
524
|
+
const memoryDir = expandTilde(
|
|
525
|
+
memoryDirOverridden ? memoryDirOverride : config.memoryDir ?? resolveMemoryDir()
|
|
526
|
+
);
|
|
527
|
+
const orchestrator = new Orchestrator3(
|
|
528
|
+
memoryDirOverridden ? { ...config, memoryDir } : config
|
|
529
|
+
);
|
|
530
|
+
await orchestrator.initialize();
|
|
531
|
+
const storage = await orchestrator.getStorageForNamespace(
|
|
532
|
+
typeof namespaceOverride === "string" && namespaceOverride.length > 0 ? namespaceOverride : void 0
|
|
533
|
+
);
|
|
534
|
+
const report = await runPreferenceDriftScan({
|
|
535
|
+
storage,
|
|
536
|
+
config: orchestrator.config,
|
|
537
|
+
memoryDir,
|
|
538
|
+
// Deliberately NOT wrapped in a swallowing try/catch: the drift scan's
|
|
539
|
+
// §22 contract is that a thrown lookup means `backend_unavailable`, and
|
|
540
|
+
// returning `[]` on failure would misreport a live preference as stale.
|
|
541
|
+
embeddingLookupFactory: (scanStorage) => (content, limit) => orchestrator.semanticDedupLookup(content, limit, scanStorage),
|
|
542
|
+
storageForNamespace: async (namespace) => {
|
|
543
|
+
const resolvedNamespace = namespace?.trim() || void 0;
|
|
544
|
+
return {
|
|
545
|
+
storage: await orchestrator.getStorageForNamespace(resolvedNamespace),
|
|
546
|
+
namespace: resolvedNamespace
|
|
547
|
+
};
|
|
548
|
+
},
|
|
549
|
+
localLlm: orchestrator.localLlm ?? null,
|
|
550
|
+
fallbackLlm: orchestrator.fastGatewayLlm ?? null,
|
|
551
|
+
namespace: typeof namespaceOverride === "string" ? namespaceOverride : void 0,
|
|
552
|
+
apply: hasFlag(args, "--apply")
|
|
553
|
+
});
|
|
554
|
+
if (format === "json") {
|
|
555
|
+
process.stdout.write(JSON.stringify(report, null, 2) + "\n");
|
|
556
|
+
return;
|
|
557
|
+
}
|
|
558
|
+
process.stdout.write(formatPreferenceDriftText(report));
|
|
559
|
+
}
|
|
560
|
+
function formatPreferenceDriftText(report) {
|
|
561
|
+
const lines = [];
|
|
562
|
+
lines.push(`Preference drift \u2014 ${report.mode} run at ${report.generatedAt}`);
|
|
563
|
+
if (report.skippedReason) {
|
|
564
|
+
lines.push(
|
|
565
|
+
report.skippedReason === "drift_disabled" ? " skipped: driftDetection.enabled is false" : " skipped: driftDetection.maxCandidatesPerRun is 0"
|
|
566
|
+
);
|
|
567
|
+
return lines.join("\n") + "\n";
|
|
568
|
+
}
|
|
569
|
+
if (report.namespace) lines.push(` namespace: ${report.namespace}`);
|
|
570
|
+
lines.push(` eligible preferences: ${report.eligible} (classified ${report.scanned})`);
|
|
571
|
+
lines.push(
|
|
572
|
+
` corroborated=${report.counts.corroborated} stale=${report.counts.stale} drifted=${report.counts.drifted} skipped=${report.counts.skipped}`
|
|
573
|
+
);
|
|
574
|
+
lines.push(` applied writes: ${report.appliedCount} (review items opened: ${report.reviewItemsOpened})`);
|
|
575
|
+
for (const finding of report.findings) {
|
|
576
|
+
const skip = finding.skipped ? ` [${finding.skipped}]` : "";
|
|
577
|
+
lines.push(` - ${finding.memoryId}: ${finding.classification}${skip} (${finding.ageDays}d old)`);
|
|
578
|
+
lines.push(` ${finding.reason}`);
|
|
579
|
+
if (finding.reviewPairId) lines.push(` review item: ${finding.reviewPairId}`);
|
|
580
|
+
}
|
|
581
|
+
lines.push(` elapsed: ${report.elapsedMs}ms`);
|
|
582
|
+
return lines.join("\n") + "\n";
|
|
583
|
+
}
|
|
584
|
+
|
|
262
585
|
// src/optional-module-loader.ts
|
|
263
586
|
function isSpecifierNotFoundError(err, specifier) {
|
|
264
587
|
if (!err || typeof err !== "object") {
|
|
@@ -309,13 +632,13 @@ async function loadWecloneExportModule() {
|
|
|
309
632
|
}
|
|
310
633
|
|
|
311
634
|
// src/converge.ts
|
|
312
|
-
import * as
|
|
635
|
+
import * as fs7 from "fs";
|
|
313
636
|
import { createHash as createHash3 } from "crypto";
|
|
314
637
|
import * as path2 from "path";
|
|
315
638
|
import {
|
|
316
639
|
CONVERGE_CONFLICT_POLICIES,
|
|
317
640
|
DEFAULT_CONVERGE_CONFLICT_POLICY,
|
|
318
|
-
parseConfig as
|
|
641
|
+
parseConfig as parseConfig6,
|
|
319
642
|
buildOfflineSyncSnapshotFromBase,
|
|
320
643
|
applyOfflineSyncFileContentChunk,
|
|
321
644
|
isInternalRemnicStatePath as isInternalRemnicStatePath3,
|
|
@@ -341,12 +664,12 @@ import {
|
|
|
341
664
|
|
|
342
665
|
// src/offline-storage-io.ts
|
|
343
666
|
import { createDecipheriv, createHash } from "crypto";
|
|
344
|
-
import
|
|
667
|
+
import fs6 from "fs";
|
|
345
668
|
import { lstat, mkdtemp, readdir, rm } from "fs/promises";
|
|
346
669
|
import path from "path";
|
|
347
670
|
import {
|
|
348
671
|
OFFLINE_SYNC_FILE_CONTENT_TRANSFER_CHUNK_BYTES,
|
|
349
|
-
StorageManager,
|
|
672
|
+
StorageManager as StorageManager2,
|
|
350
673
|
createSupportPassportPrivateFileExclusion
|
|
351
674
|
} from "@remnic/core";
|
|
352
675
|
import { OFFLINE_DECRYPT_STAGING_DIR_PREFIX } from "@remnic/core/offline-sync-exclude-globs";
|
|
@@ -391,7 +714,7 @@ async function filterOfflineSyncBaseFiles(memoryDir, files, excludeFile) {
|
|
|
391
714
|
return files.filter((_file, index) => excluded[index] === false);
|
|
392
715
|
}
|
|
393
716
|
async function createConfiguredOfflineStorage(memoryDir, secureStoreEncryptOnWrite = true) {
|
|
394
|
-
const storage = new
|
|
717
|
+
const storage = new StorageManager2(memoryDir);
|
|
395
718
|
const header = await readHeader(memoryDir);
|
|
396
719
|
let secureStoreKey = null;
|
|
397
720
|
let secureStoreRequired = false;
|
|
@@ -416,7 +739,7 @@ async function createOfflineStorageForPath(memoryDir, filePath, configured, secu
|
|
|
416
739
|
if (storageRoot !== memoryRoot && !storageRoot.startsWith(`${memoryRoot}${path.sep}`)) {
|
|
417
740
|
throw new Error(`lifecycle ledger path is outside the offline memory directory: ${filePath}`);
|
|
418
741
|
}
|
|
419
|
-
const storage = new
|
|
742
|
+
const storage = new StorageManager2(storageRoot);
|
|
420
743
|
if (configured.secureStoreRequired) {
|
|
421
744
|
storage.setSecureStoreRequired(true);
|
|
422
745
|
}
|
|
@@ -503,7 +826,7 @@ async function* readOfflineSyncFileChunks(options) {
|
|
|
503
826
|
});
|
|
504
827
|
}
|
|
505
828
|
async function readFilePrefix(filePath, length) {
|
|
506
|
-
const handle = await
|
|
829
|
+
const handle = await fs6.promises.open(filePath, "r");
|
|
507
830
|
try {
|
|
508
831
|
const out = Buffer.alloc(length);
|
|
509
832
|
const { bytesRead } = await handle.read(out, 0, length, 0);
|
|
@@ -513,7 +836,7 @@ async function readFilePrefix(filePath, length) {
|
|
|
513
836
|
}
|
|
514
837
|
}
|
|
515
838
|
async function* readPlainOfflineFileChunks(filePath, chunkSize) {
|
|
516
|
-
const stream =
|
|
839
|
+
const stream = fs6.createReadStream(filePath, { highWaterMark: chunkSize });
|
|
517
840
|
for await (const chunk of stream) {
|
|
518
841
|
yield Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
519
842
|
}
|
|
@@ -550,9 +873,9 @@ async function* readEncryptedOfflineFileChunks(options) {
|
|
|
550
873
|
});
|
|
551
874
|
decipher.setAuthTag(authTag);
|
|
552
875
|
decipher.setAAD(Buffer.concat([secureStoreEnvelopeHeaderAad(salt), aad]));
|
|
553
|
-
const output =
|
|
876
|
+
const output = fs6.createWriteStream(tempPath, { mode: 384 });
|
|
554
877
|
try {
|
|
555
|
-
const stream =
|
|
878
|
+
const stream = fs6.createReadStream(options.filePath, {
|
|
556
879
|
start: MAGIC_HEADER_SIZE + ENVELOPE_HEADER_SIZE,
|
|
557
880
|
highWaterMark: options.chunkSize
|
|
558
881
|
});
|
|
@@ -1162,7 +1485,7 @@ async function readLocalTombstoneEvidence(rootDir) {
|
|
|
1162
1485
|
for (const relativePath of TOMBSTONE_PATHS) {
|
|
1163
1486
|
let content;
|
|
1164
1487
|
try {
|
|
1165
|
-
content = await
|
|
1488
|
+
content = await fs7.promises.readFile(path2.join(rootDir, relativePath), "utf-8");
|
|
1166
1489
|
} catch (error) {
|
|
1167
1490
|
if (error.code === "ENOENT") continue;
|
|
1168
1491
|
throw error;
|
|
@@ -1177,7 +1500,7 @@ async function discoverCursorNamespaces(memoryDir, peerUrl) {
|
|
|
1177
1500
|
const cursorDir = path2.join(path2.resolve(memoryDir), ".remnic", "state", "converge-cursors");
|
|
1178
1501
|
let entries;
|
|
1179
1502
|
try {
|
|
1180
|
-
entries = await
|
|
1503
|
+
entries = await fs7.promises.readdir(cursorDir, { withFileTypes: true });
|
|
1181
1504
|
} catch (error) {
|
|
1182
1505
|
if (error.code === "ENOENT") return [];
|
|
1183
1506
|
throw error;
|
|
@@ -1253,7 +1576,7 @@ async function computeConvergePlan(options = {}) {
|
|
|
1253
1576
|
let config = options.config;
|
|
1254
1577
|
if (!config) {
|
|
1255
1578
|
try {
|
|
1256
|
-
config =
|
|
1579
|
+
config = parseConfig6({});
|
|
1257
1580
|
} catch {
|
|
1258
1581
|
}
|
|
1259
1582
|
}
|
|
@@ -1504,7 +1827,7 @@ async function executeConvergeApply(options = {}) {
|
|
|
1504
1827
|
let config = options.config;
|
|
1505
1828
|
if (!config) {
|
|
1506
1829
|
try {
|
|
1507
|
-
config =
|
|
1830
|
+
config = parseConfig6({});
|
|
1508
1831
|
} catch {
|
|
1509
1832
|
}
|
|
1510
1833
|
}
|
|
@@ -1667,7 +1990,7 @@ async function executeConvergeApply(options = {}) {
|
|
|
1667
1990
|
if (current.sha256 !== entry.localSha256) {
|
|
1668
1991
|
throw new Error(`local file changed during push: ${localPath}`);
|
|
1669
1992
|
}
|
|
1670
|
-
const stat2 = await
|
|
1993
|
+
const stat2 = await fs7.promises.stat(filePath);
|
|
1671
1994
|
let chunks;
|
|
1672
1995
|
let chunkOffset = 0;
|
|
1673
1996
|
const resetChunks = async () => {
|
|
@@ -1944,7 +2267,7 @@ function formatConvergeApplyReport(result) {
|
|
|
1944
2267
|
lines.push(formatConvergeReport(result.plan));
|
|
1945
2268
|
return lines.join("\n");
|
|
1946
2269
|
}
|
|
1947
|
-
async function cmdConverge(action, rest, json, config =
|
|
2270
|
+
async function cmdConverge(action, rest, json, config = parseConfig6({})) {
|
|
1948
2271
|
if (action === "help" || action === "--help" || action === "-h" || rest.includes("--help") || rest.includes("-h")) {
|
|
1949
2272
|
console.log(`Usage: remnic converge <plan|apply> [options]
|
|
1950
2273
|
|
|
@@ -2150,8 +2473,8 @@ function renderReplayResult(result, targetNamespace, format) {
|
|
|
2150
2473
|
}
|
|
2151
2474
|
|
|
2152
2475
|
// src/quarantine-replay.ts
|
|
2153
|
-
import * as
|
|
2154
|
-
import { EngramAccessService, Orchestrator as
|
|
2476
|
+
import * as fs8 from "fs";
|
|
2477
|
+
import { EngramAccessService, Orchestrator as Orchestrator4, initLogger as initLogger3, parseConfig as parseConfig7, resolveRemnicConfigRecord as resolveRemnicConfigRecord6 } from "@remnic/core";
|
|
2155
2478
|
import { WriteQuarantineStore } from "@remnic/core/write-quarantine.js";
|
|
2156
2479
|
function valueFlag(args, flag) {
|
|
2157
2480
|
const occurrences = args.filter((a) => a === flag).length;
|
|
@@ -2195,13 +2518,13 @@ async function runQuarantineReplay(rest, format, resolveConfigPath2) {
|
|
|
2195
2518
|
process.exitCode = 2;
|
|
2196
2519
|
return;
|
|
2197
2520
|
}
|
|
2198
|
-
|
|
2521
|
+
initLogger3();
|
|
2199
2522
|
let orchestrator;
|
|
2200
2523
|
try {
|
|
2201
2524
|
const configPath = resolveConfigPath2();
|
|
2202
|
-
const raw =
|
|
2203
|
-
const config =
|
|
2204
|
-
orchestrator = new
|
|
2525
|
+
const raw = fs8.existsSync(configPath) ? JSON.parse(fs8.readFileSync(configPath, "utf8")) : {};
|
|
2526
|
+
const config = parseConfig7(resolveRemnicConfigRecord6(raw));
|
|
2527
|
+
orchestrator = new Orchestrator4(config);
|
|
2205
2528
|
await orchestrator.initialize();
|
|
2206
2529
|
await orchestrator.deferredReady;
|
|
2207
2530
|
const service = new EngramAccessService(orchestrator);
|
|
@@ -2231,15 +2554,15 @@ async function runQuarantineReplay(rest, format, resolveConfigPath2) {
|
|
|
2231
2554
|
}
|
|
2232
2555
|
|
|
2233
2556
|
// src/offline-impression-rotation.ts
|
|
2234
|
-
import
|
|
2235
|
-
import { parseConfig as
|
|
2557
|
+
import fs9 from "fs";
|
|
2558
|
+
import { parseConfig as parseConfig8, resolveRemnicConfigRecord as resolveRemnicConfigRecord7, drainPendingImpressionsForOfflineSync } from "@remnic/core";
|
|
2236
2559
|
import { LastRecallStore } from "@remnic/core/recall-state";
|
|
2237
2560
|
function parseConfigQuietly(raw) {
|
|
2238
2561
|
const originalWarn = console.warn;
|
|
2239
2562
|
console.warn = () => {
|
|
2240
2563
|
};
|
|
2241
2564
|
try {
|
|
2242
|
-
return
|
|
2565
|
+
return parseConfig8(resolveRemnicConfigRecord7(raw));
|
|
2243
2566
|
} finally {
|
|
2244
2567
|
console.warn = originalWarn;
|
|
2245
2568
|
}
|
|
@@ -2253,7 +2576,7 @@ var OFFLINE_CONFIG_KEYS = [
|
|
|
2253
2576
|
function pickOfflineConfigRecord(raw) {
|
|
2254
2577
|
let resolved;
|
|
2255
2578
|
try {
|
|
2256
|
-
resolved =
|
|
2579
|
+
resolved = resolveRemnicConfigRecord7(raw);
|
|
2257
2580
|
} catch {
|
|
2258
2581
|
resolved = raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
|
|
2259
2582
|
}
|
|
@@ -2266,7 +2589,7 @@ function pickOfflineConfigRecord(raw) {
|
|
|
2266
2589
|
function resolveOfflineImpressionRotation(configPath) {
|
|
2267
2590
|
let raw;
|
|
2268
2591
|
try {
|
|
2269
|
-
raw =
|
|
2592
|
+
raw = fs9.existsSync(configPath) ? JSON.parse(fs9.readFileSync(configPath, "utf8")) : {};
|
|
2270
2593
|
} catch {
|
|
2271
2594
|
throw new Error(
|
|
2272
2595
|
`cannot read recall-impression rotation from ${configPath}: config file could not be read as JSON`
|
|
@@ -2524,12 +2847,12 @@ function assertBenchModuleFreshForDevelopment() {
|
|
|
2524
2847
|
}
|
|
2525
2848
|
|
|
2526
2849
|
// src/cmd-security.ts
|
|
2527
|
-
import
|
|
2850
|
+
import fs10 from "fs";
|
|
2528
2851
|
import {
|
|
2529
|
-
Orchestrator as
|
|
2530
|
-
parseConfig as
|
|
2531
|
-
initLogger as
|
|
2532
|
-
resolveRemnicConfigRecord as
|
|
2852
|
+
Orchestrator as Orchestrator5,
|
|
2853
|
+
parseConfig as parseConfig9,
|
|
2854
|
+
initLogger as initLogger4,
|
|
2855
|
+
resolveRemnicConfigRecord as resolveRemnicConfigRecord8,
|
|
2533
2856
|
runAuditMemoryCliCommand,
|
|
2534
2857
|
formatAuditMemoryReport
|
|
2535
2858
|
} from "@remnic/core";
|
|
@@ -2542,11 +2865,11 @@ async function cmdSecurity(rest) {
|
|
|
2542
2865
|
process.exitCode = 1;
|
|
2543
2866
|
return;
|
|
2544
2867
|
}
|
|
2545
|
-
|
|
2868
|
+
initLogger4();
|
|
2546
2869
|
const configPath = resolveConfigPath();
|
|
2547
|
-
const raw =
|
|
2548
|
-
const config =
|
|
2549
|
-
const orchestrator = new
|
|
2870
|
+
const raw = fs10.existsSync(configPath) ? JSON.parse(fs10.readFileSync(configPath, "utf8")) : {};
|
|
2871
|
+
const config = parseConfig9(resolveRemnicConfigRecord8(raw));
|
|
2872
|
+
const orchestrator = new Orchestrator5(config);
|
|
2550
2873
|
await orchestrator.initialize();
|
|
2551
2874
|
try {
|
|
2552
2875
|
const sinceFlag = rest.indexOf("--since");
|
|
@@ -2569,7 +2892,7 @@ async function cmdSecurity(rest) {
|
|
|
2569
2892
|
}
|
|
2570
2893
|
|
|
2571
2894
|
// src/daemon-service-candidates.ts
|
|
2572
|
-
import
|
|
2895
|
+
import fs11 from "fs";
|
|
2573
2896
|
import path5 from "path";
|
|
2574
2897
|
var LAUNCHD_LABEL = "ai.remnic.daemon";
|
|
2575
2898
|
var LEGACY_REMNIC_SERVER_LAUNCHD_LABEL = "ai.remnic.server";
|
|
@@ -2591,7 +2914,7 @@ function systemdUnitPaths(homeDir) {
|
|
|
2591
2914
|
function anyFileExists(paths) {
|
|
2592
2915
|
return paths.some((candidate) => {
|
|
2593
2916
|
try {
|
|
2594
|
-
return
|
|
2917
|
+
return fs11.statSync(candidate).isFile();
|
|
2595
2918
|
} catch {
|
|
2596
2919
|
return false;
|
|
2597
2920
|
}
|
|
@@ -2603,7 +2926,7 @@ function commandNames(command) {
|
|
|
2603
2926
|
}
|
|
2604
2927
|
function isRunnableNodeScript(filePath) {
|
|
2605
2928
|
try {
|
|
2606
|
-
const text =
|
|
2929
|
+
const text = fs11.readFileSync(filePath, "utf8").slice(0, 4096);
|
|
2607
2930
|
const firstLine = text.split(/\r?\n/, 1)[0] ?? "";
|
|
2608
2931
|
if (/^#!.*\bnode\b/.test(firstLine)) return true;
|
|
2609
2932
|
if (firstLine.startsWith("#!")) return false;
|
|
@@ -2616,7 +2939,7 @@ function isRunnableNodeScript(filePath) {
|
|
|
2616
2939
|
function resolveShimNodeScript(filePath) {
|
|
2617
2940
|
let text;
|
|
2618
2941
|
try {
|
|
2619
|
-
text =
|
|
2942
|
+
text = fs11.readFileSync(filePath, "utf8").slice(0, 16384);
|
|
2620
2943
|
} catch {
|
|
2621
2944
|
return void 0;
|
|
2622
2945
|
}
|
|
@@ -2628,8 +2951,8 @@ function resolveShimNodeScript(filePath) {
|
|
|
2628
2951
|
const candidate = raw.replaceAll("${basedir}", basedir).replaceAll("$basedir", basedir).replaceAll("\\ ", " ");
|
|
2629
2952
|
const resolved = path5.isAbsolute(candidate) ? candidate : path5.resolve(basedir, candidate);
|
|
2630
2953
|
try {
|
|
2631
|
-
if (
|
|
2632
|
-
return
|
|
2954
|
+
if (fs11.statSync(resolved).isFile() && isRunnableNodeScript(resolved)) {
|
|
2955
|
+
return fs11.realpathSync(resolved);
|
|
2633
2956
|
}
|
|
2634
2957
|
} catch {
|
|
2635
2958
|
}
|
|
@@ -2637,7 +2960,7 @@ function resolveShimNodeScript(filePath) {
|
|
|
2637
2960
|
return void 0;
|
|
2638
2961
|
}
|
|
2639
2962
|
function resolveRunnableNodeScript(filePath) {
|
|
2640
|
-
const realPath =
|
|
2963
|
+
const realPath = fs11.realpathSync(filePath);
|
|
2641
2964
|
if (isRunnableNodeScript(realPath)) return realPath;
|
|
2642
2965
|
return resolveShimNodeScript(realPath);
|
|
2643
2966
|
}
|
|
@@ -2647,9 +2970,9 @@ function findCommandOnPath(command, pathEnv = process.env.PATH ?? "") {
|
|
|
2647
2970
|
for (const name of commandNames(command)) {
|
|
2648
2971
|
const candidate = path5.join(dir, name);
|
|
2649
2972
|
try {
|
|
2650
|
-
const stat2 =
|
|
2973
|
+
const stat2 = fs11.statSync(candidate);
|
|
2651
2974
|
if (!stat2.isFile()) continue;
|
|
2652
|
-
if (process.platform !== "win32")
|
|
2975
|
+
if (process.platform !== "win32") fs11.accessSync(candidate, fs11.constants.X_OK);
|
|
2653
2976
|
const runnable = resolveRunnableNodeScript(candidate);
|
|
2654
2977
|
if (runnable) return runnable;
|
|
2655
2978
|
} catch {
|
|
@@ -3049,24 +3372,6 @@ function collectBenchmarks(argv) {
|
|
|
3049
3372
|
return benchmarks;
|
|
3050
3373
|
}
|
|
3051
3374
|
|
|
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
3375
|
// src/bench-args-research.ts
|
|
3071
3376
|
import path6 from "path";
|
|
3072
3377
|
function readPositiveInteger(args, flag) {
|
|
@@ -4140,7 +4445,7 @@ function finalizeBenchStatus(filePath) {
|
|
|
4140
4445
|
}
|
|
4141
4446
|
|
|
4142
4447
|
// src/bench-fallback.ts
|
|
4143
|
-
import
|
|
4448
|
+
import fs12 from "fs";
|
|
4144
4449
|
import path9 from "path";
|
|
4145
4450
|
var FALLBACK_RESULTS_DIRNAME = "fallback-runs";
|
|
4146
4451
|
function buildBenchRunnerArgs(parsed, benchmarkId, outputDir) {
|
|
@@ -4212,7 +4517,7 @@ function createFallbackBenchOutputDir(resultsDir, benchmarkId, pid, startedAtMs
|
|
|
4212
4517
|
);
|
|
4213
4518
|
}
|
|
4214
4519
|
function resolveFallbackBenchResultPath(outputDir) {
|
|
4215
|
-
const entries =
|
|
4520
|
+
const entries = fs12.readdirSync(outputDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name).sort();
|
|
4216
4521
|
if (entries.length === 0) {
|
|
4217
4522
|
throw new Error(`Fallback benchmark runner did not write a JSON result artifact in ${outputDir}`);
|
|
4218
4523
|
}
|
|
@@ -4220,7 +4525,7 @@ function resolveFallbackBenchResultPath(outputDir) {
|
|
|
4220
4525
|
}
|
|
4221
4526
|
|
|
4222
4527
|
// src/openclaw-upgrade-swap.ts
|
|
4223
|
-
import
|
|
4528
|
+
import fs13 from "fs";
|
|
4224
4529
|
import path10 from "path";
|
|
4225
4530
|
function describeError(error) {
|
|
4226
4531
|
return error instanceof Error ? error.message : String(error);
|
|
@@ -4232,7 +4537,7 @@ function createSiblingTempFilePath(targetPath, label) {
|
|
|
4232
4537
|
function resolveAtomicWriteMode(targetPath, explicitMode) {
|
|
4233
4538
|
if (explicitMode !== void 0) return explicitMode;
|
|
4234
4539
|
try {
|
|
4235
|
-
return
|
|
4540
|
+
return fs13.statSync(targetPath).mode & 4095;
|
|
4236
4541
|
} catch (error) {
|
|
4237
4542
|
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
4238
4543
|
return 384;
|
|
@@ -4242,8 +4547,8 @@ function resolveAtomicWriteMode(targetPath, explicitMode) {
|
|
|
4242
4547
|
}
|
|
4243
4548
|
function resolveAtomicReplacementPath(targetPath) {
|
|
4244
4549
|
try {
|
|
4245
|
-
if (
|
|
4246
|
-
return
|
|
4550
|
+
if (fs13.lstatSync(targetPath).isSymbolicLink()) {
|
|
4551
|
+
return fs13.realpathSync(targetPath);
|
|
4247
4552
|
}
|
|
4248
4553
|
} catch (error) {
|
|
4249
4554
|
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
@@ -4260,7 +4565,7 @@ function createSiblingSwapPath(targetDir, label) {
|
|
|
4260
4565
|
function cleanupDisplacedDirectoryBestEffort(displacedDir, context) {
|
|
4261
4566
|
if (!displacedDir) return void 0;
|
|
4262
4567
|
try {
|
|
4263
|
-
|
|
4568
|
+
fs13.rmSync(displacedDir, { recursive: true, force: true });
|
|
4264
4569
|
return void 0;
|
|
4265
4570
|
} catch (error) {
|
|
4266
4571
|
return `Warning: ${context}, but failed to remove the displaced plugin copy at ${displacedDir}: ${describeError(error)}`;
|
|
@@ -4268,43 +4573,43 @@ function cleanupDisplacedDirectoryBestEffort(displacedDir, context) {
|
|
|
4268
4573
|
}
|
|
4269
4574
|
function atomicWriteFileSync(targetPath, data, options = {}) {
|
|
4270
4575
|
const resolvedTargetPath = resolveAtomicReplacementPath(targetPath);
|
|
4271
|
-
|
|
4576
|
+
fs13.mkdirSync(path10.dirname(resolvedTargetPath), { recursive: true });
|
|
4272
4577
|
const tempPath = createSiblingTempFilePath(resolvedTargetPath, "write");
|
|
4273
4578
|
const mode = resolveAtomicWriteMode(resolvedTargetPath, options.mode);
|
|
4274
4579
|
try {
|
|
4275
4580
|
if (options.hooks?.writeTempFileSync) {
|
|
4276
4581
|
options.hooks.writeTempFileSync(tempPath);
|
|
4277
4582
|
} else {
|
|
4278
|
-
|
|
4583
|
+
fs13.writeFileSync(tempPath, data, { mode });
|
|
4279
4584
|
}
|
|
4280
|
-
|
|
4281
|
-
const renameTempFileSync = options.hooks?.renameTempFileSync ??
|
|
4585
|
+
fs13.chmodSync(tempPath, mode);
|
|
4586
|
+
const renameTempFileSync = options.hooks?.renameTempFileSync ?? fs13.renameSync;
|
|
4282
4587
|
renameTempFileSync(tempPath, resolvedTargetPath);
|
|
4283
4588
|
} catch (error) {
|
|
4284
|
-
|
|
4589
|
+
fs13.rmSync(tempPath, { force: true });
|
|
4285
4590
|
throw error;
|
|
4286
4591
|
}
|
|
4287
4592
|
}
|
|
4288
4593
|
function atomicCopyFileSync(sourcePath, targetPath, options = {}) {
|
|
4289
|
-
if (!
|
|
4594
|
+
if (!fs13.existsSync(sourcePath)) return;
|
|
4290
4595
|
const resolvedTargetPath = resolveAtomicReplacementPath(targetPath);
|
|
4291
|
-
|
|
4596
|
+
fs13.mkdirSync(path10.dirname(resolvedTargetPath), { recursive: true });
|
|
4292
4597
|
const tempPath = createSiblingTempFilePath(resolvedTargetPath, "copy");
|
|
4293
|
-
const mode =
|
|
4598
|
+
const mode = fs13.statSync(sourcePath).mode & 4095;
|
|
4294
4599
|
try {
|
|
4295
|
-
const copyTempFileSync = options.hooks?.copyTempFileSync ??
|
|
4600
|
+
const copyTempFileSync = options.hooks?.copyTempFileSync ?? fs13.copyFileSync;
|
|
4296
4601
|
copyTempFileSync(sourcePath, tempPath);
|
|
4297
|
-
|
|
4298
|
-
const renameTempFileSync = options.hooks?.renameTempFileSync ??
|
|
4602
|
+
fs13.chmodSync(tempPath, mode);
|
|
4603
|
+
const renameTempFileSync = options.hooks?.renameTempFileSync ?? fs13.renameSync;
|
|
4299
4604
|
renameTempFileSync(tempPath, resolvedTargetPath);
|
|
4300
4605
|
} catch (error) {
|
|
4301
|
-
|
|
4606
|
+
fs13.rmSync(tempPath, { force: true });
|
|
4302
4607
|
throw error;
|
|
4303
4608
|
}
|
|
4304
4609
|
}
|
|
4305
4610
|
function cleanupRollbackDirectory(rollbackDir) {
|
|
4306
4611
|
if (!rollbackDir) return;
|
|
4307
|
-
|
|
4612
|
+
fs13.rmSync(rollbackDir, { recursive: true, force: true });
|
|
4308
4613
|
}
|
|
4309
4614
|
function cleanupRollbackDirectoryBestEffort(rollbackDir) {
|
|
4310
4615
|
if (!rollbackDir) return void 0;
|
|
@@ -4316,20 +4621,20 @@ function cleanupRollbackDirectoryBestEffort(rollbackDir) {
|
|
|
4316
4621
|
}
|
|
4317
4622
|
}
|
|
4318
4623
|
function restoreDirectoryFromRollback(targetDir, rollbackDir) {
|
|
4319
|
-
if (!
|
|
4624
|
+
if (!fs13.existsSync(rollbackDir)) {
|
|
4320
4625
|
throw new Error(`Rollback directory is missing: ${rollbackDir}`);
|
|
4321
4626
|
}
|
|
4322
|
-
|
|
4323
|
-
const displacedDir =
|
|
4627
|
+
fs13.mkdirSync(path10.dirname(targetDir), { recursive: true });
|
|
4628
|
+
const displacedDir = fs13.existsSync(targetDir) ? createSiblingSwapPath(targetDir, "rollback-restore") : void 0;
|
|
4324
4629
|
if (displacedDir) {
|
|
4325
|
-
|
|
4630
|
+
fs13.renameSync(targetDir, displacedDir);
|
|
4326
4631
|
}
|
|
4327
4632
|
try {
|
|
4328
|
-
|
|
4633
|
+
fs13.renameSync(rollbackDir, targetDir);
|
|
4329
4634
|
} catch (restoreError) {
|
|
4330
|
-
if (displacedDir &&
|
|
4635
|
+
if (displacedDir && fs13.existsSync(displacedDir)) {
|
|
4331
4636
|
try {
|
|
4332
|
-
|
|
4637
|
+
fs13.renameSync(displacedDir, targetDir);
|
|
4333
4638
|
} catch (revertError) {
|
|
4334
4639
|
throw new AggregateError(
|
|
4335
4640
|
[restoreError, revertError],
|
|
@@ -4345,23 +4650,23 @@ function restoreDirectoryFromRollback(targetDir, rollbackDir) {
|
|
|
4345
4650
|
return cleanupDisplacedDirectoryBestEffort(displacedDir, `restored the previous plugin copy into ${targetDir}`);
|
|
4346
4651
|
}
|
|
4347
4652
|
function restoreDirectoryFromBackup(targetDir, backupDir) {
|
|
4348
|
-
if (!
|
|
4653
|
+
if (!fs13.existsSync(backupDir)) {
|
|
4349
4654
|
throw new Error(`Plugin backup directory is missing: ${backupDir}`);
|
|
4350
4655
|
}
|
|
4351
|
-
|
|
4656
|
+
fs13.mkdirSync(path10.dirname(targetDir), { recursive: true });
|
|
4352
4657
|
const stagedDir = createSiblingSwapPath(targetDir, "backup-restore");
|
|
4353
|
-
const displacedDir =
|
|
4354
|
-
|
|
4658
|
+
const displacedDir = fs13.existsSync(targetDir) ? createSiblingSwapPath(targetDir, "pre-backup-restore") : void 0;
|
|
4659
|
+
fs13.cpSync(backupDir, stagedDir, { recursive: true });
|
|
4355
4660
|
if (displacedDir) {
|
|
4356
|
-
|
|
4661
|
+
fs13.renameSync(targetDir, displacedDir);
|
|
4357
4662
|
}
|
|
4358
4663
|
try {
|
|
4359
|
-
|
|
4664
|
+
fs13.renameSync(stagedDir, targetDir);
|
|
4360
4665
|
} catch (restoreError) {
|
|
4361
|
-
|
|
4362
|
-
if (displacedDir &&
|
|
4666
|
+
fs13.rmSync(targetDir, { recursive: true, force: true });
|
|
4667
|
+
if (displacedDir && fs13.existsSync(displacedDir)) {
|
|
4363
4668
|
try {
|
|
4364
|
-
|
|
4669
|
+
fs13.renameSync(displacedDir, targetDir);
|
|
4365
4670
|
} catch (revertError) {
|
|
4366
4671
|
throw new AggregateError(
|
|
4367
4672
|
[restoreError, revertError],
|
|
@@ -4369,7 +4674,7 @@ function restoreDirectoryFromBackup(targetDir, backupDir) {
|
|
|
4369
4674
|
);
|
|
4370
4675
|
}
|
|
4371
4676
|
}
|
|
4372
|
-
|
|
4677
|
+
fs13.rmSync(stagedDir, { recursive: true, force: true });
|
|
4373
4678
|
throw new Error(
|
|
4374
4679
|
`Failed to restore the plugin backup into ${targetDir}. The durable backup remains preserved at ${backupDir}.`,
|
|
4375
4680
|
{ cause: restoreError }
|
|
@@ -4394,7 +4699,7 @@ function rollbackOpenclawUpgrade({
|
|
|
4394
4699
|
let configRemovalAttempted = false;
|
|
4395
4700
|
let pluginRestored = false;
|
|
4396
4701
|
try {
|
|
4397
|
-
if (rollbackDir &&
|
|
4702
|
+
if (rollbackDir && fs13.existsSync(rollbackDir)) {
|
|
4398
4703
|
const cleanupWarning = restoreDirectoryFromRollback(pluginDir, rollbackDir);
|
|
4399
4704
|
notes.push(`Restored previous plugin from rollback copy at ${rollbackDir}`);
|
|
4400
4705
|
if (cleanupWarning) notes.push(cleanupWarning);
|
|
@@ -4404,7 +4709,7 @@ function rollbackOpenclawUpgrade({
|
|
|
4404
4709
|
rollbackRestoreError = error instanceof Error ? error.message : String(error);
|
|
4405
4710
|
}
|
|
4406
4711
|
try {
|
|
4407
|
-
if (!pluginRestored && pluginBackupDir &&
|
|
4712
|
+
if (!pluginRestored && pluginBackupDir && fs13.existsSync(pluginBackupDir)) {
|
|
4408
4713
|
const cleanupWarning = restoreDirectoryFromBackup(pluginDir, pluginBackupDir);
|
|
4409
4714
|
if (rollbackRestoreError) {
|
|
4410
4715
|
notes.push(`Rollback copy restore failed; restored previous plugin from durable backup at ${pluginBackupDir}`);
|
|
@@ -4429,12 +4734,12 @@ function rollbackOpenclawUpgrade({
|
|
|
4429
4734
|
notes.push("No previous plugin copy was available for automatic restore");
|
|
4430
4735
|
}
|
|
4431
4736
|
try {
|
|
4432
|
-
if (configBackupPath &&
|
|
4737
|
+
if (configBackupPath && fs13.existsSync(configBackupPath)) {
|
|
4433
4738
|
restoreFileFromBackup(configPath, configBackupPath);
|
|
4434
4739
|
notes.push(`Restored OpenClaw config from backup at ${configBackupPath}`);
|
|
4435
|
-
} else if (removeConfigIfUnbacked &&
|
|
4740
|
+
} else if (removeConfigIfUnbacked && fs13.existsSync(configPath)) {
|
|
4436
4741
|
configRemovalAttempted = true;
|
|
4437
|
-
|
|
4742
|
+
fs13.rmSync(configPath, { force: true });
|
|
4438
4743
|
notes.push("Removed OpenClaw config created during the failed upgrade");
|
|
4439
4744
|
}
|
|
4440
4745
|
} catch (error) {
|
|
@@ -4487,7 +4792,7 @@ Run this manually when you're ready:
|
|
|
4487
4792
|
|
|
4488
4793
|
// src/openclaw-managed-upgrade-loader.ts
|
|
4489
4794
|
import { execFileSync } from "child_process";
|
|
4490
|
-
import
|
|
4795
|
+
import fs14 from "fs";
|
|
4491
4796
|
import os from "os";
|
|
4492
4797
|
import path11 from "path";
|
|
4493
4798
|
import { fileURLToPath as fileURLToPath3, pathToFileURL as pathToFileURL2 } from "url";
|
|
@@ -4563,7 +4868,7 @@ function buildOpenclawManagedUpgradePackageSpec(version = "latest") {
|
|
|
4563
4868
|
function readCliAdapterRange() {
|
|
4564
4869
|
const moduleDir = path11.dirname(fileURLToPath3(import.meta.url));
|
|
4565
4870
|
const manifestPath = path11.resolve(moduleDir, "../package.json");
|
|
4566
|
-
const manifest = JSON.parse(
|
|
4871
|
+
const manifest = JSON.parse(fs14.readFileSync(manifestPath, "utf8"));
|
|
4567
4872
|
if (manifest.name !== "@remnic/cli") {
|
|
4568
4873
|
throw new Error(`Invalid @remnic/cli package manifest at ${manifestPath}.`);
|
|
4569
4874
|
}
|
|
@@ -4607,7 +4912,7 @@ async function loadOpenclawManagedUpgradeModule(packageSpec, hooks = {}) {
|
|
|
4607
4912
|
const adapterMissing = isSpecifierNotFoundError(error, OPENCLAW_PLUGIN_PACKAGE) || isSpecifierNotFoundError(error, MANAGED_UPGRADE_SPECIFIER) || isManagedUpgradeSubpathMissing(error);
|
|
4608
4913
|
if (!adapterMissing) throw error;
|
|
4609
4914
|
}
|
|
4610
|
-
const temporaryRoot =
|
|
4915
|
+
const temporaryRoot = fs14.mkdtempSync(path11.join(os.tmpdir(), "remnic-openclaw-upgrade-"));
|
|
4611
4916
|
try {
|
|
4612
4917
|
const toolingPackageSpec = `${OPENCLAW_PLUGIN_PACKAGE}@${readCliAdapterRange()}`;
|
|
4613
4918
|
const installArgs = [
|
|
@@ -4622,12 +4927,12 @@ async function loadOpenclawManagedUpgradeModule(packageSpec, hooks = {}) {
|
|
|
4622
4927
|
];
|
|
4623
4928
|
(hooks.runNpmInstall ?? runNpmInstall)(installArgs);
|
|
4624
4929
|
const resolverPath = path11.join(temporaryRoot, "load-managed-upgrade.mjs");
|
|
4625
|
-
|
|
4930
|
+
fs14.writeFileSync(resolverPath, `export * from ${JSON.stringify(MANAGED_UPGRADE_SPECIFIER)};
|
|
4626
4931
|
`, "utf8");
|
|
4627
4932
|
return await importModule(pathToFileURL2(resolverPath).href);
|
|
4628
4933
|
} finally {
|
|
4629
4934
|
try {
|
|
4630
|
-
|
|
4935
|
+
fs14.rmSync(temporaryRoot, { recursive: true, force: true });
|
|
4631
4936
|
} catch (error) {
|
|
4632
4937
|
const detail = error instanceof Error ? error.message : String(error);
|
|
4633
4938
|
console.warn(`Could not remove temporary managed upgrade project at ${temporaryRoot}: ${detail}`);
|
|
@@ -4636,13 +4941,13 @@ async function loadOpenclawManagedUpgradeModule(packageSpec, hooks = {}) {
|
|
|
4636
4941
|
}
|
|
4637
4942
|
|
|
4638
4943
|
// src/remote-daemon.ts
|
|
4639
|
-
import
|
|
4944
|
+
import fs15 from "fs";
|
|
4640
4945
|
function readCompatEnv(primary, legacy) {
|
|
4641
4946
|
return process.env[primary] ?? process.env[legacy];
|
|
4642
4947
|
}
|
|
4643
4948
|
function readRemnicConfigRecord(configPath) {
|
|
4644
4949
|
try {
|
|
4645
|
-
const parsed = JSON.parse(
|
|
4950
|
+
const parsed = JSON.parse(fs15.readFileSync(configPath, "utf8"));
|
|
4646
4951
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
4647
4952
|
return parsed;
|
|
4648
4953
|
}
|
|
@@ -4871,7 +5176,7 @@ async function remoteRecallXray(daemon, request) {
|
|
|
4871
5176
|
}
|
|
4872
5177
|
|
|
4873
5178
|
// src/daemon-service.ts
|
|
4874
|
-
import
|
|
5179
|
+
import fs16 from "fs";
|
|
4875
5180
|
import path12 from "path";
|
|
4876
5181
|
import * as childProcess from "child_process";
|
|
4877
5182
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
@@ -4883,7 +5188,7 @@ function launchdUnloadPlist(plistPath, processApi = childProcess) {
|
|
|
4883
5188
|
processApi.execFileSync("launchctl", ["unload", plistPath], { stdio: "pipe" });
|
|
4884
5189
|
}
|
|
4885
5190
|
function resolveServerBinDetails(options = {}) {
|
|
4886
|
-
const existsSync4 = options.existsSync ??
|
|
5191
|
+
const existsSync4 = options.existsSync ?? fs16.existsSync;
|
|
4887
5192
|
const findCommandOnPath2 = options.findCommandOnPath ?? findCommandOnPath;
|
|
4888
5193
|
const moduleDir = options.moduleDir ?? thisModuleDir;
|
|
4889
5194
|
const packageResolve = options.packageResolve ?? resolveImportSpecifier;
|
|
@@ -4942,8 +5247,8 @@ function resolveServerBin(options = {}) {
|
|
|
4942
5247
|
return resolveServerBinDetails(options).path;
|
|
4943
5248
|
}
|
|
4944
5249
|
function readVerifiedDaemonPid(options) {
|
|
4945
|
-
const readFileSync4 = options.readFileSync ??
|
|
4946
|
-
const unlinkSync = options.unlinkSync ??
|
|
5250
|
+
const readFileSync4 = options.readFileSync ?? fs16.readFileSync;
|
|
5251
|
+
const unlinkSync = options.unlinkSync ?? fs16.unlinkSync;
|
|
4947
5252
|
const processKill = options.processKill ?? process.kill;
|
|
4948
5253
|
const platform = options.platform ?? process.platform;
|
|
4949
5254
|
const execFileSync4 = options.execFileSync ?? ((command, args, execOptions) => childProcess.execFileSync(command, args, execOptions));
|
|
@@ -5043,8 +5348,8 @@ function removePidFileBestEffort(file, unlinkSync) {
|
|
|
5043
5348
|
}
|
|
5044
5349
|
}
|
|
5045
5350
|
function inspectLaunchdPlist(plistPath, options = {}) {
|
|
5046
|
-
const existsSync4 = options.existsSync ??
|
|
5047
|
-
const readFileSync4 = options.readFileSync ??
|
|
5351
|
+
const existsSync4 = options.existsSync ?? fs16.existsSync;
|
|
5352
|
+
const readFileSync4 = options.readFileSync ?? fs16.readFileSync;
|
|
5048
5353
|
if (!existsSync4(plistPath)) {
|
|
5049
5354
|
return {
|
|
5050
5355
|
installed: false,
|
|
@@ -5168,62 +5473,6 @@ function unescapeXml(input) {
|
|
|
5168
5473
|
return input.replaceAll(""", '"').replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">").replaceAll("&", "&");
|
|
5169
5474
|
}
|
|
5170
5475
|
|
|
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
5476
|
// src/parse-connector-config.ts
|
|
5228
5477
|
function parseConfigAssignment(raw, flag) {
|
|
5229
5478
|
const eqIdx = raw.indexOf("=");
|
|
@@ -5278,7 +5527,7 @@ function stripConfigArgv(args) {
|
|
|
5278
5527
|
}
|
|
5279
5528
|
|
|
5280
5529
|
// src/import-dispatch.ts
|
|
5281
|
-
import
|
|
5530
|
+
import fs17 from "fs";
|
|
5282
5531
|
import {
|
|
5283
5532
|
runImporter,
|
|
5284
5533
|
validateImportBatchSize,
|
|
@@ -5792,7 +6041,7 @@ async function cmdImport(rest, targetFactory, disposeTarget, ioOverrides = {}) {
|
|
|
5792
6041
|
let materializedTarget;
|
|
5793
6042
|
let materializePromise;
|
|
5794
6043
|
const io = {
|
|
5795
|
-
readFile: ioOverrides.readFile ?? (async (p) =>
|
|
6044
|
+
readFile: ioOverrides.readFile ?? (async (p) => fs17.promises.readFile(p, "utf-8")),
|
|
5796
6045
|
loadAdapter: ioOverrides.loadAdapter ?? (async (name) => (await loadImporterModule(name)).adapter),
|
|
5797
6046
|
runImporter: ioOverrides.runImporter ?? runImporter,
|
|
5798
6047
|
getWriteTarget: async () => {
|
|
@@ -5905,7 +6154,7 @@ async function cmdCapture(rest, io) {
|
|
|
5905
6154
|
}
|
|
5906
6155
|
|
|
5907
6156
|
// src/import-lossless-claw-cmd.ts
|
|
5908
|
-
import
|
|
6157
|
+
import fs18 from "fs";
|
|
5909
6158
|
import path14 from "path";
|
|
5910
6159
|
import {
|
|
5911
6160
|
applyLcmSchema,
|
|
@@ -6017,15 +6266,15 @@ async function loadImportLosslessClawModule() {
|
|
|
6017
6266
|
|
|
6018
6267
|
// src/import-lossless-claw-cmd.ts
|
|
6019
6268
|
function assertDirectoryOrAbsent(p, label) {
|
|
6020
|
-
if (
|
|
6269
|
+
if (fs18.existsSync(p) && !fs18.statSync(p).isDirectory()) {
|
|
6021
6270
|
throw new Error(`${label} is not a directory: ${p}`);
|
|
6022
6271
|
}
|
|
6023
6272
|
}
|
|
6024
6273
|
function assertFile(p, label) {
|
|
6025
|
-
if (!
|
|
6274
|
+
if (!fs18.existsSync(p)) {
|
|
6026
6275
|
throw new Error(`${label} does not exist: ${p}`);
|
|
6027
6276
|
}
|
|
6028
|
-
if (!
|
|
6277
|
+
if (!fs18.statSync(p).isFile()) {
|
|
6029
6278
|
throw new Error(`${label} is not a file: ${p}`);
|
|
6030
6279
|
}
|
|
6031
6280
|
}
|
|
@@ -6057,7 +6306,7 @@ async function cmdImportLosslessClaw(argv, io, deps = {}) {
|
|
|
6057
6306
|
try {
|
|
6058
6307
|
if (parsed.dryRun) {
|
|
6059
6308
|
const lcmPath = path14.join(memoryDir, "state", "lcm.sqlite");
|
|
6060
|
-
if (
|
|
6309
|
+
if (fs18.existsSync(lcmPath)) {
|
|
6061
6310
|
destDb = mod.openExistingLcmDatabaseReadOnly(lcmPath);
|
|
6062
6311
|
} else {
|
|
6063
6312
|
destDb = mod.openInMemoryDestinationDatabase();
|
|
@@ -7409,7 +7658,7 @@ async function resolveAllBenchmarks() {
|
|
|
7409
7658
|
if (packageBenchmarks) {
|
|
7410
7659
|
return packageBenchmarks.filter((entry) => entry.runnerAvailable).map((entry) => entry.id);
|
|
7411
7660
|
}
|
|
7412
|
-
if (!
|
|
7661
|
+
if (!fs19.existsSync(EVAL_RUNNER_PATH)) {
|
|
7413
7662
|
return [];
|
|
7414
7663
|
}
|
|
7415
7664
|
return BENCHMARK_CATALOG.filter((entry) => entry.category !== "ingestion").map((entry) => entry.id);
|
|
@@ -7457,7 +7706,7 @@ async function runBenchViaFallback(parsed, benchmarkId, runtimeProfile) {
|
|
|
7457
7706
|
`Fallback benchmark runner does not support provider-backed, gateway, or thinking/timeout flags (${unsupportedOptions.join(", ")}). Build/install @remnic/bench to use those options.`
|
|
7458
7707
|
);
|
|
7459
7708
|
}
|
|
7460
|
-
if (!
|
|
7709
|
+
if (!fs19.existsSync(EVAL_RUNNER_PATH)) {
|
|
7461
7710
|
console.error(
|
|
7462
7711
|
"Benchmark runner not found. Expected eval runner at evals/run.ts or a phase-1 @remnic/bench runtime export."
|
|
7463
7712
|
);
|
|
@@ -7467,7 +7716,7 @@ async function runBenchViaFallback(parsed, benchmarkId, runtimeProfile) {
|
|
|
7467
7716
|
path18.join(CLI_REPO_ROOT, "node_modules", ".bin", "tsx"),
|
|
7468
7717
|
path18.join(CLI_REPO_ROOT, "packages", "remnic-cli", "node_modules", ".bin", "tsx")
|
|
7469
7718
|
];
|
|
7470
|
-
const tsxCmd = tsxCandidates.find((candidate) =>
|
|
7719
|
+
const tsxCmd = tsxCandidates.find((candidate) => fs19.existsSync(candidate)) ?? "tsx";
|
|
7471
7720
|
const fallbackOutputDir = createFallbackBenchOutputDir(
|
|
7472
7721
|
parsed.resultsDir ?? resolveBenchOutputDir(),
|
|
7473
7722
|
benchmarkId,
|
|
@@ -7612,9 +7861,9 @@ var PERSONAMEM_COMPLETION_MARKER = path18.join(
|
|
|
7612
7861
|
);
|
|
7613
7862
|
function resolveRealpathWithinDataset(datasetPath, relativePath) {
|
|
7614
7863
|
try {
|
|
7615
|
-
const datasetRoot =
|
|
7864
|
+
const datasetRoot = fs19.realpathSync(datasetPath);
|
|
7616
7865
|
const candidatePath = path18.resolve(datasetRoot, relativePath);
|
|
7617
|
-
const candidateRealPath =
|
|
7866
|
+
const candidateRealPath = fs19.realpathSync(candidatePath);
|
|
7618
7867
|
const relativeToRoot = path18.relative(datasetRoot, candidateRealPath);
|
|
7619
7868
|
if (relativeToRoot.startsWith("..") || path18.isAbsolute(relativeToRoot)) {
|
|
7620
7869
|
return null;
|
|
@@ -7673,14 +7922,14 @@ function parseCsvRows(raw) {
|
|
|
7673
7922
|
function isPersonaMemDatasetComplete(datasetPath) {
|
|
7674
7923
|
try {
|
|
7675
7924
|
const completionMarkerPath = path18.join(datasetPath, PERSONAMEM_COMPLETION_MARKER);
|
|
7676
|
-
if (
|
|
7925
|
+
if (fs19.statSync(completionMarkerPath).isFile()) {
|
|
7677
7926
|
return true;
|
|
7678
7927
|
}
|
|
7679
7928
|
} catch {
|
|
7680
7929
|
}
|
|
7681
7930
|
const datasetFile = PERSONAMEM_DATASET_FILE_CANDIDATES.find((candidate) => {
|
|
7682
7931
|
try {
|
|
7683
|
-
return
|
|
7932
|
+
return fs19.statSync(path18.join(datasetPath, candidate)).isFile();
|
|
7684
7933
|
} catch {
|
|
7685
7934
|
return false;
|
|
7686
7935
|
}
|
|
@@ -7689,7 +7938,7 @@ function isPersonaMemDatasetComplete(datasetPath) {
|
|
|
7689
7938
|
return false;
|
|
7690
7939
|
}
|
|
7691
7940
|
try {
|
|
7692
|
-
const rows = parseCsvRows(
|
|
7941
|
+
const rows = parseCsvRows(fs19.readFileSync(path18.join(datasetPath, datasetFile), "utf8"));
|
|
7693
7942
|
if (rows.length < 2) {
|
|
7694
7943
|
return false;
|
|
7695
7944
|
}
|
|
@@ -7704,7 +7953,7 @@ function isPersonaMemDatasetComplete(datasetPath) {
|
|
|
7704
7953
|
}
|
|
7705
7954
|
return historyPaths.every((relativePath) => {
|
|
7706
7955
|
const resolvedPath = resolveRealpathWithinDataset(datasetPath, relativePath);
|
|
7707
|
-
return resolvedPath !== null &&
|
|
7956
|
+
return resolvedPath !== null && fs19.statSync(resolvedPath).isFile();
|
|
7708
7957
|
});
|
|
7709
7958
|
} catch {
|
|
7710
7959
|
return false;
|
|
@@ -7712,7 +7961,7 @@ function isPersonaMemDatasetComplete(datasetPath) {
|
|
|
7712
7961
|
}
|
|
7713
7962
|
function hasDatasetFile(datasetPath, relativePath) {
|
|
7714
7963
|
try {
|
|
7715
|
-
return
|
|
7964
|
+
return fs19.statSync(path18.join(datasetPath, relativePath)).isFile();
|
|
7716
7965
|
} catch {
|
|
7717
7966
|
return false;
|
|
7718
7967
|
}
|
|
@@ -7732,10 +7981,10 @@ function memoryAgentBenchDatasetHasRecSysSamples(datasetPath) {
|
|
|
7732
7981
|
return candidateFilenames.some((filename) => {
|
|
7733
7982
|
const filePath = path18.join(datasetPath, filename);
|
|
7734
7983
|
try {
|
|
7735
|
-
if (!
|
|
7984
|
+
if (!fs19.statSync(filePath).isFile()) {
|
|
7736
7985
|
return false;
|
|
7737
7986
|
}
|
|
7738
|
-
const raw =
|
|
7987
|
+
const raw = fs19.readFileSync(filePath, "utf8");
|
|
7739
7988
|
return /"source"\s*:\s*"recsys[_-]/i.test(raw);
|
|
7740
7989
|
} catch {
|
|
7741
7990
|
return false;
|
|
@@ -7751,7 +8000,7 @@ function isMemoryAgentBenchDatasetComplete(datasetPath) {
|
|
|
7751
8000
|
function isDatasetDownloaded(datasetPath, benchmarkId) {
|
|
7752
8001
|
let stats;
|
|
7753
8002
|
try {
|
|
7754
|
-
stats =
|
|
8003
|
+
stats = fs19.statSync(datasetPath);
|
|
7755
8004
|
} catch {
|
|
7756
8005
|
return false;
|
|
7757
8006
|
}
|
|
@@ -7761,7 +8010,7 @@ function isDatasetDownloaded(datasetPath, benchmarkId) {
|
|
|
7761
8010
|
const marker = DOWNLOADED_DATASET_MARKERS[benchmarkId];
|
|
7762
8011
|
if (!marker) {
|
|
7763
8012
|
try {
|
|
7764
|
-
return
|
|
8013
|
+
return fs19.readdirSync(datasetPath).length > 0;
|
|
7765
8014
|
} catch {
|
|
7766
8015
|
return false;
|
|
7767
8016
|
}
|
|
@@ -7769,7 +8018,7 @@ function isDatasetDownloaded(datasetPath, benchmarkId) {
|
|
|
7769
8018
|
if (marker.allOf) {
|
|
7770
8019
|
const hasAllRequiredFiles = marker.allOf.every((name) => {
|
|
7771
8020
|
try {
|
|
7772
|
-
return
|
|
8021
|
+
return fs19.statSync(path18.join(datasetPath, name)).isFile();
|
|
7773
8022
|
} catch {
|
|
7774
8023
|
return false;
|
|
7775
8024
|
}
|
|
@@ -7781,7 +8030,7 @@ function isDatasetDownloaded(datasetPath, benchmarkId) {
|
|
|
7781
8030
|
if (marker.anyOf) {
|
|
7782
8031
|
const hasMarkerFile = marker.anyOf.some((name) => {
|
|
7783
8032
|
try {
|
|
7784
|
-
return
|
|
8033
|
+
return fs19.statSync(path18.join(datasetPath, name)).isFile();
|
|
7785
8034
|
} catch {
|
|
7786
8035
|
return false;
|
|
7787
8036
|
}
|
|
@@ -7799,7 +8048,7 @@ function isDatasetDownloaded(datasetPath, benchmarkId) {
|
|
|
7799
8048
|
}
|
|
7800
8049
|
if (marker.ext) {
|
|
7801
8050
|
try {
|
|
7802
|
-
return
|
|
8051
|
+
return fs19.readdirSync(datasetPath).some(
|
|
7803
8052
|
(name) => name.endsWith(marker.ext) && !marker.exclude?.includes(name)
|
|
7804
8053
|
);
|
|
7805
8054
|
} catch {
|
|
@@ -7811,7 +8060,7 @@ function isDatasetDownloaded(datasetPath, benchmarkId) {
|
|
|
7811
8060
|
async function launchBenchUi(resultsDir) {
|
|
7812
8061
|
const benchUiDir = path18.join(CLI_REPO_ROOT, "packages", "bench-ui");
|
|
7813
8062
|
const pnpmCmd = process.platform === "win32" ? "pnpm.cmd" : "pnpm";
|
|
7814
|
-
if (!
|
|
8063
|
+
if (!fs19.existsSync(path18.join(benchUiDir, "package.json"))) {
|
|
7815
8064
|
console.error("ERROR: @remnic/bench-ui is not available in this checkout.");
|
|
7816
8065
|
process.exit(1);
|
|
7817
8066
|
}
|
|
@@ -7849,13 +8098,13 @@ function listDownloadableBenchmarks() {
|
|
|
7849
8098
|
}
|
|
7850
8099
|
function resolveDatasetDownloadScriptPath() {
|
|
7851
8100
|
const bundled = path18.join(CLI_MODULE_DIR, "assets", "download-datasets.sh");
|
|
7852
|
-
if (
|
|
8101
|
+
if (fs19.existsSync(bundled)) {
|
|
7853
8102
|
return bundled;
|
|
7854
8103
|
}
|
|
7855
8104
|
return path18.join(CLI_REPO_ROOT, "evals", "scripts", "download-datasets.sh");
|
|
7856
8105
|
}
|
|
7857
8106
|
function isRepoCheckout() {
|
|
7858
|
-
return
|
|
8107
|
+
return fs19.existsSync(path18.join(CLI_REPO_ROOT, "pnpm-workspace.yaml")) && fs19.existsSync(path18.join(CLI_REPO_ROOT, "evals", "scripts", "download-datasets.sh"));
|
|
7859
8108
|
}
|
|
7860
8109
|
function runDatasetDownloadScript(scriptPath, benchmarkId, datasetRoot, jsonMode) {
|
|
7861
8110
|
const stdio = jsonMode ? ["inherit", process.stderr, "inherit"] : "inherit";
|
|
@@ -8168,8 +8417,8 @@ async function exportBenchPackageResult(parsed) {
|
|
|
8168
8417
|
...reportCardProvenance ? { reportCardProvenance } : {}
|
|
8169
8418
|
});
|
|
8170
8419
|
if (parsed.output) {
|
|
8171
|
-
|
|
8172
|
-
|
|
8420
|
+
fs19.mkdirSync(path18.dirname(parsed.output), { recursive: true });
|
|
8421
|
+
fs19.writeFileSync(parsed.output, rendered);
|
|
8173
8422
|
console.log(`Exported ${summary.id} as ${parsed.format} to ${parsed.output}`);
|
|
8174
8423
|
return;
|
|
8175
8424
|
}
|
|
@@ -8214,7 +8463,7 @@ async function manageBenchDatasets(parsed) {
|
|
|
8214
8463
|
process.exit(1);
|
|
8215
8464
|
}
|
|
8216
8465
|
const scriptPath = resolveDatasetDownloadScriptPath();
|
|
8217
|
-
if (!
|
|
8466
|
+
if (!fs19.existsSync(scriptPath)) {
|
|
8218
8467
|
console.error(`ERROR: dataset download script not found: ${scriptPath}`);
|
|
8219
8468
|
process.exit(1);
|
|
8220
8469
|
}
|
|
@@ -8414,7 +8663,7 @@ async function calibrateBenchJudges(parsed, rawArgs) {
|
|
|
8414
8663
|
);
|
|
8415
8664
|
process.exit(1);
|
|
8416
8665
|
}
|
|
8417
|
-
const sourceResultSha256 = createHash4("sha256").update(
|
|
8666
|
+
const sourceResultSha256 = createHash4("sha256").update(fs19.readFileSync(latest.path)).digest("hex");
|
|
8418
8667
|
const expandedManifestPath = expandTilde(manifestPath);
|
|
8419
8668
|
if (!bench.resolveLocalLabJudgeProviderConfig) {
|
|
8420
8669
|
console.error(
|
|
@@ -8829,7 +9078,7 @@ function loadPinnedLoCoMoTaskSelector(parsed) {
|
|
|
8829
9078
|
}
|
|
8830
9079
|
let decoded;
|
|
8831
9080
|
try {
|
|
8832
|
-
decoded = JSON.parse(
|
|
9081
|
+
decoded = JSON.parse(fs19.readFileSync(parsed.taskIdsFile, "utf8"));
|
|
8833
9082
|
} catch (error) {
|
|
8834
9083
|
throw new Error(
|
|
8835
9084
|
`Unable to read --task-ids-file ${parsed.taskIdsFile}: ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -9504,7 +9753,7 @@ function resolveBenchReproDatasetDir(datasetDir) {
|
|
|
9504
9753
|
return void 0;
|
|
9505
9754
|
}
|
|
9506
9755
|
try {
|
|
9507
|
-
return
|
|
9756
|
+
return fs19.realpathSync(datasetDir);
|
|
9508
9757
|
} catch {
|
|
9509
9758
|
return datasetDir;
|
|
9510
9759
|
}
|
|
@@ -9558,13 +9807,13 @@ async function writeBenchReproManifestForPackageRun(args) {
|
|
|
9558
9807
|
}
|
|
9559
9808
|
function loadStandaloneConvergeCommandConfig() {
|
|
9560
9809
|
const configPath = resolveConfigPath();
|
|
9561
|
-
const raw =
|
|
9562
|
-
return
|
|
9810
|
+
const raw = fs19.existsSync(configPath) ? JSON.parse(fs19.readFileSync(configPath, "utf8")) : {};
|
|
9811
|
+
return parseConfig10(resolveRemnicConfigRecord9(raw));
|
|
9563
9812
|
}
|
|
9564
9813
|
function parseConvergePluginConfig(value) {
|
|
9565
9814
|
if (value === null || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
9566
9815
|
if (Object.keys(value).length === 0) return void 0;
|
|
9567
|
-
return
|
|
9816
|
+
return parseConfig10(resolveRemnicConfigRecord9(value));
|
|
9568
9817
|
}
|
|
9569
9818
|
function loadConvergeCommandConfig() {
|
|
9570
9819
|
if (readCompatEnv("REMNIC_CONFIG_PATH", "ENGRAM_CONFIG_PATH")) {
|
|
@@ -9587,13 +9836,13 @@ function resolveConfigPath(cliPath) {
|
|
|
9587
9836
|
path18.join(resolveHomeDir(), ".config", "engram", "config.json")
|
|
9588
9837
|
];
|
|
9589
9838
|
for (const candidate of candidates) {
|
|
9590
|
-
if (
|
|
9839
|
+
if (fs19.existsSync(candidate)) return candidate;
|
|
9591
9840
|
}
|
|
9592
9841
|
return path18.join(resolveHomeDir(), ".config", "remnic", "config.json");
|
|
9593
9842
|
}
|
|
9594
9843
|
function resolveExistingBenchRemnicConfigPath(cliPath) {
|
|
9595
9844
|
const configPath = resolveConfigPath(cliPath);
|
|
9596
|
-
if (
|
|
9845
|
+
if (fs19.existsSync(configPath)) {
|
|
9597
9846
|
return configPath;
|
|
9598
9847
|
}
|
|
9599
9848
|
if (cliPath) {
|
|
@@ -9603,7 +9852,7 @@ function resolveExistingBenchRemnicConfigPath(cliPath) {
|
|
|
9603
9852
|
}
|
|
9604
9853
|
function resolveExistingBenchOpenclawConfigPath(cliPath) {
|
|
9605
9854
|
const configPath = resolveOpenclawConfigPath(cliPath);
|
|
9606
|
-
if (
|
|
9855
|
+
if (fs19.existsSync(configPath)) {
|
|
9607
9856
|
return configPath;
|
|
9608
9857
|
}
|
|
9609
9858
|
if (cliPath) {
|
|
@@ -9710,8 +9959,8 @@ function resolveMemoryDir() {
|
|
|
9710
9959
|
const envMemoryDir = readCompatEnv("REMNIC_MEMORY_DIR", "ENGRAM_MEMORY_DIR");
|
|
9711
9960
|
if (envMemoryDir) return normalizeMemoryDirPath(envMemoryDir);
|
|
9712
9961
|
const configPath = resolveConfigPath();
|
|
9713
|
-
const raw =
|
|
9714
|
-
const remnicCfg =
|
|
9962
|
+
const raw = fs19.existsSync(configPath) ? JSON.parse(fs19.readFileSync(configPath, "utf8")) : {};
|
|
9963
|
+
const remnicCfg = resolveRemnicConfigRecord9(raw);
|
|
9715
9964
|
if (typeof remnicCfg.memoryDir === "string" && remnicCfg.memoryDir.length > 0) {
|
|
9716
9965
|
return normalizeMemoryDirPath(remnicCfg.memoryDir);
|
|
9717
9966
|
}
|
|
@@ -9719,18 +9968,18 @@ function resolveMemoryDir() {
|
|
|
9719
9968
|
const standalonePath = path18.join(home, ".remnic", "memory");
|
|
9720
9969
|
const legacyStandalonePath = path18.join(home, ".engram", "memory");
|
|
9721
9970
|
const openclawPath = path18.join(resolveOpenclawStateDir(), "workspace", "memory", "local");
|
|
9722
|
-
if (
|
|
9723
|
-
if (
|
|
9971
|
+
if (fs19.existsSync(standalonePath)) return standalonePath;
|
|
9972
|
+
if (fs19.existsSync(legacyStandalonePath)) return legacyStandalonePath;
|
|
9724
9973
|
return openclawPath;
|
|
9725
9974
|
})();
|
|
9726
9975
|
const manifestPath = getManifestPath();
|
|
9727
|
-
if (
|
|
9976
|
+
if (fs19.existsSync(manifestPath)) {
|
|
9728
9977
|
try {
|
|
9729
9978
|
const active = getActiveSpace();
|
|
9730
9979
|
if (active?.memoryDir) {
|
|
9731
9980
|
const activeMemoryDir = normalizeMemoryDirPath(active.memoryDir);
|
|
9732
|
-
if (!
|
|
9733
|
-
|
|
9981
|
+
if (!fs19.existsSync(activeMemoryDir)) {
|
|
9982
|
+
fs19.mkdirSync(activeMemoryDir, { recursive: true });
|
|
9734
9983
|
}
|
|
9735
9984
|
return activeMemoryDir;
|
|
9736
9985
|
}
|
|
@@ -9779,13 +10028,13 @@ function resolveOpenclawConfigPath(cliPath) {
|
|
|
9779
10028
|
const envPath = process.env.OPENCLAW_CONFIG_PATH || process.env.OPENCLAW_ENGRAM_CONFIG_PATH;
|
|
9780
10029
|
if (envPath) return path18.resolve(expandTilde(envPath));
|
|
9781
10030
|
for (const candidate of DEFAULT_OPENCLAW_CONFIG_PATHS_FOR_DOCTOR) {
|
|
9782
|
-
if (
|
|
10031
|
+
if (fs19.existsSync(candidate)) return candidate;
|
|
9783
10032
|
}
|
|
9784
10033
|
return path18.join(resolveOpenclawStateDir(), "openclaw.json");
|
|
9785
10034
|
}
|
|
9786
10035
|
function readOpenclawConfig(configPath) {
|
|
9787
|
-
if (!
|
|
9788
|
-
const raw =
|
|
10036
|
+
if (!fs19.existsSync(configPath)) return {};
|
|
10037
|
+
const raw = fs19.readFileSync(configPath, "utf-8");
|
|
9789
10038
|
let parsed;
|
|
9790
10039
|
try {
|
|
9791
10040
|
parsed = JSON.parse(raw);
|
|
@@ -9887,9 +10136,9 @@ function formatOpenclawUpgradeStamp(now = /* @__PURE__ */ new Date()) {
|
|
|
9887
10136
|
return `${yyyy}${mm}${dd}-${hh}${min}${ss}`;
|
|
9888
10137
|
}
|
|
9889
10138
|
function backupPathIfPresent(sourcePath, backupPath) {
|
|
9890
|
-
if (!
|
|
9891
|
-
|
|
9892
|
-
|
|
10139
|
+
if (!fs19.existsSync(sourcePath)) return false;
|
|
10140
|
+
fs19.mkdirSync(path18.dirname(backupPath), { recursive: true });
|
|
10141
|
+
fs19.cpSync(sourcePath, backupPath, { recursive: true });
|
|
9893
10142
|
return true;
|
|
9894
10143
|
}
|
|
9895
10144
|
function restartOpenclawGateway() {
|
|
@@ -9908,7 +10157,7 @@ function restartOpenclawGateway() {
|
|
|
9908
10157
|
}
|
|
9909
10158
|
function cmdInit() {
|
|
9910
10159
|
const configPath = path18.join(process.cwd(), "remnic.config.json");
|
|
9911
|
-
if (
|
|
10160
|
+
if (fs19.existsSync(configPath)) {
|
|
9912
10161
|
console.log(`Config already exists: ${configPath}`);
|
|
9913
10162
|
return;
|
|
9914
10163
|
}
|
|
@@ -9924,7 +10173,7 @@ function cmdInit() {
|
|
|
9924
10173
|
authToken: "${REMNIC_AUTH_TOKEN}"
|
|
9925
10174
|
}
|
|
9926
10175
|
};
|
|
9927
|
-
|
|
10176
|
+
fs19.writeFileSync(configPath, JSON.stringify(template, null, 2) + "\n");
|
|
9928
10177
|
console.log(`Created ${configPath}`);
|
|
9929
10178
|
console.log("\nSet these environment variables:");
|
|
9930
10179
|
console.log(" export OPENAI_API_KEY=sk-...");
|
|
@@ -10344,12 +10593,12 @@ async function cmdQuery(queryText, json, explain) {
|
|
|
10344
10593
|
printQueryResult(result, json);
|
|
10345
10594
|
return;
|
|
10346
10595
|
}
|
|
10347
|
-
|
|
10596
|
+
initLogger5();
|
|
10348
10597
|
const configPath = resolveConfigPath();
|
|
10349
|
-
const raw =
|
|
10350
|
-
const remnicCfg =
|
|
10351
|
-
const config =
|
|
10352
|
-
const orchestrator = new
|
|
10598
|
+
const raw = fs19.existsSync(configPath) ? JSON.parse(fs19.readFileSync(configPath, "utf8")) : {};
|
|
10599
|
+
const remnicCfg = resolveRemnicConfigRecord9(raw);
|
|
10600
|
+
const config = parseConfig10(remnicCfg);
|
|
10601
|
+
const orchestrator = new Orchestrator6(config);
|
|
10353
10602
|
await orchestrator.initialize();
|
|
10354
10603
|
const service = new EngramAccessService2(orchestrator);
|
|
10355
10604
|
const recallRequest = buildQueryRecallRequest(queryText);
|
|
@@ -10524,12 +10773,12 @@ async function cmdXray(rest) {
|
|
|
10524
10773
|
await runXrayCommand(rest, xrayCliIo((request) => remoteRecallXray(remote, request)));
|
|
10525
10774
|
return;
|
|
10526
10775
|
}
|
|
10527
|
-
|
|
10776
|
+
initLogger5();
|
|
10528
10777
|
const configPath = resolveConfigPath();
|
|
10529
|
-
const raw =
|
|
10530
|
-
const remnicCfg =
|
|
10531
|
-
const config =
|
|
10532
|
-
const orchestrator = new
|
|
10778
|
+
const raw = fs19.existsSync(configPath) ? JSON.parse(fs19.readFileSync(configPath, "utf8")) : {};
|
|
10779
|
+
const remnicCfg = resolveRemnicConfigRecord9(raw);
|
|
10780
|
+
const config = parseConfig10(remnicCfg);
|
|
10781
|
+
const orchestrator = new Orchestrator6(config);
|
|
10533
10782
|
await orchestrator.initialize();
|
|
10534
10783
|
await orchestrator.deferredReady;
|
|
10535
10784
|
const service = new EngramAccessService2(orchestrator);
|
|
@@ -10556,36 +10805,45 @@ async function runWhoKnowsCommand(rest, io) {
|
|
|
10556
10805
|
});
|
|
10557
10806
|
io.stdout(renderWhoKnows(result, parsed.json));
|
|
10558
10807
|
}
|
|
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();
|
|
10808
|
+
async function withLocalService(fn) {
|
|
10809
|
+
initLogger5();
|
|
10566
10810
|
const configPath = resolveConfigPath();
|
|
10567
|
-
const raw =
|
|
10568
|
-
const
|
|
10569
|
-
const orchestrator = new Orchestrator5(config);
|
|
10811
|
+
const raw = fs19.existsSync(configPath) ? JSON.parse(fs19.readFileSync(configPath, "utf8")) : {};
|
|
10812
|
+
const orchestrator = new Orchestrator6(parseConfig10(resolveRemnicConfigRecord9(raw)));
|
|
10570
10813
|
await orchestrator.initialize();
|
|
10571
10814
|
await orchestrator.deferredReady;
|
|
10572
10815
|
const service = new EngramAccessService2(orchestrator);
|
|
10573
10816
|
try {
|
|
10574
|
-
await
|
|
10575
|
-
whoKnows: (request) => service.whoKnows(request),
|
|
10576
|
-
stdout: (line) => console.log(line)
|
|
10577
|
-
});
|
|
10817
|
+
return await fn(service, orchestrator);
|
|
10578
10818
|
} finally {
|
|
10579
10819
|
orchestrator.abortDeferredInit();
|
|
10580
10820
|
await orchestrator.destroy();
|
|
10581
10821
|
}
|
|
10582
10822
|
}
|
|
10823
|
+
async function cmdWhoKnows(rest) {
|
|
10824
|
+
const { topic, options } = extractWhoKnowsRawArgs(rest);
|
|
10825
|
+
parseWhoKnowsCliOptions(topic, options);
|
|
10826
|
+
if (resolveRemoteDaemon(resolveConfigPath())) {
|
|
10827
|
+
throw new Error("who-knows: remote daemon mode is not supported yet; run with a local config");
|
|
10828
|
+
}
|
|
10829
|
+
await withLocalService((service) => runWhoKnowsCommand(rest, {
|
|
10830
|
+
whoKnows: (request) => service.whoKnows(request),
|
|
10831
|
+
stdout: (line) => console.log(line)
|
|
10832
|
+
}));
|
|
10833
|
+
}
|
|
10834
|
+
async function cmdPromotionCandidates(rest) {
|
|
10835
|
+
if (resolveRemoteDaemon(resolveConfigPath())) throw new Error("promotion-candidates: remote daemon mode is not supported yet; run with a local config");
|
|
10836
|
+
await withLocalService((service) => runPromotionCandidatesCommand(rest, {
|
|
10837
|
+
promotionCandidates: (request) => service.promotionCandidates(request),
|
|
10838
|
+
stdout: (line) => console.log(line)
|
|
10839
|
+
}));
|
|
10840
|
+
}
|
|
10583
10841
|
async function cmdVersions(rest) {
|
|
10584
|
-
|
|
10842
|
+
initLogger5();
|
|
10585
10843
|
const configPath = resolveConfigPath();
|
|
10586
|
-
const raw =
|
|
10587
|
-
const remnicCfg =
|
|
10588
|
-
const config =
|
|
10844
|
+
const raw = fs19.existsSync(configPath) ? JSON.parse(fs19.readFileSync(configPath, "utf8")) : {};
|
|
10845
|
+
const remnicCfg = resolveRemnicConfigRecord9(raw);
|
|
10846
|
+
const config = parseConfig10(remnicCfg);
|
|
10589
10847
|
if (!config.versioningEnabled) {
|
|
10590
10848
|
console.error("Page versioning is disabled (versioningEnabled = false).");
|
|
10591
10849
|
process.exit(1);
|
|
@@ -10697,11 +10955,11 @@ Options:
|
|
|
10697
10955
|
}
|
|
10698
10956
|
}
|
|
10699
10957
|
async function cmdEnrich(rest) {
|
|
10700
|
-
|
|
10958
|
+
initLogger5();
|
|
10701
10959
|
const configPath = resolveConfigPath();
|
|
10702
|
-
const raw =
|
|
10703
|
-
const remnicCfg =
|
|
10704
|
-
const config =
|
|
10960
|
+
const raw = fs19.existsSync(configPath) ? JSON.parse(fs19.readFileSync(configPath, "utf8")) : {};
|
|
10961
|
+
const remnicCfg = resolveRemnicConfigRecord9(raw);
|
|
10962
|
+
const config = parseConfig10(remnicCfg);
|
|
10705
10963
|
const subcommand = rest[0];
|
|
10706
10964
|
if (subcommand === "audit") {
|
|
10707
10965
|
const memoryDir2 = expandTilde(config.memoryDir);
|
|
@@ -10729,7 +10987,7 @@ async function cmdEnrich(rest) {
|
|
|
10729
10987
|
pipelineConfig2.providers = [
|
|
10730
10988
|
{ id: "web-search", enabled: true, costTier: "cheap" }
|
|
10731
10989
|
];
|
|
10732
|
-
const orchestrator2 = new
|
|
10990
|
+
const orchestrator2 = new Orchestrator6(config);
|
|
10733
10991
|
await orchestrator2.initialize();
|
|
10734
10992
|
await orchestrator2.deferredReady;
|
|
10735
10993
|
const searchBackend2 = orchestrator2.qmd;
|
|
@@ -10765,7 +11023,7 @@ Registered providers:`);
|
|
|
10765
11023
|
console.error("Usage: remnic enrich <entity-name> | --all | --dry-run | audit | providers");
|
|
10766
11024
|
process.exit(1);
|
|
10767
11025
|
}
|
|
10768
|
-
const orchestrator = new
|
|
11026
|
+
const orchestrator = new Orchestrator6(config);
|
|
10769
11027
|
await orchestrator.initialize();
|
|
10770
11028
|
await orchestrator.deferredReady;
|
|
10771
11029
|
const storage = await orchestrator.getStorage(config.defaultNamespace);
|
|
@@ -10890,80 +11148,12 @@ Registered providers:`);
|
|
|
10890
11148
|
${totalPersisted} candidate(s) persisted to memory store.`);
|
|
10891
11149
|
}
|
|
10892
11150
|
}
|
|
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
11151
|
async function cmdExtensions(action, rest) {
|
|
10962
|
-
|
|
11152
|
+
initLogger5();
|
|
10963
11153
|
const configPath = resolveConfigPath();
|
|
10964
|
-
const raw =
|
|
10965
|
-
const remnicCfg =
|
|
10966
|
-
const config =
|
|
11154
|
+
const raw = fs19.existsSync(configPath) ? JSON.parse(fs19.readFileSync(configPath, "utf8")) : {};
|
|
11155
|
+
const remnicCfg = resolveRemnicConfigRecord9(raw);
|
|
11156
|
+
const config = parseConfig10(remnicCfg);
|
|
10967
11157
|
const root = resolveExtensionsRoot(config);
|
|
10968
11158
|
const noopLog = { warn: () => {
|
|
10969
11159
|
}, debug: () => {
|
|
@@ -11012,7 +11202,7 @@ Root: ${root}`);
|
|
|
11012
11202
|
const extensions = await discoverMemoryExtensions(root, warnLog);
|
|
11013
11203
|
let entries = [];
|
|
11014
11204
|
try {
|
|
11015
|
-
entries =
|
|
11205
|
+
entries = fs19.readdirSync(root);
|
|
11016
11206
|
} catch {
|
|
11017
11207
|
console.log(`Extensions root does not exist: ${root}`);
|
|
11018
11208
|
process.exitCode = 0;
|
|
@@ -11023,7 +11213,7 @@ Root: ${root}`);
|
|
|
11023
11213
|
for (const entry of entries) {
|
|
11024
11214
|
const entryPath = path18.join(root, entry);
|
|
11025
11215
|
try {
|
|
11026
|
-
if (!
|
|
11216
|
+
if (!fs19.statSync(entryPath).isDirectory()) continue;
|
|
11027
11217
|
} catch {
|
|
11028
11218
|
continue;
|
|
11029
11219
|
}
|
|
@@ -11053,11 +11243,11 @@ Root: ${root}`);
|
|
|
11053
11243
|
}
|
|
11054
11244
|
}
|
|
11055
11245
|
async function cmdBriefing(rest) {
|
|
11056
|
-
|
|
11246
|
+
initLogger5();
|
|
11057
11247
|
const configPath = resolveConfigPath();
|
|
11058
|
-
const raw =
|
|
11059
|
-
const remnicCfg =
|
|
11060
|
-
const config =
|
|
11248
|
+
const raw = fs19.existsSync(configPath) ? JSON.parse(fs19.readFileSync(configPath, "utf8")) : {};
|
|
11249
|
+
const remnicCfg = resolveRemnicConfigRecord9(raw);
|
|
11250
|
+
const config = parseConfig10(remnicCfg);
|
|
11061
11251
|
if (!config.briefing.enabled) {
|
|
11062
11252
|
console.error("Briefing is disabled in config (briefing.enabled = false).");
|
|
11063
11253
|
process.exit(1);
|
|
@@ -11110,7 +11300,7 @@ async function cmdBriefing(rest) {
|
|
|
11110
11300
|
process.exit(1);
|
|
11111
11301
|
}
|
|
11112
11302
|
const format = effectiveFormatFlag === "json" ? "json" : effectiveFormatFlag === "markdown" ? "markdown" : config.briefing.defaultFormat;
|
|
11113
|
-
const orchestrator = new
|
|
11303
|
+
const orchestrator = new Orchestrator6(config);
|
|
11114
11304
|
await orchestrator.initialize();
|
|
11115
11305
|
const storage = await orchestrator.getStorage(config.defaultNamespace);
|
|
11116
11306
|
const calendarSource = config.briefing.calendarSource ? new FileCalendarSource(config.briefing.calendarSource) : void 0;
|
|
@@ -11135,10 +11325,10 @@ async function cmdBriefing(rest) {
|
|
|
11135
11325
|
if (save) {
|
|
11136
11326
|
try {
|
|
11137
11327
|
const saveDir = resolveBriefingSaveDir(config.briefing.saveDir);
|
|
11138
|
-
|
|
11328
|
+
fs19.mkdirSync(saveDir, { recursive: true });
|
|
11139
11329
|
const filename = briefingFilename(new Date(result.window.to), format);
|
|
11140
11330
|
const filePath = path18.join(saveDir, filename);
|
|
11141
|
-
|
|
11331
|
+
fs19.writeFileSync(filePath, payload + (payload.endsWith("\n") ? "" : "\n"));
|
|
11142
11332
|
console.error(`Saved briefing: ${filePath}`);
|
|
11143
11333
|
} catch (err) {
|
|
11144
11334
|
console.error(`Failed to save briefing: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -11156,7 +11346,7 @@ async function cmdDoctor() {
|
|
|
11156
11346
|
detail: `${nodeVersion} (requires >= 22.12.0)`
|
|
11157
11347
|
});
|
|
11158
11348
|
const configPath = resolveConfigPath();
|
|
11159
|
-
const configExists =
|
|
11349
|
+
const configExists = fs19.existsSync(configPath);
|
|
11160
11350
|
checks.push({ name: "Config file", ok: configExists, detail: configPath });
|
|
11161
11351
|
let standaloneConfig;
|
|
11162
11352
|
let standaloneConfigError;
|
|
@@ -11164,11 +11354,11 @@ async function cmdDoctor() {
|
|
|
11164
11354
|
let configuredNs = { invalid: false };
|
|
11165
11355
|
if (configExists) {
|
|
11166
11356
|
try {
|
|
11167
|
-
const raw = JSON.parse(
|
|
11168
|
-
const remnicCfg =
|
|
11357
|
+
const raw = JSON.parse(fs19.readFileSync(configPath, "utf8"));
|
|
11358
|
+
const remnicCfg = resolveRemnicConfigRecord9(raw);
|
|
11169
11359
|
standaloneOpenaiApiKeyExplicitlyFalse = isOpenaiApiKeyDisabled(remnicCfg.openaiApiKey);
|
|
11170
11360
|
configuredNs = readConfiguredNamespace(remnicCfg);
|
|
11171
|
-
standaloneConfig =
|
|
11361
|
+
standaloneConfig = parseConfig10(remnicCfg);
|
|
11172
11362
|
} catch (err) {
|
|
11173
11363
|
standaloneConfigError = err instanceof Error ? err.message : String(err);
|
|
11174
11364
|
}
|
|
@@ -11177,10 +11367,10 @@ async function cmdDoctor() {
|
|
|
11177
11367
|
try {
|
|
11178
11368
|
memoryDir = resolveMemoryDir();
|
|
11179
11369
|
} catch {
|
|
11180
|
-
memoryDir =
|
|
11370
|
+
memoryDir = parseConfig10({}).memoryDir;
|
|
11181
11371
|
}
|
|
11182
11372
|
try {
|
|
11183
|
-
|
|
11373
|
+
fs19.mkdirSync(memoryDir, { recursive: true });
|
|
11184
11374
|
checks.push({ name: "Memory directory", ok: true, detail: memoryDir });
|
|
11185
11375
|
} catch {
|
|
11186
11376
|
checks.push({ name: "Memory directory", ok: false, detail: `cannot create ${memoryDir}` });
|
|
@@ -11209,7 +11399,7 @@ async function cmdDoctor() {
|
|
|
11209
11399
|
});
|
|
11210
11400
|
if (nsPolicyCheck) checks.push(nsPolicyCheck);
|
|
11211
11401
|
const openclawConfigPath = resolveOpenclawConfigPath();
|
|
11212
|
-
const openclawConfigExists =
|
|
11402
|
+
const openclawConfigExists = fs19.existsSync(openclawConfigPath);
|
|
11213
11403
|
let openclawConfig = {};
|
|
11214
11404
|
let openclawConfigValid = false;
|
|
11215
11405
|
let openclawPluginModeConfigured = false;
|
|
@@ -11217,7 +11407,7 @@ async function cmdDoctor() {
|
|
|
11217
11407
|
let activeOpenclawEntryConfig = null;
|
|
11218
11408
|
if (openclawConfigExists) {
|
|
11219
11409
|
try {
|
|
11220
|
-
const parsed = JSON.parse(
|
|
11410
|
+
const parsed = JSON.parse(fs19.readFileSync(openclawConfigPath, "utf-8"));
|
|
11221
11411
|
if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
|
|
11222
11412
|
openclawConfig = parsed;
|
|
11223
11413
|
openclawConfigValid = true;
|
|
@@ -11297,9 +11487,9 @@ async function cmdDoctor() {
|
|
|
11297
11487
|
let memDirOk = false;
|
|
11298
11488
|
let memDirDetail = `${resolvedMemDir} (not found)`;
|
|
11299
11489
|
let memDirRemediation = `Run \`remnic openclaw install --memory-dir "${resolvedMemDir}"\` to create the directory.`;
|
|
11300
|
-
if (
|
|
11490
|
+
if (fs19.existsSync(resolvedMemDir)) {
|
|
11301
11491
|
try {
|
|
11302
|
-
const stat2 =
|
|
11492
|
+
const stat2 = fs19.statSync(resolvedMemDir);
|
|
11303
11493
|
if (stat2.isDirectory()) {
|
|
11304
11494
|
memDirOk = true;
|
|
11305
11495
|
memDirDetail = resolvedMemDir;
|
|
@@ -11454,12 +11644,12 @@ async function cmdDoctor() {
|
|
|
11454
11644
|
}
|
|
11455
11645
|
function cmdConfig() {
|
|
11456
11646
|
const configPath = resolveConfigPath();
|
|
11457
|
-
if (!
|
|
11647
|
+
if (!fs19.existsSync(configPath)) {
|
|
11458
11648
|
console.log("No config file found. Run `remnic init` to create one.");
|
|
11459
11649
|
return;
|
|
11460
11650
|
}
|
|
11461
11651
|
console.log(`Config: ${configPath}`);
|
|
11462
|
-
const rawConfig =
|
|
11652
|
+
const rawConfig = fs19.readFileSync(configPath, "utf8");
|
|
11463
11653
|
const redacted = rawConfig.replace(
|
|
11464
11654
|
/("(?:openaiApiKey|localLlmApiKey|authToken|apiKey|remoteSearchApiKey|meilisearchApiKey|opikApiKey)"\s*:\s*")([^"]*)(")/g,
|
|
11465
11655
|
"$1[REDACTED]$3"
|
|
@@ -11563,13 +11753,13 @@ async function cmdReview(action, rest) {
|
|
|
11563
11753
|
console.error("Usage: remnic review <approve|dismiss|flag> <id>");
|
|
11564
11754
|
process.exit(1);
|
|
11565
11755
|
}
|
|
11566
|
-
const storage = new
|
|
11756
|
+
const storage = new StorageManager3(memoryDir);
|
|
11567
11757
|
const configPath = resolveConfigPath();
|
|
11568
11758
|
let tombstonesConfig = null;
|
|
11569
11759
|
try {
|
|
11570
|
-
const rawCfg =
|
|
11571
|
-
const remnicCfg =
|
|
11572
|
-
const config =
|
|
11760
|
+
const rawCfg = fs19.existsSync(configPath) ? JSON.parse(fs19.readFileSync(configPath, "utf8")) : {};
|
|
11761
|
+
const remnicCfg = resolveRemnicConfigRecord9(rawCfg);
|
|
11762
|
+
const config = parseConfig10(remnicCfg);
|
|
11573
11763
|
tombstonesConfig = {
|
|
11574
11764
|
enabled: config.tombstonesEnabled,
|
|
11575
11765
|
semanticMatch: config.tombstonesSemanticMatch,
|
|
@@ -12311,7 +12501,7 @@ async function pushOfflineFileContent(args) {
|
|
|
12311
12501
|
}
|
|
12312
12502
|
async function pushOfflineFileContentFromChunkReader(args) {
|
|
12313
12503
|
const filePath = resolveOfflineDirectHydrationPath(args.memoryDir, args.file.path);
|
|
12314
|
-
const stat2 =
|
|
12504
|
+
const stat2 = fs19.statSync(filePath);
|
|
12315
12505
|
if (stat2.mtimeMs !== args.file.mtimeMs) {
|
|
12316
12506
|
throw new Error(`local file changed while pushing offline content: ${args.file.path}`);
|
|
12317
12507
|
}
|
|
@@ -12802,7 +12992,7 @@ function advanceOfflineBaseFilesForSuccessfulPush(options) {
|
|
|
12802
12992
|
return [...next.values()].sort((left, right) => left.path.localeCompare(right.path));
|
|
12803
12993
|
}
|
|
12804
12994
|
async function runOfflineSyncOnce(options) {
|
|
12805
|
-
|
|
12995
|
+
fs19.mkdirSync(options.memoryDir, { recursive: true });
|
|
12806
12996
|
let activeStatePath = options.statePath;
|
|
12807
12997
|
let priorState = await readOfflineSyncState(activeStatePath);
|
|
12808
12998
|
let syncNamespace = options.namespace ?? priorState?.namespace;
|
|
@@ -13435,7 +13625,7 @@ Environment fallbacks:
|
|
|
13435
13625
|
const configPath = resolveConfigPath();
|
|
13436
13626
|
let config;
|
|
13437
13627
|
try {
|
|
13438
|
-
const rawConfig =
|
|
13628
|
+
const rawConfig = fs19.existsSync(configPath) ? JSON.parse(fs19.readFileSync(configPath, "utf8")) : {};
|
|
13439
13629
|
config = parseConfigQuietly(pickOfflineConfigRecord(rawConfig));
|
|
13440
13630
|
} catch {
|
|
13441
13631
|
throw new Error(
|
|
@@ -13450,7 +13640,7 @@ Environment fallbacks:
|
|
|
13450
13640
|
const statePath = statePathExplicit ? path18.resolve(expandTilde(stateOverride)) : remoteUrl !== void 0 ? defaultOfflineSyncStatePath(memoryDir, remoteUrl, namespace) : void 0;
|
|
13451
13641
|
if (action === "prepare") {
|
|
13452
13642
|
if (!remoteUrl || !token || !statePath) throw new Error("offline prepare requires remote URL and token");
|
|
13453
|
-
|
|
13643
|
+
fs19.mkdirSync(memoryDir, { recursive: true });
|
|
13454
13644
|
const remoteSnapshot = await fetchOfflineSnapshot({
|
|
13455
13645
|
remoteUrl,
|
|
13456
13646
|
token,
|
|
@@ -13549,7 +13739,7 @@ Environment fallbacks:
|
|
|
13549
13739
|
return;
|
|
13550
13740
|
}
|
|
13551
13741
|
if (action === "status") {
|
|
13552
|
-
|
|
13742
|
+
fs19.mkdirSync(memoryDir, { recursive: true });
|
|
13553
13743
|
const state = statePath ? await readOfflineSyncState(statePath) : null;
|
|
13554
13744
|
if (state && remoteUrl && statePath) {
|
|
13555
13745
|
assertOfflineStateMatches({
|
|
@@ -13687,7 +13877,7 @@ function cmdDedup(json) {
|
|
|
13687
13877
|
function readInstalledConnectorConfig(configPath, fallback) {
|
|
13688
13878
|
if (!configPath) return fallback;
|
|
13689
13879
|
try {
|
|
13690
|
-
const parsed = JSON.parse(
|
|
13880
|
+
const parsed = JSON.parse(fs19.readFileSync(configPath, "utf8"));
|
|
13691
13881
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return fallback;
|
|
13692
13882
|
const { token: _token, ...config } = parsed;
|
|
13693
13883
|
return config;
|
|
@@ -13865,7 +14055,7 @@ async function cmdConnectors(action, rest, json) {
|
|
|
13865
14055
|
const pub = factory();
|
|
13866
14056
|
const available = await pub.isHostAvailable();
|
|
13867
14057
|
const extRoot = available ? await pub.resolveExtensionRoot() : "(host not installed)";
|
|
13868
|
-
const extensionExists = available && extRoot ?
|
|
14058
|
+
const extensionExists = available && extRoot ? fs19.existsSync(extRoot) : false;
|
|
13869
14059
|
publisherChecks.push({
|
|
13870
14060
|
name: `Publisher: ${targetHostId}`,
|
|
13871
14061
|
ok: !available || extensionExists,
|
|
@@ -13939,7 +14129,7 @@ async function cmdConnectors(action, rest, json) {
|
|
|
13939
14129
|
let connectorsCfg;
|
|
13940
14130
|
const configPath = resolveConfigPath();
|
|
13941
14131
|
try {
|
|
13942
|
-
const raw =
|
|
14132
|
+
const raw = fs19.existsSync(configPath) ? JSON.parse(fs19.readFileSync(configPath, "utf8")) : {};
|
|
13943
14133
|
connectorsCfg = parseConfigQuietly(raw).connectors;
|
|
13944
14134
|
} catch {
|
|
13945
14135
|
process.stderr.write(
|
|
@@ -14013,12 +14203,12 @@ async function cmdConnectors(action, rest, json) {
|
|
|
14013
14203
|
process.exitCode = 2;
|
|
14014
14204
|
return;
|
|
14015
14205
|
}
|
|
14016
|
-
|
|
14206
|
+
initLogger5();
|
|
14017
14207
|
const configPath = resolveConfigPath();
|
|
14018
|
-
const raw =
|
|
14019
|
-
const remnicCfg =
|
|
14020
|
-
const config =
|
|
14021
|
-
const orchestrator = new
|
|
14208
|
+
const raw = fs19.existsSync(configPath) ? JSON.parse(fs19.readFileSync(configPath, "utf8")) : {};
|
|
14209
|
+
const remnicCfg = resolveRemnicConfigRecord9(raw);
|
|
14210
|
+
const config = parseConfig10(remnicCfg);
|
|
14211
|
+
const orchestrator = new Orchestrator6(config);
|
|
14022
14212
|
try {
|
|
14023
14213
|
await orchestrator.initialize();
|
|
14024
14214
|
await orchestrator.deferredReady;
|
|
@@ -14140,9 +14330,9 @@ async function cmdConnectorsMarketplace(subAction, rest, json) {
|
|
|
14140
14330
|
console.error(`connectors marketplace: ${err instanceof Error ? err.message : String(err)}`);
|
|
14141
14331
|
process.exit(1);
|
|
14142
14332
|
}
|
|
14143
|
-
const rawConfig =
|
|
14144
|
-
const pluginConfig =
|
|
14145
|
-
const config =
|
|
14333
|
+
const rawConfig = fs19.existsSync(configPath) ? JSON.parse(fs19.readFileSync(configPath, "utf8")) : {};
|
|
14334
|
+
const pluginConfig = resolveRemnicConfigRecord9(rawConfig);
|
|
14335
|
+
const config = parseConfig10(pluginConfig);
|
|
14146
14336
|
if (subAction === "generate") {
|
|
14147
14337
|
let outputDir;
|
|
14148
14338
|
try {
|
|
@@ -14162,13 +14352,13 @@ async function cmdConnectorsMarketplace(subAction, rest, json) {
|
|
|
14162
14352
|
} else if (subAction === "validate") {
|
|
14163
14353
|
const targetPath = rest.filter((a) => !a.startsWith("--"))[0] ?? path18.join(process.cwd(), "marketplace.json");
|
|
14164
14354
|
const resolved = path18.resolve(targetPath);
|
|
14165
|
-
if (!
|
|
14355
|
+
if (!fs19.existsSync(resolved)) {
|
|
14166
14356
|
console.error(`File not found: ${resolved}`);
|
|
14167
14357
|
process.exit(1);
|
|
14168
14358
|
}
|
|
14169
14359
|
let parsed;
|
|
14170
14360
|
try {
|
|
14171
|
-
parsed = JSON.parse(
|
|
14361
|
+
parsed = JSON.parse(fs19.readFileSync(resolved, "utf8"));
|
|
14172
14362
|
} catch {
|
|
14173
14363
|
console.error(`Invalid JSON in ${resolved}`);
|
|
14174
14364
|
process.exit(1);
|
|
@@ -14339,12 +14529,14 @@ async function cmdSpace(action, rest, json) {
|
|
|
14339
14529
|
}
|
|
14340
14530
|
const result = await promoteSpace(sourceId, targetId, {
|
|
14341
14531
|
force: rest.includes("--force"),
|
|
14342
|
-
forceOverwrite: rest.includes("--force-overwrite")
|
|
14532
|
+
forceOverwrite: rest.includes("--force-overwrite"),
|
|
14533
|
+
allowUserSubject: rest.includes("--allow-user-subject")
|
|
14343
14534
|
});
|
|
14344
14535
|
if (json) {
|
|
14345
14536
|
console.log(JSON.stringify(result, null, 2));
|
|
14346
14537
|
} else {
|
|
14347
14538
|
console.log(`Promoted ${result.memoriesPromoted} memories`);
|
|
14539
|
+
if (result.subjectWarnings && result.subjectWarnings.length > 0) console.log(`Subject-guard warnings: ${result.subjectWarnings.length} (see --json)`);
|
|
14348
14540
|
if (result.conflicts.length > 0) console.log(`Conflicts: ${result.conflicts.length}`);
|
|
14349
14541
|
console.log(`Duration: ${result.durationMs}ms`);
|
|
14350
14542
|
}
|
|
@@ -14367,12 +14559,12 @@ async function cmdSpace(action, rest, json) {
|
|
|
14367
14559
|
}
|
|
14368
14560
|
}
|
|
14369
14561
|
async function cmdLegacyBenchmark(action, rest, json) {
|
|
14370
|
-
|
|
14562
|
+
initLogger5();
|
|
14371
14563
|
const configPath = resolveConfigPath();
|
|
14372
|
-
const raw =
|
|
14373
|
-
const remnicCfg =
|
|
14374
|
-
const config =
|
|
14375
|
-
const orchestrator = new
|
|
14564
|
+
const raw = fs19.existsSync(configPath) ? JSON.parse(fs19.readFileSync(configPath, "utf8")) : {};
|
|
14565
|
+
const remnicCfg = resolveRemnicConfigRecord9(raw);
|
|
14566
|
+
const config = parseConfig10(remnicCfg);
|
|
14567
|
+
const orchestrator = new Orchestrator6(config);
|
|
14376
14568
|
const service = new EngramAccessService2(orchestrator);
|
|
14377
14569
|
const { runBenchSuite, loadBaseline, checkRegression } = await loadBenchModule();
|
|
14378
14570
|
const benchConfig = {
|
|
@@ -14774,7 +14966,7 @@ function readPid() {
|
|
|
14774
14966
|
function inferPort() {
|
|
14775
14967
|
try {
|
|
14776
14968
|
const configPath = resolveConfigPath();
|
|
14777
|
-
const raw = JSON.parse(
|
|
14969
|
+
const raw = JSON.parse(fs19.readFileSync(configPath, "utf8"));
|
|
14778
14970
|
return raw.server?.port ?? 4318;
|
|
14779
14971
|
} catch {
|
|
14780
14972
|
return 4318;
|
|
@@ -14869,13 +15061,13 @@ function daemonInstall() {
|
|
|
14869
15061
|
process.exit(1);
|
|
14870
15062
|
}
|
|
14871
15063
|
const vars = { HOME: home, NODE_PATH: nodePath, REMNIC_SERVER_BIN: serverBin };
|
|
14872
|
-
|
|
15064
|
+
fs19.mkdirSync(LOGS_DIR, { recursive: true });
|
|
14873
15065
|
if (isMacOS()) {
|
|
14874
15066
|
const templatePath = path18.resolve(import.meta.dirname, "../templates/launchd/ai.remnic.daemon.plist");
|
|
14875
|
-
const template =
|
|
15067
|
+
const template = fs19.readFileSync(templatePath, "utf8");
|
|
14876
15068
|
const plist = renderTemplate(template, vars);
|
|
14877
|
-
|
|
14878
|
-
|
|
15069
|
+
fs19.mkdirSync(path18.dirname(LAUNCHD_PLIST_PATH), { recursive: true });
|
|
15070
|
+
fs19.writeFileSync(LAUNCHD_PLIST_PATH, plist);
|
|
14879
15071
|
try {
|
|
14880
15072
|
launchdLoadPlist(LAUNCHD_PLIST_PATH);
|
|
14881
15073
|
} catch (err) {
|
|
@@ -14892,10 +15084,10 @@ function daemonInstall() {
|
|
|
14892
15084
|
console.log(` Logs: ${LOGS_DIR}/daemon.log`);
|
|
14893
15085
|
} else if (isLinux()) {
|
|
14894
15086
|
const templatePath = path18.resolve(import.meta.dirname, "../templates/systemd/remnic.service");
|
|
14895
|
-
const template =
|
|
15087
|
+
const template = fs19.readFileSync(templatePath, "utf8");
|
|
14896
15088
|
const unit = renderTemplate(template, vars);
|
|
14897
|
-
|
|
14898
|
-
|
|
15089
|
+
fs19.mkdirSync(path18.dirname(SYSTEMD_UNIT_PATH), { recursive: true });
|
|
15090
|
+
fs19.writeFileSync(SYSTEMD_UNIT_PATH, unit);
|
|
14899
15091
|
try {
|
|
14900
15092
|
childProcess2.execSync("systemctl --user daemon-reload", { stdio: "pipe" });
|
|
14901
15093
|
} catch (err) {
|
|
@@ -14931,7 +15123,7 @@ function daemonUninstall() {
|
|
|
14931
15123
|
} catch {
|
|
14932
15124
|
}
|
|
14933
15125
|
try {
|
|
14934
|
-
|
|
15126
|
+
fs19.unlinkSync(plistPath);
|
|
14935
15127
|
removed = true;
|
|
14936
15128
|
console.log(`Removed launchd service: ${plistPath}`);
|
|
14937
15129
|
} catch {
|
|
@@ -14951,7 +15143,7 @@ function daemonUninstall() {
|
|
|
14951
15143
|
let removed = false;
|
|
14952
15144
|
for (const unitPath of SYSTEMD_UNIT_PATHS) {
|
|
14953
15145
|
try {
|
|
14954
|
-
|
|
15146
|
+
fs19.unlinkSync(unitPath);
|
|
14955
15147
|
removed = true;
|
|
14956
15148
|
console.log(`Removed systemd service: ${unitPath}`);
|
|
14957
15149
|
} catch {
|
|
@@ -15018,13 +15210,13 @@ async function daemonStatus() {
|
|
|
15018
15210
|
console.log(` Port: ${port}`);
|
|
15019
15211
|
console.log(` Service: ${serviceInstalled ? "installed" : "not installed"}`);
|
|
15020
15212
|
console.log(` Platform: ${process.platform}`);
|
|
15021
|
-
console.log(` PID file: ${
|
|
15022
|
-
console.log(` Log file: ${
|
|
15213
|
+
console.log(` PID file: ${fs19.existsSync(PID_FILE) ? PID_FILE : LEGACY_PID_FILE}`);
|
|
15214
|
+
console.log(` Log file: ${fs19.existsSync(LOG_FILE) ? LOG_FILE : LEGACY_LOG_FILE}`);
|
|
15023
15215
|
try {
|
|
15024
15216
|
const configPath = resolveConfigPath();
|
|
15025
|
-
const raw =
|
|
15026
|
-
const remnicCfg =
|
|
15027
|
-
const config =
|
|
15217
|
+
const raw = fs19.existsSync(configPath) ? JSON.parse(fs19.readFileSync(configPath, "utf8")) : {};
|
|
15218
|
+
const remnicCfg = resolveRemnicConfigRecord9(raw);
|
|
15219
|
+
const config = parseConfig10(remnicCfg);
|
|
15028
15220
|
const extRoot = resolveExtensionsRoot(config);
|
|
15029
15221
|
const noopLog = { warn: () => {
|
|
15030
15222
|
}, debug: () => {
|
|
@@ -15063,9 +15255,9 @@ function daemonStart() {
|
|
|
15063
15255
|
return;
|
|
15064
15256
|
}
|
|
15065
15257
|
}
|
|
15066
|
-
|
|
15067
|
-
|
|
15068
|
-
const logStream =
|
|
15258
|
+
fs19.mkdirSync(PID_DIR, { recursive: true });
|
|
15259
|
+
fs19.mkdirSync(LOGS_DIR, { recursive: true });
|
|
15260
|
+
const logStream = fs19.openSync(LOG_FILE, "a");
|
|
15069
15261
|
const serverBin = resolveServerBin();
|
|
15070
15262
|
const isSource = serverBin.endsWith(".ts");
|
|
15071
15263
|
let cmd;
|
|
@@ -15087,7 +15279,7 @@ function daemonStart() {
|
|
|
15087
15279
|
}
|
|
15088
15280
|
});
|
|
15089
15281
|
child.unref();
|
|
15090
|
-
|
|
15282
|
+
fs19.writeFileSync(PID_FILE, String(child.pid));
|
|
15091
15283
|
console.log(`Started remnic server (pid ${child.pid})`);
|
|
15092
15284
|
console.log(` Log: ${LOG_FILE}`);
|
|
15093
15285
|
}
|
|
@@ -15121,11 +15313,11 @@ function daemonStop() {
|
|
|
15121
15313
|
console.log("Process not found (cleaning up PID file)");
|
|
15122
15314
|
}
|
|
15123
15315
|
try {
|
|
15124
|
-
|
|
15316
|
+
fs19.unlinkSync(PID_FILE);
|
|
15125
15317
|
} catch {
|
|
15126
15318
|
}
|
|
15127
15319
|
try {
|
|
15128
|
-
|
|
15320
|
+
fs19.unlinkSync(LEGACY_PID_FILE);
|
|
15129
15321
|
} catch {
|
|
15130
15322
|
}
|
|
15131
15323
|
}
|
|
@@ -15251,11 +15443,11 @@ async function promptYesNo(question, defaultYes = true) {
|
|
|
15251
15443
|
});
|
|
15252
15444
|
}
|
|
15253
15445
|
async function cmdBinary(rest) {
|
|
15254
|
-
|
|
15446
|
+
initLogger5();
|
|
15255
15447
|
const configPath = resolveConfigPath();
|
|
15256
|
-
const raw =
|
|
15257
|
-
const remnicCfg =
|
|
15258
|
-
const config =
|
|
15448
|
+
const raw = fs19.existsSync(configPath) ? JSON.parse(fs19.readFileSync(configPath, "utf8")) : {};
|
|
15449
|
+
const remnicCfg = resolveRemnicConfigRecord9(raw);
|
|
15450
|
+
const config = parseConfig10(remnicCfg);
|
|
15259
15451
|
const memoryDir = resolveMemoryDir();
|
|
15260
15452
|
const blConfig = {
|
|
15261
15453
|
enabled: config.binaryLifecycleEnabled,
|
|
@@ -15444,7 +15636,7 @@ async function cmdOpenclawInstall(opts) {
|
|
|
15444
15636
|
} else if (slotIsActiveLegacy) {
|
|
15445
15637
|
changes.push(` Slot left as "${REMNIC_OPENCLAW_LEGACY_PLUGIN_ID}" \u2014 re-run with --yes to activate the new entry`);
|
|
15446
15638
|
}
|
|
15447
|
-
if (!
|
|
15639
|
+
if (!fs19.existsSync(memoryDir)) changes.push(`+ Will create memory directory: ${memoryDir}`);
|
|
15448
15640
|
if (hasLegacy && migrateLegacy) {
|
|
15449
15641
|
changes.push(`~ Legacy '${REMNIC_OPENCLAW_LEGACY_PLUGIN_ID}' entry retained (safe to remove after verifying hooks fire)`);
|
|
15450
15642
|
}
|
|
@@ -15464,8 +15656,8 @@ async function cmdOpenclawInstall(opts) {
|
|
|
15464
15656
|
Resulting plugins.slots.memory: ${dryRunPlugins.slots?.memory ?? "(unset)"}`);
|
|
15465
15657
|
return;
|
|
15466
15658
|
}
|
|
15467
|
-
if (
|
|
15468
|
-
const st =
|
|
15659
|
+
if (fs19.existsSync(memoryDir)) {
|
|
15660
|
+
const st = fs19.statSync(memoryDir);
|
|
15469
15661
|
if (!st.isDirectory()) {
|
|
15470
15662
|
throw new Error(
|
|
15471
15663
|
`Cannot use ${memoryDir} as the memory directory \u2014 a file already exists at that path.
|
|
@@ -15473,12 +15665,12 @@ Remove it first and re-run, or choose a different path with --memory-dir.`
|
|
|
15473
15665
|
);
|
|
15474
15666
|
}
|
|
15475
15667
|
} else {
|
|
15476
|
-
|
|
15668
|
+
fs19.mkdirSync(memoryDir, { recursive: true });
|
|
15477
15669
|
console.log(`Created memory directory: ${memoryDir}`);
|
|
15478
15670
|
}
|
|
15479
15671
|
const configDir = path18.dirname(configPath);
|
|
15480
|
-
if (!
|
|
15481
|
-
|
|
15672
|
+
if (!fs19.existsSync(configDir)) {
|
|
15673
|
+
fs19.mkdirSync(configDir, { recursive: true });
|
|
15482
15674
|
}
|
|
15483
15675
|
atomicWriteFileSync(configPath, JSON.stringify(updatedConfig, null, 2) + "\n");
|
|
15484
15676
|
console.log("\nDone! Summary of changes:");
|
|
@@ -15507,7 +15699,7 @@ async function cmdOpenclawUpgrade(opts) {
|
|
|
15507
15699
|
const legacyPluginDirForBackup = opts.legacyPluginDirForBackup ? resolveOpenclawLegacyPluginDir(opts.legacyPluginDirForBackup) : void 0;
|
|
15508
15700
|
const fallbackMemoryDir = path18.join(resolveOpenclawStateDir(), "workspace", "memory", "local");
|
|
15509
15701
|
const packageSpec = buildOpenclawManagedUpgradePackageSpec(opts.version);
|
|
15510
|
-
const configExistedBefore =
|
|
15702
|
+
const configExistedBefore = fs19.existsSync(configPath);
|
|
15511
15703
|
const existingConfig = readOpenclawConfig(configPath);
|
|
15512
15704
|
const { entries, slots } = parseOpenclawPluginState(existingConfig, configPath);
|
|
15513
15705
|
const preservedMemoryDir = opts.memoryDir ? path18.resolve(expandTilde(opts.memoryDir)) : resolveCurrentOpenclawMemoryDir(entries, slots, fallbackMemoryDir);
|
|
@@ -15732,15 +15924,15 @@ async function cmdOpenclawMigrateEngram(opts) {
|
|
|
15732
15924
|
}
|
|
15733
15925
|
function createOpenclawUpgradeBackupDir() {
|
|
15734
15926
|
const backupsRoot = path18.join(resolveOpenclawStateDir(), "backups");
|
|
15735
|
-
|
|
15736
|
-
return
|
|
15927
|
+
fs19.mkdirSync(backupsRoot, { recursive: true });
|
|
15928
|
+
return fs19.mkdtempSync(path18.join(backupsRoot, `remnic-openclaw-upgrade-${formatOpenclawUpgradeStamp()}-`));
|
|
15737
15929
|
}
|
|
15738
15930
|
async function cmdTaxonomy(rest) {
|
|
15739
|
-
|
|
15931
|
+
initLogger5();
|
|
15740
15932
|
const configPath = resolveConfigPath();
|
|
15741
|
-
const raw =
|
|
15742
|
-
const remnicCfg =
|
|
15743
|
-
const config =
|
|
15933
|
+
const raw = fs19.existsSync(configPath) ? JSON.parse(fs19.readFileSync(configPath, "utf8")) : {};
|
|
15934
|
+
const remnicCfg = resolveRemnicConfigRecord9(raw);
|
|
15935
|
+
const config = parseConfig10(remnicCfg);
|
|
15744
15936
|
if (!config.taxonomyEnabled) {
|
|
15745
15937
|
console.error(
|
|
15746
15938
|
"Taxonomy is disabled in config (taxonomyEnabled = false). Enable it to use taxonomy commands."
|
|
@@ -15776,8 +15968,8 @@ async function cmdTaxonomy(rest) {
|
|
|
15776
15968
|
console.log(doc);
|
|
15777
15969
|
if (config.taxonomyAutoGenResolver) {
|
|
15778
15970
|
const resolverPath = path18.join(config.memoryDir, ".taxonomy", "RESOLVER.md");
|
|
15779
|
-
|
|
15780
|
-
|
|
15971
|
+
fs19.mkdirSync(path18.dirname(resolverPath), { recursive: true });
|
|
15972
|
+
fs19.writeFileSync(resolverPath, doc);
|
|
15781
15973
|
console.error(`Written: ${resolverPath}`);
|
|
15782
15974
|
}
|
|
15783
15975
|
break;
|
|
@@ -15823,7 +16015,7 @@ async function cmdTaxonomy(rest) {
|
|
|
15823
16015
|
if (config.taxonomyAutoGenResolver) {
|
|
15824
16016
|
const doc = generateResolverDocument(taxonomy);
|
|
15825
16017
|
const resolverPath = path18.join(config.memoryDir, ".taxonomy", "RESOLVER.md");
|
|
15826
|
-
|
|
16018
|
+
fs19.writeFileSync(resolverPath, doc);
|
|
15827
16019
|
console.error(`Regenerated: ${resolverPath}`);
|
|
15828
16020
|
}
|
|
15829
16021
|
break;
|
|
@@ -15854,7 +16046,7 @@ async function cmdTaxonomy(rest) {
|
|
|
15854
16046
|
if (config.taxonomyAutoGenResolver) {
|
|
15855
16047
|
const doc = generateResolverDocument(taxonomy);
|
|
15856
16048
|
const resolverPath = path18.join(config.memoryDir, ".taxonomy", "RESOLVER.md");
|
|
15857
|
-
|
|
16049
|
+
fs19.writeFileSync(resolverPath, doc);
|
|
15858
16050
|
console.error(`Regenerated: ${resolverPath}`);
|
|
15859
16051
|
}
|
|
15860
16052
|
break;
|
|
@@ -16045,12 +16237,12 @@ async function runTrainingExport(args, stdout = process.stdout) {
|
|
|
16045
16237
|
`Unknown training-export format "${args.format}". ${validList}`
|
|
16046
16238
|
);
|
|
16047
16239
|
}
|
|
16048
|
-
if (!
|
|
16240
|
+
if (!fs19.existsSync(args.memoryDir)) {
|
|
16049
16241
|
throw new Error(
|
|
16050
16242
|
`--memory-dir "${args.memoryDir}" does not exist. Provide the path to an existing memory directory.`
|
|
16051
16243
|
);
|
|
16052
16244
|
}
|
|
16053
|
-
if (!
|
|
16245
|
+
if (!fs19.statSync(args.memoryDir).isDirectory()) {
|
|
16054
16246
|
throw new Error(
|
|
16055
16247
|
`--memory-dir "${args.memoryDir}" is not a directory. Provide the path to a memory directory, not a file.`
|
|
16056
16248
|
);
|
|
@@ -16136,10 +16328,10 @@ async function runTrainingExport(args, stdout = process.stdout) {
|
|
|
16136
16328
|
}
|
|
16137
16329
|
const formatted = adapter.formatRecords(records);
|
|
16138
16330
|
const outDir = path18.dirname(args.output);
|
|
16139
|
-
|
|
16331
|
+
fs19.mkdirSync(outDir, { recursive: true });
|
|
16140
16332
|
const tmpPath = `${args.output}.tmp-${process.pid}-${Date.now()}`;
|
|
16141
|
-
|
|
16142
|
-
|
|
16333
|
+
fs19.writeFileSync(tmpPath, formatted, "utf-8");
|
|
16334
|
+
fs19.renameSync(tmpPath, args.output);
|
|
16143
16335
|
stdout.write(
|
|
16144
16336
|
`Exported ${records.length} records to ${args.output} (${adapter.name} format)
|
|
16145
16337
|
`
|
|
@@ -16191,6 +16383,9 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
16191
16383
|
case "who-knows":
|
|
16192
16384
|
await cmdWhoKnows(rest);
|
|
16193
16385
|
break;
|
|
16386
|
+
case "promotion-candidates":
|
|
16387
|
+
await cmdPromotionCandidates(rest);
|
|
16388
|
+
break;
|
|
16194
16389
|
case "security":
|
|
16195
16390
|
await cmdSecurity(rest);
|
|
16196
16391
|
break;
|
|
@@ -16314,7 +16509,7 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
16314
16509
|
}
|
|
16315
16510
|
}, 500);
|
|
16316
16511
|
};
|
|
16317
|
-
|
|
16512
|
+
fs19.watch(memoryDir, { recursive: true }, (_event, filename) => {
|
|
16318
16513
|
if (filename && filename.startsWith(".")) return;
|
|
16319
16514
|
rebuild();
|
|
16320
16515
|
});
|
|
@@ -16322,12 +16517,12 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
16322
16517
|
});
|
|
16323
16518
|
} else if (subAction === "validate") {
|
|
16324
16519
|
const treeDir = outputDir;
|
|
16325
|
-
if (!
|
|
16520
|
+
if (!fs19.existsSync(treeDir)) {
|
|
16326
16521
|
console.error(`Context tree not found at ${treeDir}. Run 'remnic tree generate' first.`);
|
|
16327
16522
|
process.exit(1);
|
|
16328
16523
|
}
|
|
16329
16524
|
const indexPath = path18.join(treeDir, "INDEX.md");
|
|
16330
|
-
if (!
|
|
16525
|
+
if (!fs19.existsSync(indexPath)) {
|
|
16331
16526
|
console.error(`INDEX.md missing in ${treeDir}. Tree may be corrupt \u2014 regenerate.`);
|
|
16332
16527
|
process.exit(1);
|
|
16333
16528
|
}
|
|
@@ -16449,7 +16644,11 @@ Options:
|
|
|
16449
16644
|
break;
|
|
16450
16645
|
}
|
|
16451
16646
|
case "procedural": {
|
|
16452
|
-
await
|
|
16647
|
+
await runProceduralBinaryCommand(rest);
|
|
16648
|
+
break;
|
|
16649
|
+
}
|
|
16650
|
+
case "drift": {
|
|
16651
|
+
await runDriftBinaryCommand(rest);
|
|
16453
16652
|
break;
|
|
16454
16653
|
}
|
|
16455
16654
|
case "extensions": {
|
|
@@ -16509,10 +16708,10 @@ Other:
|
|
|
16509
16708
|
let wearablesService;
|
|
16510
16709
|
try {
|
|
16511
16710
|
const configPath = resolveConfigPath();
|
|
16512
|
-
const raw =
|
|
16513
|
-
const remnicCfg =
|
|
16514
|
-
const config =
|
|
16515
|
-
wearablesOrchestrator = new
|
|
16711
|
+
const raw = fs19.existsSync(configPath) ? JSON.parse(fs19.readFileSync(configPath, "utf8")) : {};
|
|
16712
|
+
const remnicCfg = resolveRemnicConfigRecord9(raw);
|
|
16713
|
+
const config = parseConfig10(remnicCfg);
|
|
16714
|
+
wearablesOrchestrator = new Orchestrator6(config);
|
|
16516
16715
|
await wearablesOrchestrator.initialize();
|
|
16517
16716
|
await wearablesOrchestrator.deferredReady;
|
|
16518
16717
|
wearablesService = wearablesOrchestrator.getWearablesService();
|
|
@@ -16567,10 +16766,10 @@ Other:
|
|
|
16567
16766
|
const targetFactory = async () => {
|
|
16568
16767
|
if (!orchestratorSingleton) {
|
|
16569
16768
|
const configPath = resolveConfigPath();
|
|
16570
|
-
const raw =
|
|
16571
|
-
const remnicCfg =
|
|
16572
|
-
const config =
|
|
16573
|
-
orchestratorSingleton = new
|
|
16769
|
+
const raw = fs19.existsSync(configPath) ? JSON.parse(fs19.readFileSync(configPath, "utf8")) : {};
|
|
16770
|
+
const remnicCfg = resolveRemnicConfigRecord9(raw);
|
|
16771
|
+
const config = parseConfig10(remnicCfg);
|
|
16772
|
+
orchestratorSingleton = new Orchestrator6(config);
|
|
16574
16773
|
await orchestratorSingleton.initialize();
|
|
16575
16774
|
await orchestratorSingleton.deferredReady;
|
|
16576
16775
|
}
|
|
@@ -16821,6 +17020,17 @@ Usage:
|
|
|
16821
17020
|
Print procedural memory stats (counts + recency + config). Mirrors
|
|
16822
17021
|
GET /engram/v1/procedural/stats and remnic.procedural_stats MCP tool
|
|
16823
17022
|
(issue #567).
|
|
17023
|
+
remnic procedural maintain [--apply] [--format json|text] [--memory-dir <path>]
|
|
17024
|
+
Run procedure library-health maintenance (issue #2370): shadow report of
|
|
17025
|
+
merge / repair-flag / retire proposals from outcome telemetry; --apply
|
|
17026
|
+
executes them (requires procedural.maintenance.enabled). Mirrors the
|
|
17027
|
+
remnic.procedure_library_maintenance MCP tool.
|
|
17028
|
+
remnic drift scan [--apply] [--namespace <ns>] [--format json|text] [--memory-dir <path>]
|
|
17029
|
+
Run preference drift detection (issue #2371): classify aging preference
|
|
17030
|
+
memories as corroborated / stale / drifted from recent evidence; --apply
|
|
17031
|
+
stamps lastCorroborated / driftState and opens a review item per drifted
|
|
17032
|
+
preference (requires driftDetection.enabled). Mirrors the
|
|
17033
|
+
remnic.preference_drift_scan MCP tool.
|
|
16824
17034
|
remnic training:export --format <name> --output <path> [options]
|
|
16825
17035
|
Export memories as a fine-tuning dataset (issue #459). Run
|
|
16826
17036
|
'remnic training:export --help' for the full option list.
|