@remnic/cli 9.63.1 → 9.63.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 +482 -291
- package/package.json +31 -31
package/dist/index.js
CHANGED
|
@@ -18,10 +18,11 @@ async function persistEnrichmentCandidate(storage, entityName, candidate) {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
// src/index.ts
|
|
21
|
-
import
|
|
21
|
+
import fs16 from "fs";
|
|
22
22
|
import os3 from "os";
|
|
23
23
|
import path18 from "path";
|
|
24
24
|
import { createHash as createHash4 } from "crypto";
|
|
25
|
+
import { writeFile as fsWriteFile } from "fs/promises";
|
|
25
26
|
import * as childProcess2 from "child_process";
|
|
26
27
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
27
28
|
import { gzipSync } from "zlib";
|
|
@@ -4594,8 +4595,243 @@ async function loadOpenclawManagedUpgradeModule(packageSpec, hooks = {}) {
|
|
|
4594
4595
|
}
|
|
4595
4596
|
}
|
|
4596
4597
|
|
|
4597
|
-
// src/daemon
|
|
4598
|
+
// src/remote-daemon.ts
|
|
4598
4599
|
import fs12 from "fs";
|
|
4600
|
+
function readCompatEnv(primary, legacy) {
|
|
4601
|
+
return process.env[primary] ?? process.env[legacy];
|
|
4602
|
+
}
|
|
4603
|
+
function readRemnicConfigRecord(configPath) {
|
|
4604
|
+
try {
|
|
4605
|
+
const parsed = JSON.parse(fs12.readFileSync(configPath, "utf8"));
|
|
4606
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
4607
|
+
return parsed;
|
|
4608
|
+
}
|
|
4609
|
+
return void 0;
|
|
4610
|
+
} catch {
|
|
4611
|
+
return void 0;
|
|
4612
|
+
}
|
|
4613
|
+
}
|
|
4614
|
+
function normalizeRemoteDaemonUrl(raw, source) {
|
|
4615
|
+
let parsed;
|
|
4616
|
+
try {
|
|
4617
|
+
parsed = new URL(raw.trim());
|
|
4618
|
+
} catch {
|
|
4619
|
+
throw new Error(`Invalid ${source} "${raw}": expected an http:// or https:// URL.`);
|
|
4620
|
+
}
|
|
4621
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
4622
|
+
throw new Error(`Invalid ${source} "${raw}": scheme must be http:// or https://.`);
|
|
4623
|
+
}
|
|
4624
|
+
return `${parsed.origin}${parsed.pathname.replace(/\/+$/, "")}`;
|
|
4625
|
+
}
|
|
4626
|
+
function resolveRemoteDaemonUrl(configPath) {
|
|
4627
|
+
const envUrl = readCompatEnv("REMNIC_DAEMON_URL", "ENGRAM_DAEMON_URL");
|
|
4628
|
+
if (typeof envUrl === "string" && envUrl.trim().length > 0) {
|
|
4629
|
+
return normalizeRemoteDaemonUrl(envUrl, "REMNIC_DAEMON_URL/ENGRAM_DAEMON_URL");
|
|
4630
|
+
}
|
|
4631
|
+
const raw = readRemnicConfigRecord(configPath);
|
|
4632
|
+
if (raw && "server" in raw) {
|
|
4633
|
+
const server = raw.server;
|
|
4634
|
+
if (server && typeof server === "object") {
|
|
4635
|
+
const candidate = server.url;
|
|
4636
|
+
if (typeof candidate === "string" && candidate.trim().length > 0) {
|
|
4637
|
+
return normalizeRemoteDaemonUrl(candidate, "server.url");
|
|
4638
|
+
}
|
|
4639
|
+
}
|
|
4640
|
+
}
|
|
4641
|
+
return void 0;
|
|
4642
|
+
}
|
|
4643
|
+
function resolveDaemonBaseUrl(configPath) {
|
|
4644
|
+
const remoteUrl = resolveRemoteDaemonUrl(configPath);
|
|
4645
|
+
if (remoteUrl) return remoteUrl;
|
|
4646
|
+
let port = 4318;
|
|
4647
|
+
let host = "127.0.0.1";
|
|
4648
|
+
const raw = readRemnicConfigRecord(configPath);
|
|
4649
|
+
if (raw && "server" in raw) {
|
|
4650
|
+
const server = raw.server;
|
|
4651
|
+
if (server && typeof server === "object") {
|
|
4652
|
+
const hostCandidate = server.host;
|
|
4653
|
+
if (typeof hostCandidate === "string" && hostCandidate.length > 0) {
|
|
4654
|
+
host = hostCandidate;
|
|
4655
|
+
}
|
|
4656
|
+
const portCandidate = server.port;
|
|
4657
|
+
if (typeof portCandidate === "number" && Number.isInteger(portCandidate)) {
|
|
4658
|
+
port = portCandidate;
|
|
4659
|
+
}
|
|
4660
|
+
}
|
|
4661
|
+
}
|
|
4662
|
+
const envHost = readCompatEnv("REMNIC_HOST", "ENGRAM_HOST");
|
|
4663
|
+
if (typeof envHost === "string" && envHost.length > 0) {
|
|
4664
|
+
host = envHost;
|
|
4665
|
+
}
|
|
4666
|
+
const envPortRaw = readCompatEnv("REMNIC_PORT", "ENGRAM_PORT");
|
|
4667
|
+
if (typeof envPortRaw === "string" && envPortRaw.length > 0) {
|
|
4668
|
+
const envPort = Number(envPortRaw);
|
|
4669
|
+
if (!Number.isInteger(envPort) || envPort < 1 || envPort > 65535) {
|
|
4670
|
+
throw new Error(
|
|
4671
|
+
`Invalid REMNIC_PORT/ENGRAM_PORT "${envPortRaw}": expected an integer in [1, 65535].`
|
|
4672
|
+
);
|
|
4673
|
+
}
|
|
4674
|
+
port = envPort;
|
|
4675
|
+
}
|
|
4676
|
+
return `http://${host}:${port}`;
|
|
4677
|
+
}
|
|
4678
|
+
function resolveOperatorToken(configPath) {
|
|
4679
|
+
const envToken = readCompatEnv("REMNIC_AUTH_TOKEN", "ENGRAM_AUTH_TOKEN");
|
|
4680
|
+
if (typeof envToken === "string" && envToken.length > 0) return envToken;
|
|
4681
|
+
const raw = readRemnicConfigRecord(configPath);
|
|
4682
|
+
if (raw && "server" in raw) {
|
|
4683
|
+
const server = raw.server;
|
|
4684
|
+
if (server && typeof server === "object" && "authToken" in server) {
|
|
4685
|
+
const candidate = server.authToken;
|
|
4686
|
+
if (typeof candidate === "string" && candidate.length > 0 && !candidate.includes("${")) {
|
|
4687
|
+
return candidate;
|
|
4688
|
+
}
|
|
4689
|
+
}
|
|
4690
|
+
}
|
|
4691
|
+
return void 0;
|
|
4692
|
+
}
|
|
4693
|
+
function resolveRemoteDaemon(configPath) {
|
|
4694
|
+
const baseUrl = resolveRemoteDaemonUrl(configPath);
|
|
4695
|
+
if (!baseUrl) return void 0;
|
|
4696
|
+
const token = resolveOperatorToken(configPath);
|
|
4697
|
+
return token ? { baseUrl, token } : { baseUrl };
|
|
4698
|
+
}
|
|
4699
|
+
function isTransportError(err) {
|
|
4700
|
+
return err instanceof Error && (err.message.includes("ECONNREFUSED") || err.message.includes("ECONNRESET") || err.message.includes("fetch failed") || err.message.includes("aborted") || err.message.includes("ENOTFOUND"));
|
|
4701
|
+
}
|
|
4702
|
+
function unreachableError(baseUrl) {
|
|
4703
|
+
return new Error(
|
|
4704
|
+
`cannot reach remnic-server at ${baseUrl} \u2014 check REMNIC_DAEMON_URL / server.url and the remote server's availability.`
|
|
4705
|
+
);
|
|
4706
|
+
}
|
|
4707
|
+
async function daemonFetch(baseUrl, relativePath, token, timeoutMs, init) {
|
|
4708
|
+
const url = new URL(relativePath, `${baseUrl}/`);
|
|
4709
|
+
if (baseUrl.startsWith("https:") && url.protocol !== "https:") {
|
|
4710
|
+
throw new Error(
|
|
4711
|
+
`refusing to downgrade https daemon URL ${baseUrl} to ${url.protocol}// \u2014 fix REMNIC_DAEMON_URL / server.url.`
|
|
4712
|
+
);
|
|
4713
|
+
}
|
|
4714
|
+
const controller = new AbortController();
|
|
4715
|
+
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
4716
|
+
try {
|
|
4717
|
+
const headers = { accept: "application/json" };
|
|
4718
|
+
if (token) headers.authorization = `Bearer ${token}`;
|
|
4719
|
+
return await fetch(url, {
|
|
4720
|
+
...init,
|
|
4721
|
+
headers: { ...headers, ...init?.headers },
|
|
4722
|
+
signal: controller.signal
|
|
4723
|
+
});
|
|
4724
|
+
} finally {
|
|
4725
|
+
clearTimeout(timeoutId);
|
|
4726
|
+
}
|
|
4727
|
+
}
|
|
4728
|
+
async function probeDaemonHealth(baseUrl, token, timeoutMs = 3e3) {
|
|
4729
|
+
try {
|
|
4730
|
+
const response = await daemonFetch(baseUrl, "engram/v1/health", token, timeoutMs);
|
|
4731
|
+
return response.ok ? { ok: true, status: response.status } : { ok: false, status: response.status };
|
|
4732
|
+
} catch (err) {
|
|
4733
|
+
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
4734
|
+
}
|
|
4735
|
+
}
|
|
4736
|
+
async function printHealthCheck(baseUrl, token, timeoutMs = 3e3) {
|
|
4737
|
+
try {
|
|
4738
|
+
const response = await daemonFetch(baseUrl, "engram/v1/health", token, timeoutMs);
|
|
4739
|
+
if (!response.ok) {
|
|
4740
|
+
const hint = response.status === 401 && !token ? " (daemon requires auth and no token was found \u2014 set REMNIC_AUTH_TOKEN or configure server.authToken)" : response.status === 401 ? " (token rejected by the daemon)" : "";
|
|
4741
|
+
console.log(`Health: server responded with ${response.status} ${response.statusText}${hint}`);
|
|
4742
|
+
return;
|
|
4743
|
+
}
|
|
4744
|
+
const health = await response.json();
|
|
4745
|
+
const status = typeof health.status === "string" ? health.status : "ok";
|
|
4746
|
+
console.log(`Health: ${status}`);
|
|
4747
|
+
const qmd = health.qmd;
|
|
4748
|
+
if (qmd?.pendingEmbeddings != null) {
|
|
4749
|
+
console.log(` Pending embeddings: ${qmd.pendingEmbeddings}`);
|
|
4750
|
+
if (qmd.oldestPendingAgeMs != null) {
|
|
4751
|
+
console.log(` Oldest pending: ${Math.round(qmd.oldestPendingAgeMs / 6e4)}m`);
|
|
4752
|
+
}
|
|
4753
|
+
if (qmd.embeddingBacklogThreshold != null) {
|
|
4754
|
+
console.log(` Backlog threshold: ${qmd.embeddingBacklogThreshold}`);
|
|
4755
|
+
}
|
|
4756
|
+
}
|
|
4757
|
+
if (qmd?.degradedReason) {
|
|
4758
|
+
console.log(` Degraded: ${qmd.degradedReason}`);
|
|
4759
|
+
}
|
|
4760
|
+
} catch {
|
|
4761
|
+
console.log("Health: unable to reach server");
|
|
4762
|
+
}
|
|
4763
|
+
}
|
|
4764
|
+
async function remoteRecall(daemon, request) {
|
|
4765
|
+
let response;
|
|
4766
|
+
try {
|
|
4767
|
+
response = await daemonFetch(daemon.baseUrl, "engram/v1/recall", daemon.token, 1e4, {
|
|
4768
|
+
method: "POST",
|
|
4769
|
+
headers: { "content-type": "application/json" },
|
|
4770
|
+
body: JSON.stringify(request)
|
|
4771
|
+
});
|
|
4772
|
+
} catch (err) {
|
|
4773
|
+
if (isTransportError(err)) throw unreachableError(daemon.baseUrl);
|
|
4774
|
+
throw err;
|
|
4775
|
+
}
|
|
4776
|
+
if (response.status === 401) {
|
|
4777
|
+
throw new Error(
|
|
4778
|
+
`token rejected by remnic-server at ${daemon.baseUrl} (HTTP 401). Update server.authToken or REMNIC_AUTH_TOKEN to match the remote daemon.`
|
|
4779
|
+
);
|
|
4780
|
+
}
|
|
4781
|
+
if (!response.ok) {
|
|
4782
|
+
throw new Error(`remnic-server returned HTTP ${response.status} ${response.statusText}`);
|
|
4783
|
+
}
|
|
4784
|
+
try {
|
|
4785
|
+
return await response.json();
|
|
4786
|
+
} catch {
|
|
4787
|
+
throw new Error("remnic-server returned a non-JSON response");
|
|
4788
|
+
}
|
|
4789
|
+
}
|
|
4790
|
+
async function remoteRecallXray(daemon, request) {
|
|
4791
|
+
const params = new URLSearchParams({ q: request.query });
|
|
4792
|
+
if (request.namespace && request.namespace.length > 0) {
|
|
4793
|
+
params.set("namespace", request.namespace);
|
|
4794
|
+
}
|
|
4795
|
+
if (request.budget !== void 0) {
|
|
4796
|
+
params.set("budget", String(request.budget));
|
|
4797
|
+
}
|
|
4798
|
+
let response;
|
|
4799
|
+
try {
|
|
4800
|
+
response = await daemonFetch(
|
|
4801
|
+
daemon.baseUrl,
|
|
4802
|
+
`engram/v1/recall/xray?${params.toString()}`,
|
|
4803
|
+
daemon.token,
|
|
4804
|
+
1e4
|
|
4805
|
+
);
|
|
4806
|
+
} catch (err) {
|
|
4807
|
+
if (isTransportError(err)) throw unreachableError(daemon.baseUrl);
|
|
4808
|
+
throw err;
|
|
4809
|
+
}
|
|
4810
|
+
if (response.status === 401) {
|
|
4811
|
+
throw new Error(
|
|
4812
|
+
`token rejected by remnic-server at ${daemon.baseUrl} (HTTP 401). Update server.authToken or REMNIC_AUTH_TOKEN to match the remote daemon.`
|
|
4813
|
+
);
|
|
4814
|
+
}
|
|
4815
|
+
if (!response.ok) {
|
|
4816
|
+
throw new Error(`remnic-server returned HTTP ${response.status} ${response.statusText}`);
|
|
4817
|
+
}
|
|
4818
|
+
let payload;
|
|
4819
|
+
try {
|
|
4820
|
+
payload = await response.json();
|
|
4821
|
+
} catch {
|
|
4822
|
+
throw new Error("remnic-server returned a non-JSON response");
|
|
4823
|
+
}
|
|
4824
|
+
if (payload && typeof payload === "object" && !Array.isArray(payload)) {
|
|
4825
|
+
const record2 = payload;
|
|
4826
|
+
if (record2.snapshotFound === true && record2.snapshot && typeof record2.snapshot === "object") {
|
|
4827
|
+
return { snapshotFound: true, snapshot: record2.snapshot };
|
|
4828
|
+
}
|
|
4829
|
+
}
|
|
4830
|
+
return { snapshotFound: false };
|
|
4831
|
+
}
|
|
4832
|
+
|
|
4833
|
+
// src/daemon-service.ts
|
|
4834
|
+
import fs13 from "fs";
|
|
4599
4835
|
import path12 from "path";
|
|
4600
4836
|
import * as childProcess from "child_process";
|
|
4601
4837
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
@@ -4607,7 +4843,7 @@ function launchdUnloadPlist(plistPath, processApi = childProcess) {
|
|
|
4607
4843
|
processApi.execFileSync("launchctl", ["unload", plistPath], { stdio: "pipe" });
|
|
4608
4844
|
}
|
|
4609
4845
|
function resolveServerBinDetails(options = {}) {
|
|
4610
|
-
const existsSync4 = options.existsSync ??
|
|
4846
|
+
const existsSync4 = options.existsSync ?? fs13.existsSync;
|
|
4611
4847
|
const findCommandOnPath2 = options.findCommandOnPath ?? findCommandOnPath;
|
|
4612
4848
|
const moduleDir = options.moduleDir ?? thisModuleDir;
|
|
4613
4849
|
const packageResolve = options.packageResolve ?? resolveImportSpecifier;
|
|
@@ -4666,8 +4902,8 @@ function resolveServerBin(options = {}) {
|
|
|
4666
4902
|
return resolveServerBinDetails(options).path;
|
|
4667
4903
|
}
|
|
4668
4904
|
function readVerifiedDaemonPid(options) {
|
|
4669
|
-
const readFileSync4 = options.readFileSync ??
|
|
4670
|
-
const unlinkSync = options.unlinkSync ??
|
|
4905
|
+
const readFileSync4 = options.readFileSync ?? fs13.readFileSync;
|
|
4906
|
+
const unlinkSync = options.unlinkSync ?? fs13.unlinkSync;
|
|
4671
4907
|
const processKill = options.processKill ?? process.kill;
|
|
4672
4908
|
const platform = options.platform ?? process.platform;
|
|
4673
4909
|
const execFileSync4 = options.execFileSync ?? ((command, args, execOptions) => childProcess.execFileSync(command, args, execOptions));
|
|
@@ -4767,8 +5003,8 @@ function removePidFileBestEffort(file, unlinkSync) {
|
|
|
4767
5003
|
}
|
|
4768
5004
|
}
|
|
4769
5005
|
function inspectLaunchdPlist(plistPath, options = {}) {
|
|
4770
|
-
const existsSync4 = options.existsSync ??
|
|
4771
|
-
const readFileSync4 = options.readFileSync ??
|
|
5006
|
+
const existsSync4 = options.existsSync ?? fs13.existsSync;
|
|
5007
|
+
const readFileSync4 = options.readFileSync ?? fs13.readFileSync;
|
|
4772
5008
|
if (!existsSync4(plistPath)) {
|
|
4773
5009
|
return {
|
|
4774
5010
|
installed: false,
|
|
@@ -5002,7 +5238,7 @@ function stripConfigArgv(args) {
|
|
|
5002
5238
|
}
|
|
5003
5239
|
|
|
5004
5240
|
// src/import-dispatch.ts
|
|
5005
|
-
import
|
|
5241
|
+
import fs14 from "fs";
|
|
5006
5242
|
import {
|
|
5007
5243
|
runImporter,
|
|
5008
5244
|
validateImportBatchSize,
|
|
@@ -5516,7 +5752,7 @@ async function cmdImport(rest, targetFactory, disposeTarget, ioOverrides = {}) {
|
|
|
5516
5752
|
let materializedTarget;
|
|
5517
5753
|
let materializePromise;
|
|
5518
5754
|
const io = {
|
|
5519
|
-
readFile: ioOverrides.readFile ?? (async (p) =>
|
|
5755
|
+
readFile: ioOverrides.readFile ?? (async (p) => fs14.promises.readFile(p, "utf-8")),
|
|
5520
5756
|
loadAdapter: ioOverrides.loadAdapter ?? (async (name) => (await loadImporterModule(name)).adapter),
|
|
5521
5757
|
runImporter: ioOverrides.runImporter ?? runImporter,
|
|
5522
5758
|
getWriteTarget: async () => {
|
|
@@ -5629,7 +5865,7 @@ async function cmdCapture(rest, io) {
|
|
|
5629
5865
|
}
|
|
5630
5866
|
|
|
5631
5867
|
// src/import-lossless-claw-cmd.ts
|
|
5632
|
-
import
|
|
5868
|
+
import fs15 from "fs";
|
|
5633
5869
|
import path14 from "path";
|
|
5634
5870
|
import {
|
|
5635
5871
|
applyLcmSchema,
|
|
@@ -5741,15 +5977,15 @@ async function loadImportLosslessClawModule() {
|
|
|
5741
5977
|
|
|
5742
5978
|
// src/import-lossless-claw-cmd.ts
|
|
5743
5979
|
function assertDirectoryOrAbsent(p, label) {
|
|
5744
|
-
if (
|
|
5980
|
+
if (fs15.existsSync(p) && !fs15.statSync(p).isDirectory()) {
|
|
5745
5981
|
throw new Error(`${label} is not a directory: ${p}`);
|
|
5746
5982
|
}
|
|
5747
5983
|
}
|
|
5748
5984
|
function assertFile(p, label) {
|
|
5749
|
-
if (!
|
|
5985
|
+
if (!fs15.existsSync(p)) {
|
|
5750
5986
|
throw new Error(`${label} does not exist: ${p}`);
|
|
5751
5987
|
}
|
|
5752
|
-
if (!
|
|
5988
|
+
if (!fs15.statSync(p).isFile()) {
|
|
5753
5989
|
throw new Error(`${label} is not a file: ${p}`);
|
|
5754
5990
|
}
|
|
5755
5991
|
}
|
|
@@ -5781,7 +6017,7 @@ async function cmdImportLosslessClaw(argv, io, deps = {}) {
|
|
|
5781
6017
|
try {
|
|
5782
6018
|
if (parsed.dryRun) {
|
|
5783
6019
|
const lcmPath = path14.join(memoryDir, "state", "lcm.sqlite");
|
|
5784
|
-
if (
|
|
6020
|
+
if (fs15.existsSync(lcmPath)) {
|
|
5785
6021
|
destDb = mod.openExistingLcmDatabaseReadOnly(lcmPath);
|
|
5786
6022
|
} else {
|
|
5787
6023
|
destDb = mod.openInMemoryDestinationDatabase();
|
|
@@ -6959,9 +7195,6 @@ registerPublisher("claude-code", () => new ClaudeCodeMemoryExtensionPublisher())
|
|
|
6959
7195
|
registerPublisher("hermes", () => new HermesMemoryExtensionPublisher());
|
|
6960
7196
|
registerPublisher("pi", () => new LazyPluginPiPublisher("pi", (mod) => mod.PiMemoryExtensionPublisher));
|
|
6961
7197
|
registerPublisher("omp", () => new LazyPluginPiPublisher("omp", (mod) => mod.OmpMemoryExtensionPublisher));
|
|
6962
|
-
function readCompatEnv(primary, legacy) {
|
|
6963
|
-
return process.env[primary] ?? process.env[legacy];
|
|
6964
|
-
}
|
|
6965
7198
|
var PID_DIR = path18.join(resolveHomeDir(), ".remnic");
|
|
6966
7199
|
var LEGACY_PID_DIR = path18.join(resolveHomeDir(), ".engram");
|
|
6967
7200
|
var PID_FILE = path18.join(PID_DIR, "server.pid");
|
|
@@ -7135,7 +7368,7 @@ async function resolveAllBenchmarks() {
|
|
|
7135
7368
|
if (packageBenchmarks) {
|
|
7136
7369
|
return packageBenchmarks.filter((entry) => entry.runnerAvailable).map((entry) => entry.id);
|
|
7137
7370
|
}
|
|
7138
|
-
if (!
|
|
7371
|
+
if (!fs16.existsSync(EVAL_RUNNER_PATH)) {
|
|
7139
7372
|
return [];
|
|
7140
7373
|
}
|
|
7141
7374
|
return BENCHMARK_CATALOG.filter((entry) => entry.category !== "ingestion").map((entry) => entry.id);
|
|
@@ -7183,7 +7416,7 @@ async function runBenchViaFallback(parsed, benchmarkId, runtimeProfile) {
|
|
|
7183
7416
|
`Fallback benchmark runner does not support provider-backed, gateway, or thinking/timeout flags (${unsupportedOptions.join(", ")}). Build/install @remnic/bench to use those options.`
|
|
7184
7417
|
);
|
|
7185
7418
|
}
|
|
7186
|
-
if (!
|
|
7419
|
+
if (!fs16.existsSync(EVAL_RUNNER_PATH)) {
|
|
7187
7420
|
console.error(
|
|
7188
7421
|
"Benchmark runner not found. Expected eval runner at evals/run.ts or a phase-1 @remnic/bench runtime export."
|
|
7189
7422
|
);
|
|
@@ -7193,7 +7426,7 @@ async function runBenchViaFallback(parsed, benchmarkId, runtimeProfile) {
|
|
|
7193
7426
|
path18.join(CLI_REPO_ROOT, "node_modules", ".bin", "tsx"),
|
|
7194
7427
|
path18.join(CLI_REPO_ROOT, "packages", "remnic-cli", "node_modules", ".bin", "tsx")
|
|
7195
7428
|
];
|
|
7196
|
-
const tsxCmd = tsxCandidates.find((candidate) =>
|
|
7429
|
+
const tsxCmd = tsxCandidates.find((candidate) => fs16.existsSync(candidate)) ?? "tsx";
|
|
7197
7430
|
const fallbackOutputDir = createFallbackBenchOutputDir(
|
|
7198
7431
|
parsed.resultsDir ?? resolveBenchOutputDir(),
|
|
7199
7432
|
benchmarkId,
|
|
@@ -7338,9 +7571,9 @@ var PERSONAMEM_COMPLETION_MARKER = path18.join(
|
|
|
7338
7571
|
);
|
|
7339
7572
|
function resolveRealpathWithinDataset(datasetPath, relativePath) {
|
|
7340
7573
|
try {
|
|
7341
|
-
const datasetRoot =
|
|
7574
|
+
const datasetRoot = fs16.realpathSync(datasetPath);
|
|
7342
7575
|
const candidatePath = path18.resolve(datasetRoot, relativePath);
|
|
7343
|
-
const candidateRealPath =
|
|
7576
|
+
const candidateRealPath = fs16.realpathSync(candidatePath);
|
|
7344
7577
|
const relativeToRoot = path18.relative(datasetRoot, candidateRealPath);
|
|
7345
7578
|
if (relativeToRoot.startsWith("..") || path18.isAbsolute(relativeToRoot)) {
|
|
7346
7579
|
return null;
|
|
@@ -7399,14 +7632,14 @@ function parseCsvRows(raw) {
|
|
|
7399
7632
|
function isPersonaMemDatasetComplete(datasetPath) {
|
|
7400
7633
|
try {
|
|
7401
7634
|
const completionMarkerPath = path18.join(datasetPath, PERSONAMEM_COMPLETION_MARKER);
|
|
7402
|
-
if (
|
|
7635
|
+
if (fs16.statSync(completionMarkerPath).isFile()) {
|
|
7403
7636
|
return true;
|
|
7404
7637
|
}
|
|
7405
7638
|
} catch {
|
|
7406
7639
|
}
|
|
7407
7640
|
const datasetFile = PERSONAMEM_DATASET_FILE_CANDIDATES.find((candidate) => {
|
|
7408
7641
|
try {
|
|
7409
|
-
return
|
|
7642
|
+
return fs16.statSync(path18.join(datasetPath, candidate)).isFile();
|
|
7410
7643
|
} catch {
|
|
7411
7644
|
return false;
|
|
7412
7645
|
}
|
|
@@ -7415,7 +7648,7 @@ function isPersonaMemDatasetComplete(datasetPath) {
|
|
|
7415
7648
|
return false;
|
|
7416
7649
|
}
|
|
7417
7650
|
try {
|
|
7418
|
-
const rows = parseCsvRows(
|
|
7651
|
+
const rows = parseCsvRows(fs16.readFileSync(path18.join(datasetPath, datasetFile), "utf8"));
|
|
7419
7652
|
if (rows.length < 2) {
|
|
7420
7653
|
return false;
|
|
7421
7654
|
}
|
|
@@ -7430,7 +7663,7 @@ function isPersonaMemDatasetComplete(datasetPath) {
|
|
|
7430
7663
|
}
|
|
7431
7664
|
return historyPaths.every((relativePath) => {
|
|
7432
7665
|
const resolvedPath = resolveRealpathWithinDataset(datasetPath, relativePath);
|
|
7433
|
-
return resolvedPath !== null &&
|
|
7666
|
+
return resolvedPath !== null && fs16.statSync(resolvedPath).isFile();
|
|
7434
7667
|
});
|
|
7435
7668
|
} catch {
|
|
7436
7669
|
return false;
|
|
@@ -7438,7 +7671,7 @@ function isPersonaMemDatasetComplete(datasetPath) {
|
|
|
7438
7671
|
}
|
|
7439
7672
|
function hasDatasetFile(datasetPath, relativePath) {
|
|
7440
7673
|
try {
|
|
7441
|
-
return
|
|
7674
|
+
return fs16.statSync(path18.join(datasetPath, relativePath)).isFile();
|
|
7442
7675
|
} catch {
|
|
7443
7676
|
return false;
|
|
7444
7677
|
}
|
|
@@ -7458,10 +7691,10 @@ function memoryAgentBenchDatasetHasRecSysSamples(datasetPath) {
|
|
|
7458
7691
|
return candidateFilenames.some((filename) => {
|
|
7459
7692
|
const filePath = path18.join(datasetPath, filename);
|
|
7460
7693
|
try {
|
|
7461
|
-
if (!
|
|
7694
|
+
if (!fs16.statSync(filePath).isFile()) {
|
|
7462
7695
|
return false;
|
|
7463
7696
|
}
|
|
7464
|
-
const raw =
|
|
7697
|
+
const raw = fs16.readFileSync(filePath, "utf8");
|
|
7465
7698
|
return /"source"\s*:\s*"recsys[_-]/i.test(raw);
|
|
7466
7699
|
} catch {
|
|
7467
7700
|
return false;
|
|
@@ -7477,7 +7710,7 @@ function isMemoryAgentBenchDatasetComplete(datasetPath) {
|
|
|
7477
7710
|
function isDatasetDownloaded(datasetPath, benchmarkId) {
|
|
7478
7711
|
let stats;
|
|
7479
7712
|
try {
|
|
7480
|
-
stats =
|
|
7713
|
+
stats = fs16.statSync(datasetPath);
|
|
7481
7714
|
} catch {
|
|
7482
7715
|
return false;
|
|
7483
7716
|
}
|
|
@@ -7487,7 +7720,7 @@ function isDatasetDownloaded(datasetPath, benchmarkId) {
|
|
|
7487
7720
|
const marker = DOWNLOADED_DATASET_MARKERS[benchmarkId];
|
|
7488
7721
|
if (!marker) {
|
|
7489
7722
|
try {
|
|
7490
|
-
return
|
|
7723
|
+
return fs16.readdirSync(datasetPath).length > 0;
|
|
7491
7724
|
} catch {
|
|
7492
7725
|
return false;
|
|
7493
7726
|
}
|
|
@@ -7495,7 +7728,7 @@ function isDatasetDownloaded(datasetPath, benchmarkId) {
|
|
|
7495
7728
|
if (marker.allOf) {
|
|
7496
7729
|
const hasAllRequiredFiles = marker.allOf.every((name) => {
|
|
7497
7730
|
try {
|
|
7498
|
-
return
|
|
7731
|
+
return fs16.statSync(path18.join(datasetPath, name)).isFile();
|
|
7499
7732
|
} catch {
|
|
7500
7733
|
return false;
|
|
7501
7734
|
}
|
|
@@ -7507,7 +7740,7 @@ function isDatasetDownloaded(datasetPath, benchmarkId) {
|
|
|
7507
7740
|
if (marker.anyOf) {
|
|
7508
7741
|
const hasMarkerFile = marker.anyOf.some((name) => {
|
|
7509
7742
|
try {
|
|
7510
|
-
return
|
|
7743
|
+
return fs16.statSync(path18.join(datasetPath, name)).isFile();
|
|
7511
7744
|
} catch {
|
|
7512
7745
|
return false;
|
|
7513
7746
|
}
|
|
@@ -7525,7 +7758,7 @@ function isDatasetDownloaded(datasetPath, benchmarkId) {
|
|
|
7525
7758
|
}
|
|
7526
7759
|
if (marker.ext) {
|
|
7527
7760
|
try {
|
|
7528
|
-
return
|
|
7761
|
+
return fs16.readdirSync(datasetPath).some(
|
|
7529
7762
|
(name) => name.endsWith(marker.ext) && !marker.exclude?.includes(name)
|
|
7530
7763
|
);
|
|
7531
7764
|
} catch {
|
|
@@ -7537,7 +7770,7 @@ function isDatasetDownloaded(datasetPath, benchmarkId) {
|
|
|
7537
7770
|
async function launchBenchUi(resultsDir) {
|
|
7538
7771
|
const benchUiDir = path18.join(CLI_REPO_ROOT, "packages", "bench-ui");
|
|
7539
7772
|
const pnpmCmd = process.platform === "win32" ? "pnpm.cmd" : "pnpm";
|
|
7540
|
-
if (!
|
|
7773
|
+
if (!fs16.existsSync(path18.join(benchUiDir, "package.json"))) {
|
|
7541
7774
|
console.error("ERROR: @remnic/bench-ui is not available in this checkout.");
|
|
7542
7775
|
process.exit(1);
|
|
7543
7776
|
}
|
|
@@ -7575,13 +7808,13 @@ function listDownloadableBenchmarks() {
|
|
|
7575
7808
|
}
|
|
7576
7809
|
function resolveDatasetDownloadScriptPath() {
|
|
7577
7810
|
const bundled = path18.join(CLI_MODULE_DIR, "assets", "download-datasets.sh");
|
|
7578
|
-
if (
|
|
7811
|
+
if (fs16.existsSync(bundled)) {
|
|
7579
7812
|
return bundled;
|
|
7580
7813
|
}
|
|
7581
7814
|
return path18.join(CLI_REPO_ROOT, "evals", "scripts", "download-datasets.sh");
|
|
7582
7815
|
}
|
|
7583
7816
|
function isRepoCheckout() {
|
|
7584
|
-
return
|
|
7817
|
+
return fs16.existsSync(path18.join(CLI_REPO_ROOT, "pnpm-workspace.yaml")) && fs16.existsSync(path18.join(CLI_REPO_ROOT, "evals", "scripts", "download-datasets.sh"));
|
|
7585
7818
|
}
|
|
7586
7819
|
function runDatasetDownloadScript(scriptPath, benchmarkId, datasetRoot, jsonMode) {
|
|
7587
7820
|
const stdio = jsonMode ? ["inherit", process.stderr, "inherit"] : "inherit";
|
|
@@ -7894,8 +8127,8 @@ async function exportBenchPackageResult(parsed) {
|
|
|
7894
8127
|
...reportCardProvenance ? { reportCardProvenance } : {}
|
|
7895
8128
|
});
|
|
7896
8129
|
if (parsed.output) {
|
|
7897
|
-
|
|
7898
|
-
|
|
8130
|
+
fs16.mkdirSync(path18.dirname(parsed.output), { recursive: true });
|
|
8131
|
+
fs16.writeFileSync(parsed.output, rendered);
|
|
7899
8132
|
console.log(`Exported ${summary.id} as ${parsed.format} to ${parsed.output}`);
|
|
7900
8133
|
return;
|
|
7901
8134
|
}
|
|
@@ -7940,7 +8173,7 @@ async function manageBenchDatasets(parsed) {
|
|
|
7940
8173
|
process.exit(1);
|
|
7941
8174
|
}
|
|
7942
8175
|
const scriptPath = resolveDatasetDownloadScriptPath();
|
|
7943
|
-
if (!
|
|
8176
|
+
if (!fs16.existsSync(scriptPath)) {
|
|
7944
8177
|
console.error(`ERROR: dataset download script not found: ${scriptPath}`);
|
|
7945
8178
|
process.exit(1);
|
|
7946
8179
|
}
|
|
@@ -8140,7 +8373,7 @@ async function calibrateBenchJudges(parsed, rawArgs) {
|
|
|
8140
8373
|
);
|
|
8141
8374
|
process.exit(1);
|
|
8142
8375
|
}
|
|
8143
|
-
const sourceResultSha256 = createHash4("sha256").update(
|
|
8376
|
+
const sourceResultSha256 = createHash4("sha256").update(fs16.readFileSync(latest.path)).digest("hex");
|
|
8144
8377
|
const expandedManifestPath = expandTilde(manifestPath);
|
|
8145
8378
|
if (!bench.resolveLocalLabJudgeProviderConfig) {
|
|
8146
8379
|
console.error(
|
|
@@ -8555,7 +8788,7 @@ function loadPinnedLoCoMoTaskSelector(parsed) {
|
|
|
8555
8788
|
}
|
|
8556
8789
|
let decoded;
|
|
8557
8790
|
try {
|
|
8558
|
-
decoded = JSON.parse(
|
|
8791
|
+
decoded = JSON.parse(fs16.readFileSync(parsed.taskIdsFile, "utf8"));
|
|
8559
8792
|
} catch (error) {
|
|
8560
8793
|
throw new Error(
|
|
8561
8794
|
`Unable to read --task-ids-file ${parsed.taskIdsFile}: ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -9230,7 +9463,7 @@ function resolveBenchReproDatasetDir(datasetDir) {
|
|
|
9230
9463
|
return void 0;
|
|
9231
9464
|
}
|
|
9232
9465
|
try {
|
|
9233
|
-
return
|
|
9466
|
+
return fs16.realpathSync(datasetDir);
|
|
9234
9467
|
} catch {
|
|
9235
9468
|
return datasetDir;
|
|
9236
9469
|
}
|
|
@@ -9284,7 +9517,7 @@ async function writeBenchReproManifestForPackageRun(args) {
|
|
|
9284
9517
|
}
|
|
9285
9518
|
function loadStandaloneConvergeCommandConfig() {
|
|
9286
9519
|
const configPath = resolveConfigPath();
|
|
9287
|
-
const raw =
|
|
9520
|
+
const raw = fs16.existsSync(configPath) ? JSON.parse(fs16.readFileSync(configPath, "utf8")) : {};
|
|
9288
9521
|
return parseConfig7(resolveRemnicConfigRecord6(raw));
|
|
9289
9522
|
}
|
|
9290
9523
|
function parseConvergePluginConfig(value) {
|
|
@@ -9313,13 +9546,13 @@ function resolveConfigPath(cliPath) {
|
|
|
9313
9546
|
path18.join(resolveHomeDir(), ".config", "engram", "config.json")
|
|
9314
9547
|
];
|
|
9315
9548
|
for (const candidate of candidates) {
|
|
9316
|
-
if (
|
|
9549
|
+
if (fs16.existsSync(candidate)) return candidate;
|
|
9317
9550
|
}
|
|
9318
9551
|
return path18.join(resolveHomeDir(), ".config", "remnic", "config.json");
|
|
9319
9552
|
}
|
|
9320
9553
|
function resolveExistingBenchRemnicConfigPath(cliPath) {
|
|
9321
9554
|
const configPath = resolveConfigPath(cliPath);
|
|
9322
|
-
if (
|
|
9555
|
+
if (fs16.existsSync(configPath)) {
|
|
9323
9556
|
return configPath;
|
|
9324
9557
|
}
|
|
9325
9558
|
if (cliPath) {
|
|
@@ -9329,7 +9562,7 @@ function resolveExistingBenchRemnicConfigPath(cliPath) {
|
|
|
9329
9562
|
}
|
|
9330
9563
|
function resolveExistingBenchOpenclawConfigPath(cliPath) {
|
|
9331
9564
|
const configPath = resolveOpenclawConfigPath(cliPath);
|
|
9332
|
-
if (
|
|
9565
|
+
if (fs16.existsSync(configPath)) {
|
|
9333
9566
|
return configPath;
|
|
9334
9567
|
}
|
|
9335
9568
|
if (cliPath) {
|
|
@@ -9436,7 +9669,7 @@ function resolveMemoryDir() {
|
|
|
9436
9669
|
const envMemoryDir = readCompatEnv("REMNIC_MEMORY_DIR", "ENGRAM_MEMORY_DIR");
|
|
9437
9670
|
if (envMemoryDir) return normalizeMemoryDirPath(envMemoryDir);
|
|
9438
9671
|
const configPath = resolveConfigPath();
|
|
9439
|
-
const raw =
|
|
9672
|
+
const raw = fs16.existsSync(configPath) ? JSON.parse(fs16.readFileSync(configPath, "utf8")) : {};
|
|
9440
9673
|
const remnicCfg = resolveRemnicConfigRecord6(raw);
|
|
9441
9674
|
if (typeof remnicCfg.memoryDir === "string" && remnicCfg.memoryDir.length > 0) {
|
|
9442
9675
|
return normalizeMemoryDirPath(remnicCfg.memoryDir);
|
|
@@ -9445,18 +9678,18 @@ function resolveMemoryDir() {
|
|
|
9445
9678
|
const standalonePath = path18.join(home, ".remnic", "memory");
|
|
9446
9679
|
const legacyStandalonePath = path18.join(home, ".engram", "memory");
|
|
9447
9680
|
const openclawPath = path18.join(resolveOpenclawStateDir(), "workspace", "memory", "local");
|
|
9448
|
-
if (
|
|
9449
|
-
if (
|
|
9681
|
+
if (fs16.existsSync(standalonePath)) return standalonePath;
|
|
9682
|
+
if (fs16.existsSync(legacyStandalonePath)) return legacyStandalonePath;
|
|
9450
9683
|
return openclawPath;
|
|
9451
9684
|
})();
|
|
9452
9685
|
const manifestPath = getManifestPath();
|
|
9453
|
-
if (
|
|
9686
|
+
if (fs16.existsSync(manifestPath)) {
|
|
9454
9687
|
try {
|
|
9455
9688
|
const active = getActiveSpace();
|
|
9456
9689
|
if (active?.memoryDir) {
|
|
9457
9690
|
const activeMemoryDir = normalizeMemoryDirPath(active.memoryDir);
|
|
9458
|
-
if (!
|
|
9459
|
-
|
|
9691
|
+
if (!fs16.existsSync(activeMemoryDir)) {
|
|
9692
|
+
fs16.mkdirSync(activeMemoryDir, { recursive: true });
|
|
9460
9693
|
}
|
|
9461
9694
|
return activeMemoryDir;
|
|
9462
9695
|
}
|
|
@@ -9505,13 +9738,13 @@ function resolveOpenclawConfigPath(cliPath) {
|
|
|
9505
9738
|
const envPath = process.env.OPENCLAW_CONFIG_PATH || process.env.OPENCLAW_ENGRAM_CONFIG_PATH;
|
|
9506
9739
|
if (envPath) return path18.resolve(expandTilde(envPath));
|
|
9507
9740
|
for (const candidate of DEFAULT_OPENCLAW_CONFIG_PATHS_FOR_DOCTOR) {
|
|
9508
|
-
if (
|
|
9741
|
+
if (fs16.existsSync(candidate)) return candidate;
|
|
9509
9742
|
}
|
|
9510
9743
|
return path18.join(resolveOpenclawStateDir(), "openclaw.json");
|
|
9511
9744
|
}
|
|
9512
9745
|
function readOpenclawConfig(configPath) {
|
|
9513
|
-
if (!
|
|
9514
|
-
const raw =
|
|
9746
|
+
if (!fs16.existsSync(configPath)) return {};
|
|
9747
|
+
const raw = fs16.readFileSync(configPath, "utf-8");
|
|
9515
9748
|
let parsed;
|
|
9516
9749
|
try {
|
|
9517
9750
|
parsed = JSON.parse(raw);
|
|
@@ -9613,9 +9846,9 @@ function formatOpenclawUpgradeStamp(now = /* @__PURE__ */ new Date()) {
|
|
|
9613
9846
|
return `${yyyy}${mm}${dd}-${hh}${min}${ss}`;
|
|
9614
9847
|
}
|
|
9615
9848
|
function backupPathIfPresent(sourcePath, backupPath) {
|
|
9616
|
-
if (!
|
|
9617
|
-
|
|
9618
|
-
|
|
9849
|
+
if (!fs16.existsSync(sourcePath)) return false;
|
|
9850
|
+
fs16.mkdirSync(path18.dirname(backupPath), { recursive: true });
|
|
9851
|
+
fs16.cpSync(sourcePath, backupPath, { recursive: true });
|
|
9619
9852
|
return true;
|
|
9620
9853
|
}
|
|
9621
9854
|
function restartOpenclawGateway() {
|
|
@@ -9634,7 +9867,7 @@ function restartOpenclawGateway() {
|
|
|
9634
9867
|
}
|
|
9635
9868
|
function cmdInit() {
|
|
9636
9869
|
const configPath = path18.join(process.cwd(), "remnic.config.json");
|
|
9637
|
-
if (
|
|
9870
|
+
if (fs16.existsSync(configPath)) {
|
|
9638
9871
|
console.log(`Config already exists: ${configPath}`);
|
|
9639
9872
|
return;
|
|
9640
9873
|
}
|
|
@@ -9650,7 +9883,7 @@ function cmdInit() {
|
|
|
9650
9883
|
authToken: "${REMNIC_AUTH_TOKEN}"
|
|
9651
9884
|
}
|
|
9652
9885
|
};
|
|
9653
|
-
|
|
9886
|
+
fs16.writeFileSync(configPath, JSON.stringify(template, null, 2) + "\n");
|
|
9654
9887
|
console.log(`Created ${configPath}`);
|
|
9655
9888
|
console.log("\nSet these environment variables:");
|
|
9656
9889
|
console.log(" export OPENAI_API_KEY=sk-...");
|
|
@@ -9660,7 +9893,7 @@ function cmdInit() {
|
|
|
9660
9893
|
console.log(" npx --package @remnic/server remnic-server");
|
|
9661
9894
|
}
|
|
9662
9895
|
function resolveStatusProbeToken() {
|
|
9663
|
-
const operatorToken =
|
|
9896
|
+
const operatorToken = resolveOperatorToken(resolveConfigPath());
|
|
9664
9897
|
if (operatorToken) return operatorToken;
|
|
9665
9898
|
try {
|
|
9666
9899
|
const usable = listTokens().find(
|
|
@@ -9672,6 +9905,25 @@ function resolveStatusProbeToken() {
|
|
|
9672
9905
|
}
|
|
9673
9906
|
var __statusHealthTestHooks = { resolveStatusProbeToken };
|
|
9674
9907
|
async function cmdStatus(json) {
|
|
9908
|
+
const remote = resolveRemoteDaemon(resolveConfigPath());
|
|
9909
|
+
if (remote) {
|
|
9910
|
+
if (json) {
|
|
9911
|
+
const probe = await probeDaemonHealth(remote.baseUrl, remote.token);
|
|
9912
|
+
console.log(
|
|
9913
|
+
JSON.stringify({
|
|
9914
|
+
running: probe.ok,
|
|
9915
|
+
pid: null,
|
|
9916
|
+
pidFile: null,
|
|
9917
|
+
logFile: null,
|
|
9918
|
+
remote: remote.baseUrl
|
|
9919
|
+
})
|
|
9920
|
+
);
|
|
9921
|
+
return;
|
|
9922
|
+
}
|
|
9923
|
+
console.log(`Remnic server: remote (${remote.baseUrl})`);
|
|
9924
|
+
await printHealthCheck(remote.baseUrl, remote.token);
|
|
9925
|
+
return;
|
|
9926
|
+
}
|
|
9675
9927
|
const { running, pid } = isServiceRunning();
|
|
9676
9928
|
if (json) {
|
|
9677
9929
|
console.log(JSON.stringify({ running, pid: pid ?? null, pidFile: PID_FILE, logFile: LOG_FILE }));
|
|
@@ -9682,101 +9934,7 @@ async function cmdStatus(json) {
|
|
|
9682
9934
|
return;
|
|
9683
9935
|
}
|
|
9684
9936
|
console.log(`Remnic server: running${pid ? ` (pid ${pid})` : ""}`);
|
|
9685
|
-
|
|
9686
|
-
const probeToken = resolveStatusProbeToken();
|
|
9687
|
-
const controller = new AbortController();
|
|
9688
|
-
const timeoutId = setTimeout(() => controller.abort(), 3e3);
|
|
9689
|
-
try {
|
|
9690
|
-
const response = await fetch(`http://127.0.0.1:${port}/engram/v1/health`, {
|
|
9691
|
-
signal: controller.signal,
|
|
9692
|
-
...probeToken ? { headers: { Authorization: `Bearer ${probeToken}` } } : {}
|
|
9693
|
-
});
|
|
9694
|
-
if (!response.ok) {
|
|
9695
|
-
const hint = response.status === 401 && !probeToken ? " (daemon requires auth and no local token was found \u2014 set REMNIC_AUTH_TOKEN, configure server.authToken, or run 'remnic token generate')" : response.status === 401 ? " (local token rejected by the daemon)" : "";
|
|
9696
|
-
console.log(`Health: server responded with ${response.status} ${response.statusText}${hint}`);
|
|
9697
|
-
} else {
|
|
9698
|
-
const health = await response.json();
|
|
9699
|
-
const status = typeof health.status === "string" ? health.status : "ok";
|
|
9700
|
-
console.log(`Health: ${status}`);
|
|
9701
|
-
const qmd = health.qmd;
|
|
9702
|
-
if (qmd?.pendingEmbeddings != null) {
|
|
9703
|
-
console.log(` Pending embeddings: ${qmd.pendingEmbeddings}`);
|
|
9704
|
-
if (qmd.oldestPendingAgeMs != null) {
|
|
9705
|
-
console.log(` Oldest pending: ${Math.round(qmd.oldestPendingAgeMs / 6e4)}m`);
|
|
9706
|
-
}
|
|
9707
|
-
if (qmd.embeddingBacklogThreshold != null) {
|
|
9708
|
-
console.log(` Backlog threshold: ${qmd.embeddingBacklogThreshold}`);
|
|
9709
|
-
}
|
|
9710
|
-
}
|
|
9711
|
-
if (qmd?.degradedReason) {
|
|
9712
|
-
console.log(` Degraded: ${qmd.degradedReason}`);
|
|
9713
|
-
}
|
|
9714
|
-
}
|
|
9715
|
-
} catch {
|
|
9716
|
-
console.log("Health: unable to reach server");
|
|
9717
|
-
} finally {
|
|
9718
|
-
clearTimeout(timeoutId);
|
|
9719
|
-
}
|
|
9720
|
-
}
|
|
9721
|
-
function oauthReadConfigRecord(configPath) {
|
|
9722
|
-
try {
|
|
9723
|
-
const parsed = JSON.parse(fs15.readFileSync(configPath, "utf8"));
|
|
9724
|
-
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
9725
|
-
return parsed;
|
|
9726
|
-
}
|
|
9727
|
-
return void 0;
|
|
9728
|
-
} catch {
|
|
9729
|
-
return void 0;
|
|
9730
|
-
}
|
|
9731
|
-
}
|
|
9732
|
-
function oauthResolveBaseUrl() {
|
|
9733
|
-
const configPath = resolveConfigPath();
|
|
9734
|
-
let port = 4318;
|
|
9735
|
-
let host = "127.0.0.1";
|
|
9736
|
-
const raw = oauthReadConfigRecord(configPath);
|
|
9737
|
-
if (raw && "server" in raw) {
|
|
9738
|
-
const server = raw.server;
|
|
9739
|
-
if (server && typeof server === "object") {
|
|
9740
|
-
const hostCandidate = server.host;
|
|
9741
|
-
if (typeof hostCandidate === "string" && hostCandidate.length > 0) {
|
|
9742
|
-
host = hostCandidate;
|
|
9743
|
-
}
|
|
9744
|
-
const portCandidate = server.port;
|
|
9745
|
-
if (typeof portCandidate === "number" && Number.isInteger(portCandidate)) {
|
|
9746
|
-
port = portCandidate;
|
|
9747
|
-
}
|
|
9748
|
-
}
|
|
9749
|
-
}
|
|
9750
|
-
const envHost = readCompatEnv("REMNIC_HOST", "ENGRAM_HOST");
|
|
9751
|
-
if (typeof envHost === "string" && envHost.length > 0) {
|
|
9752
|
-
host = envHost;
|
|
9753
|
-
}
|
|
9754
|
-
const envPortRaw = readCompatEnv("REMNIC_PORT", "ENGRAM_PORT");
|
|
9755
|
-
if (typeof envPortRaw === "string" && envPortRaw.length > 0) {
|
|
9756
|
-
const envPort = Number(envPortRaw);
|
|
9757
|
-
if (!Number.isInteger(envPort) || envPort < 1 || envPort > 65535) {
|
|
9758
|
-
throw new Error(
|
|
9759
|
-
`Invalid REMNIC_PORT/ENGRAM_PORT "${envPortRaw}": expected an integer in [1, 65535].`
|
|
9760
|
-
);
|
|
9761
|
-
}
|
|
9762
|
-
port = envPort;
|
|
9763
|
-
}
|
|
9764
|
-
return `http://${host}:${port}`;
|
|
9765
|
-
}
|
|
9766
|
-
function oauthResolveOperatorToken() {
|
|
9767
|
-
const envToken = readCompatEnv("REMNIC_AUTH_TOKEN", "ENGRAM_AUTH_TOKEN");
|
|
9768
|
-
if (typeof envToken === "string" && envToken.length > 0) return envToken;
|
|
9769
|
-
const raw = oauthReadConfigRecord(resolveConfigPath());
|
|
9770
|
-
if (raw && "server" in raw) {
|
|
9771
|
-
const server = raw.server;
|
|
9772
|
-
if (server && typeof server === "object" && "authToken" in server) {
|
|
9773
|
-
const candidate = server.authToken;
|
|
9774
|
-
if (typeof candidate === "string" && candidate.length > 0 && !candidate.includes("${")) {
|
|
9775
|
-
return candidate;
|
|
9776
|
-
}
|
|
9777
|
-
}
|
|
9778
|
-
}
|
|
9779
|
-
return void 0;
|
|
9937
|
+
await printHealthCheck(resolveDaemonBaseUrl(resolveConfigPath()), resolveStatusProbeToken());
|
|
9780
9938
|
}
|
|
9781
9939
|
async function oauthFetch(method, path19, token, body) {
|
|
9782
9940
|
const controller = new AbortController();
|
|
@@ -9797,7 +9955,7 @@ async function oauthFetch(method, path19, token, body) {
|
|
|
9797
9955
|
if (body !== void 0) {
|
|
9798
9956
|
init.body = JSON.stringify(body);
|
|
9799
9957
|
}
|
|
9800
|
-
const response = await fetch(`${
|
|
9958
|
+
const response = await fetch(`${resolveDaemonBaseUrl(resolveConfigPath())}${path19}`, init);
|
|
9801
9959
|
if (response.status === 401) {
|
|
9802
9960
|
throw new Error(
|
|
9803
9961
|
"operator token rejected by remnic-server (HTTP 401). Update `server.authToken` or `REMNIC_AUTH_TOKEN` to match the running daemon."
|
|
@@ -9835,7 +9993,7 @@ async function oauthFetch(method, path19, token, body) {
|
|
|
9835
9993
|
const msg = err.message;
|
|
9836
9994
|
if (msg.includes("ECONNREFUSED") || msg.includes("ECONNRESET") || msg.includes("fetch failed") || msg.includes("aborted") || msg.includes("ENOTFOUND")) {
|
|
9837
9995
|
throw new Error(
|
|
9838
|
-
`cannot reach remnic-server at ${
|
|
9996
|
+
`cannot reach remnic-server at ${resolveDaemonBaseUrl(resolveConfigPath())} \u2014 is remnic-server running? Start it with \`remnic daemon start\` (or point REMNIC_DAEMON_URL at a remote daemon).`
|
|
9839
9997
|
);
|
|
9840
9998
|
}
|
|
9841
9999
|
throw err;
|
|
@@ -9914,7 +10072,7 @@ Server endpoints (operator bearer auth):
|
|
|
9914
10072
|
POST /oauth/pending/<ref>/approve
|
|
9915
10073
|
POST /oauth/pending/<ref>/deny`;
|
|
9916
10074
|
function oauthRequireOperatorToken() {
|
|
9917
|
-
const token =
|
|
10075
|
+
const token = resolveOperatorToken(resolveConfigPath());
|
|
9918
10076
|
if (!token) {
|
|
9919
10077
|
console.error(
|
|
9920
10078
|
"remnic oauth: no operator token configured. Set `server.authToken` in remnic.config.json or export REMNIC_AUTH_TOKEN."
|
|
@@ -10134,9 +10292,20 @@ async function cmdQuery(queryText, json, explain) {
|
|
|
10134
10292
|
console.error("Usage: remnic query <text>");
|
|
10135
10293
|
process.exit(1);
|
|
10136
10294
|
}
|
|
10295
|
+
const remote = resolveRemoteDaemon(resolveConfigPath());
|
|
10296
|
+
if (remote) {
|
|
10297
|
+
const started = Date.now();
|
|
10298
|
+
const result = await remoteRecall(remote, buildQueryRecallRequest(queryText));
|
|
10299
|
+
if (explain) {
|
|
10300
|
+
printMinimalQueryExplain(queryText, result, Date.now() - started, json);
|
|
10301
|
+
return;
|
|
10302
|
+
}
|
|
10303
|
+
printQueryResult(result, json);
|
|
10304
|
+
return;
|
|
10305
|
+
}
|
|
10137
10306
|
initLogger3();
|
|
10138
10307
|
const configPath = resolveConfigPath();
|
|
10139
|
-
const raw =
|
|
10308
|
+
const raw = fs16.existsSync(configPath) ? JSON.parse(fs16.readFileSync(configPath, "utf8")) : {};
|
|
10140
10309
|
const remnicCfg = resolveRemnicConfigRecord6(raw);
|
|
10141
10310
|
const config = parseConfig7(remnicCfg);
|
|
10142
10311
|
const orchestrator = new Orchestrator4(config);
|
|
@@ -10147,14 +10316,14 @@ async function cmdQuery(queryText, json, explain) {
|
|
|
10147
10316
|
if (explain) {
|
|
10148
10317
|
const bench = await tryLoadBenchModule();
|
|
10149
10318
|
if (bench?.runExplain) {
|
|
10150
|
-
const
|
|
10319
|
+
const result = await bench.runExplain(service, queryText);
|
|
10151
10320
|
if (json) {
|
|
10152
|
-
console.log(JSON.stringify(
|
|
10321
|
+
console.log(JSON.stringify(result, null, 2));
|
|
10153
10322
|
} else {
|
|
10154
|
-
console.log(`Query: ${
|
|
10155
|
-
console.log(`Tiers used: ${
|
|
10156
|
-
console.log(`Total duration: ${
|
|
10157
|
-
for (const t of
|
|
10323
|
+
console.log(`Query: ${result.query}`);
|
|
10324
|
+
console.log(`Tiers used: ${result.tiersUsed.join(" \u2192 ")}`);
|
|
10325
|
+
console.log(`Total duration: ${result.totalDurationMs}ms`);
|
|
10326
|
+
for (const t of result.tierResults) {
|
|
10158
10327
|
console.log(` ${t.tier}: ${t.latencyMs}ms (${t.resultsCount} results)`);
|
|
10159
10328
|
}
|
|
10160
10329
|
}
|
|
@@ -10162,42 +10331,46 @@ async function cmdQuery(queryText, json, explain) {
|
|
|
10162
10331
|
}
|
|
10163
10332
|
const explainStart = Date.now();
|
|
10164
10333
|
const recallResult = await service.recall(recallRequest);
|
|
10165
|
-
|
|
10166
|
-
const resultsCount = typeof recallResult.count === "number" ? recallResult.count : Array.isArray(recallResult.results) ? recallResult.results.length : 0;
|
|
10167
|
-
const minimalExplain = {
|
|
10168
|
-
query: queryText,
|
|
10169
|
-
totalDurationMs,
|
|
10170
|
-
resultsCount,
|
|
10171
|
-
results: summarizeQueryExplainFallbackResults(recallResult),
|
|
10172
|
-
note: "Install @remnic/bench for a full tier-level explain breakdown."
|
|
10173
|
-
};
|
|
10174
|
-
if (json) {
|
|
10175
|
-
console.log(JSON.stringify(minimalExplain, null, 2));
|
|
10176
|
-
} else {
|
|
10177
|
-
console.log(`Query: ${minimalExplain.query}`);
|
|
10178
|
-
console.log(`Total duration: ${minimalExplain.totalDurationMs}ms`);
|
|
10179
|
-
console.log(`Results: ${minimalExplain.resultsCount}`);
|
|
10180
|
-
for (const result2 of minimalExplain.results) {
|
|
10181
|
-
const suffix = result2.source ? ` (${result2.source})` : "";
|
|
10182
|
-
console.log(` ${result2.index}. ${result2.text}${suffix}`);
|
|
10183
|
-
}
|
|
10184
|
-
console.log(`Note: ${minimalExplain.note}`);
|
|
10185
|
-
}
|
|
10334
|
+
printMinimalQueryExplain(queryText, recallResult, Date.now() - explainStart, json);
|
|
10186
10335
|
return;
|
|
10187
10336
|
}
|
|
10188
|
-
|
|
10189
|
-
if (json) {
|
|
10190
|
-
console.log(JSON.stringify(result, null, 2));
|
|
10191
|
-
} else {
|
|
10192
|
-
for (const line of renderQueryTextLines(result)) {
|
|
10193
|
-
console.log(line);
|
|
10194
|
-
}
|
|
10195
|
-
}
|
|
10337
|
+
printQueryResult(await service.recall(recallRequest), json);
|
|
10196
10338
|
} finally {
|
|
10197
10339
|
orchestrator.abortDeferredInit();
|
|
10198
10340
|
await orchestrator.destroy();
|
|
10199
10341
|
}
|
|
10200
10342
|
}
|
|
10343
|
+
function printQueryResult(result, json) {
|
|
10344
|
+
if (json) {
|
|
10345
|
+
console.log(JSON.stringify(result, null, 2));
|
|
10346
|
+
return;
|
|
10347
|
+
}
|
|
10348
|
+
for (const line of renderQueryTextLines(result)) {
|
|
10349
|
+
console.log(line);
|
|
10350
|
+
}
|
|
10351
|
+
}
|
|
10352
|
+
function printMinimalQueryExplain(queryText, result, totalDurationMs, json) {
|
|
10353
|
+
const resultsCount = typeof result.count === "number" ? result.count : Array.isArray(result.results) ? result.results.length : 0;
|
|
10354
|
+
const minimalExplain = {
|
|
10355
|
+
query: queryText,
|
|
10356
|
+
totalDurationMs,
|
|
10357
|
+
resultsCount,
|
|
10358
|
+
results: summarizeQueryExplainFallbackResults(result),
|
|
10359
|
+
note: "Install @remnic/bench for a full tier-level explain breakdown."
|
|
10360
|
+
};
|
|
10361
|
+
if (json) {
|
|
10362
|
+
console.log(JSON.stringify(minimalExplain, null, 2));
|
|
10363
|
+
return;
|
|
10364
|
+
}
|
|
10365
|
+
console.log(`Query: ${minimalExplain.query}`);
|
|
10366
|
+
console.log(`Total duration: ${minimalExplain.totalDurationMs}ms`);
|
|
10367
|
+
console.log(`Results: ${minimalExplain.resultsCount}`);
|
|
10368
|
+
for (const resultLine of minimalExplain.results) {
|
|
10369
|
+
const suffix = resultLine.source ? ` (${resultLine.source})` : "";
|
|
10370
|
+
console.log(` ${resultLine.index}. ${resultLine.text}${suffix}`);
|
|
10371
|
+
}
|
|
10372
|
+
console.log(`Note: ${minimalExplain.note}`);
|
|
10373
|
+
}
|
|
10201
10374
|
function parseActionConfidenceRest(rest) {
|
|
10202
10375
|
const valueFlags = /* @__PURE__ */ new Set([
|
|
10203
10376
|
"--action",
|
|
@@ -10305,9 +10478,14 @@ async function runXrayCommand(rest, io) {
|
|
|
10305
10478
|
async function cmdXray(rest) {
|
|
10306
10479
|
const { rawQuery, options } = extractXrayRawArgs(rest);
|
|
10307
10480
|
parseXrayCliOptions(rawQuery, options);
|
|
10481
|
+
const remote = resolveRemoteDaemon(resolveConfigPath());
|
|
10482
|
+
if (remote) {
|
|
10483
|
+
await runXrayCommand(rest, xrayCliIo((request) => remoteRecallXray(remote, request)));
|
|
10484
|
+
return;
|
|
10485
|
+
}
|
|
10308
10486
|
initLogger3();
|
|
10309
10487
|
const configPath = resolveConfigPath();
|
|
10310
|
-
const raw =
|
|
10488
|
+
const raw = fs16.existsSync(configPath) ? JSON.parse(fs16.readFileSync(configPath, "utf8")) : {};
|
|
10311
10489
|
const remnicCfg = resolveRemnicConfigRecord6(raw);
|
|
10312
10490
|
const config = parseConfig7(remnicCfg);
|
|
10313
10491
|
const orchestrator = new Orchestrator4(config);
|
|
@@ -10315,22 +10493,22 @@ async function cmdXray(rest) {
|
|
|
10315
10493
|
await orchestrator.deferredReady;
|
|
10316
10494
|
const service = new EngramAccessService2(orchestrator);
|
|
10317
10495
|
try {
|
|
10318
|
-
await runXrayCommand(rest,
|
|
10319
|
-
recallXray: (request) => service.recallXray(request),
|
|
10320
|
-
writeFile: async (filePath, data) => {
|
|
10321
|
-
const { writeFile: fsWriteFile } = await import("fs/promises");
|
|
10322
|
-
await fsWriteFile(filePath, data, "utf8");
|
|
10323
|
-
},
|
|
10324
|
-
stdout: (line) => console.log(line)
|
|
10325
|
-
});
|
|
10496
|
+
await runXrayCommand(rest, xrayCliIo((request) => service.recallXray(request)));
|
|
10326
10497
|
} finally {
|
|
10327
10498
|
orchestrator.abortDeferredInit();
|
|
10328
10499
|
}
|
|
10329
10500
|
}
|
|
10501
|
+
function xrayCliIo(recallXray) {
|
|
10502
|
+
return {
|
|
10503
|
+
recallXray,
|
|
10504
|
+
writeFile: (filePath, data) => fsWriteFile(filePath, data, "utf8"),
|
|
10505
|
+
stdout: (line) => console.log(line)
|
|
10506
|
+
};
|
|
10507
|
+
}
|
|
10330
10508
|
async function cmdVersions(rest) {
|
|
10331
10509
|
initLogger3();
|
|
10332
10510
|
const configPath = resolveConfigPath();
|
|
10333
|
-
const raw =
|
|
10511
|
+
const raw = fs16.existsSync(configPath) ? JSON.parse(fs16.readFileSync(configPath, "utf8")) : {};
|
|
10334
10512
|
const remnicCfg = resolveRemnicConfigRecord6(raw);
|
|
10335
10513
|
const config = parseConfig7(remnicCfg);
|
|
10336
10514
|
if (!config.versioningEnabled) {
|
|
@@ -10446,7 +10624,7 @@ Options:
|
|
|
10446
10624
|
async function cmdEnrich(rest) {
|
|
10447
10625
|
initLogger3();
|
|
10448
10626
|
const configPath = resolveConfigPath();
|
|
10449
|
-
const raw =
|
|
10627
|
+
const raw = fs16.existsSync(configPath) ? JSON.parse(fs16.readFileSync(configPath, "utf8")) : {};
|
|
10450
10628
|
const remnicCfg = resolveRemnicConfigRecord6(raw);
|
|
10451
10629
|
const config = parseConfig7(remnicCfg);
|
|
10452
10630
|
const subcommand = rest[0];
|
|
@@ -10691,7 +10869,7 @@ Shared with:
|
|
|
10691
10869
|
process.exit(1);
|
|
10692
10870
|
}
|
|
10693
10871
|
const configPath = resolveConfigPath();
|
|
10694
|
-
const raw =
|
|
10872
|
+
const raw = fs16.existsSync(configPath) ? JSON.parse(fs16.readFileSync(configPath, "utf8")) : {};
|
|
10695
10873
|
const remnicCfg = resolveRemnicConfigRecord6(raw);
|
|
10696
10874
|
const config = parseConfig7(remnicCfg);
|
|
10697
10875
|
const memoryDir = expandTilde(
|
|
@@ -10708,7 +10886,7 @@ Shared with:
|
|
|
10708
10886
|
async function cmdExtensions(action, rest) {
|
|
10709
10887
|
initLogger3();
|
|
10710
10888
|
const configPath = resolveConfigPath();
|
|
10711
|
-
const raw =
|
|
10889
|
+
const raw = fs16.existsSync(configPath) ? JSON.parse(fs16.readFileSync(configPath, "utf8")) : {};
|
|
10712
10890
|
const remnicCfg = resolveRemnicConfigRecord6(raw);
|
|
10713
10891
|
const config = parseConfig7(remnicCfg);
|
|
10714
10892
|
const root = resolveExtensionsRoot(config);
|
|
@@ -10759,7 +10937,7 @@ Root: ${root}`);
|
|
|
10759
10937
|
const extensions = await discoverMemoryExtensions(root, warnLog);
|
|
10760
10938
|
let entries = [];
|
|
10761
10939
|
try {
|
|
10762
|
-
entries =
|
|
10940
|
+
entries = fs16.readdirSync(root);
|
|
10763
10941
|
} catch {
|
|
10764
10942
|
console.log(`Extensions root does not exist: ${root}`);
|
|
10765
10943
|
process.exitCode = 0;
|
|
@@ -10770,7 +10948,7 @@ Root: ${root}`);
|
|
|
10770
10948
|
for (const entry of entries) {
|
|
10771
10949
|
const entryPath = path18.join(root, entry);
|
|
10772
10950
|
try {
|
|
10773
|
-
if (!
|
|
10951
|
+
if (!fs16.statSync(entryPath).isDirectory()) continue;
|
|
10774
10952
|
} catch {
|
|
10775
10953
|
continue;
|
|
10776
10954
|
}
|
|
@@ -10802,7 +10980,7 @@ Root: ${root}`);
|
|
|
10802
10980
|
async function cmdBriefing(rest) {
|
|
10803
10981
|
initLogger3();
|
|
10804
10982
|
const configPath = resolveConfigPath();
|
|
10805
|
-
const raw =
|
|
10983
|
+
const raw = fs16.existsSync(configPath) ? JSON.parse(fs16.readFileSync(configPath, "utf8")) : {};
|
|
10806
10984
|
const remnicCfg = resolveRemnicConfigRecord6(raw);
|
|
10807
10985
|
const config = parseConfig7(remnicCfg);
|
|
10808
10986
|
if (!config.briefing.enabled) {
|
|
@@ -10882,10 +11060,10 @@ async function cmdBriefing(rest) {
|
|
|
10882
11060
|
if (save) {
|
|
10883
11061
|
try {
|
|
10884
11062
|
const saveDir = resolveBriefingSaveDir(config.briefing.saveDir);
|
|
10885
|
-
|
|
11063
|
+
fs16.mkdirSync(saveDir, { recursive: true });
|
|
10886
11064
|
const filename = briefingFilename(new Date(result.window.to), format);
|
|
10887
11065
|
const filePath = path18.join(saveDir, filename);
|
|
10888
|
-
|
|
11066
|
+
fs16.writeFileSync(filePath, payload + (payload.endsWith("\n") ? "" : "\n"));
|
|
10889
11067
|
console.error(`Saved briefing: ${filePath}`);
|
|
10890
11068
|
} catch (err) {
|
|
10891
11069
|
console.error(`Failed to save briefing: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -10903,7 +11081,7 @@ async function cmdDoctor() {
|
|
|
10903
11081
|
detail: `${nodeVersion} (requires >= 22.12.0)`
|
|
10904
11082
|
});
|
|
10905
11083
|
const configPath = resolveConfigPath();
|
|
10906
|
-
const configExists =
|
|
11084
|
+
const configExists = fs16.existsSync(configPath);
|
|
10907
11085
|
checks.push({ name: "Config file", ok: configExists, detail: configPath });
|
|
10908
11086
|
let standaloneConfig;
|
|
10909
11087
|
let standaloneConfigError;
|
|
@@ -10911,7 +11089,7 @@ async function cmdDoctor() {
|
|
|
10911
11089
|
let configuredNs = { invalid: false };
|
|
10912
11090
|
if (configExists) {
|
|
10913
11091
|
try {
|
|
10914
|
-
const raw = JSON.parse(
|
|
11092
|
+
const raw = JSON.parse(fs16.readFileSync(configPath, "utf8"));
|
|
10915
11093
|
const remnicCfg = resolveRemnicConfigRecord6(raw);
|
|
10916
11094
|
standaloneOpenaiApiKeyExplicitlyFalse = isOpenaiApiKeyDisabled(remnicCfg.openaiApiKey);
|
|
10917
11095
|
configuredNs = readConfiguredNamespace(remnicCfg);
|
|
@@ -10927,7 +11105,7 @@ async function cmdDoctor() {
|
|
|
10927
11105
|
memoryDir = parseConfig7({}).memoryDir;
|
|
10928
11106
|
}
|
|
10929
11107
|
try {
|
|
10930
|
-
|
|
11108
|
+
fs16.mkdirSync(memoryDir, { recursive: true });
|
|
10931
11109
|
checks.push({ name: "Memory directory", ok: true, detail: memoryDir });
|
|
10932
11110
|
} catch {
|
|
10933
11111
|
checks.push({ name: "Memory directory", ok: false, detail: `cannot create ${memoryDir}` });
|
|
@@ -10956,7 +11134,7 @@ async function cmdDoctor() {
|
|
|
10956
11134
|
});
|
|
10957
11135
|
if (nsPolicyCheck) checks.push(nsPolicyCheck);
|
|
10958
11136
|
const openclawConfigPath = resolveOpenclawConfigPath();
|
|
10959
|
-
const openclawConfigExists =
|
|
11137
|
+
const openclawConfigExists = fs16.existsSync(openclawConfigPath);
|
|
10960
11138
|
let openclawConfig = {};
|
|
10961
11139
|
let openclawConfigValid = false;
|
|
10962
11140
|
let openclawPluginModeConfigured = false;
|
|
@@ -10964,7 +11142,7 @@ async function cmdDoctor() {
|
|
|
10964
11142
|
let activeOpenclawEntryConfig = null;
|
|
10965
11143
|
if (openclawConfigExists) {
|
|
10966
11144
|
try {
|
|
10967
|
-
const parsed = JSON.parse(
|
|
11145
|
+
const parsed = JSON.parse(fs16.readFileSync(openclawConfigPath, "utf-8"));
|
|
10968
11146
|
if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
|
|
10969
11147
|
openclawConfig = parsed;
|
|
10970
11148
|
openclawConfigValid = true;
|
|
@@ -11044,9 +11222,9 @@ async function cmdDoctor() {
|
|
|
11044
11222
|
let memDirOk = false;
|
|
11045
11223
|
let memDirDetail = `${resolvedMemDir} (not found)`;
|
|
11046
11224
|
let memDirRemediation = `Run \`remnic openclaw install --memory-dir "${resolvedMemDir}"\` to create the directory.`;
|
|
11047
|
-
if (
|
|
11225
|
+
if (fs16.existsSync(resolvedMemDir)) {
|
|
11048
11226
|
try {
|
|
11049
|
-
const stat2 =
|
|
11227
|
+
const stat2 = fs16.statSync(resolvedMemDir);
|
|
11050
11228
|
if (stat2.isDirectory()) {
|
|
11051
11229
|
memDirOk = true;
|
|
11052
11230
|
memDirDetail = resolvedMemDir;
|
|
@@ -11097,16 +11275,29 @@ async function cmdDoctor() {
|
|
|
11097
11275
|
warn: openclawKeyErrorBlocksOk || standaloneConfigErrorBlocksOk || !hasApiKey && !openaiKeyOptionalForOpenclaw && !openaiKeyOptionalForStandalone,
|
|
11098
11276
|
detail: standaloneConfigErrorBlocksOk ? "config parse failed" : openclawKeyErrorBlocksOk ? "OpenClaw openaiApiKey placeholder failed" : hasApiKey ? "configured" : !diagnosingOpenclawPluginMode && standaloneOpenaiApiKeyExplicitlyFalse && localLlmConfigured ? "disabled by config (local LLM enabled)" : !diagnosingOpenclawPluginMode && standaloneOpenaiApiKeyExplicitlyFalse && standaloneConfig?.modelSource === "gateway" ? "disabled by config (gateway modelSource)" : activeOpenclawOpenaiApiKeyExplicitlyFalse ? "disabled by OpenClaw config" : openaiKeyOptionalForOpenclaw ? activeOpenclawModelSource === "gateway" ? "not set (not required for OpenClaw gateway modelSource)" : "not set (not required for OpenClaw local LLM)" : openaiKeyOptionalForStandalone ? "not set (standalone local/gateway model path configured)" : "not set (required for direct OpenAI-backed extraction)"
|
|
11099
11277
|
});
|
|
11100
|
-
const
|
|
11101
|
-
|
|
11102
|
-
|
|
11103
|
-
|
|
11104
|
-
|
|
11105
|
-
|
|
11106
|
-
|
|
11107
|
-
|
|
11108
|
-
|
|
11109
|
-
|
|
11278
|
+
const remoteDaemon = resolveRemoteDaemon(configPath);
|
|
11279
|
+
if (remoteDaemon) {
|
|
11280
|
+
const probe = await probeDaemonHealth(remoteDaemon.baseUrl, remoteDaemon.token);
|
|
11281
|
+
const detail = probe.ok ? `remote ${remoteDaemon.baseUrl} (reachable)` : `remote ${remoteDaemon.baseUrl} (unreachable${probe.status ? `, HTTP ${probe.status}` : probe.error ? `, ${probe.error}` : ""})`;
|
|
11282
|
+
checks.push({
|
|
11283
|
+
name: "Server daemon",
|
|
11284
|
+
ok: probe.ok,
|
|
11285
|
+
warn: !probe.ok,
|
|
11286
|
+
detail,
|
|
11287
|
+
remediation: probe.ok ? void 0 : "Check REMNIC_DAEMON_URL / server.url and the remote server's availability."
|
|
11288
|
+
});
|
|
11289
|
+
} else {
|
|
11290
|
+
const svcState = isServiceRunning();
|
|
11291
|
+
const standaloneServiceInstalled = isStandaloneServiceInstalled();
|
|
11292
|
+
const daemonOptionalForOpenclaw = openclawPluginModeConfigured && !standaloneServiceInstalled;
|
|
11293
|
+
checks.push({
|
|
11294
|
+
name: "Server daemon",
|
|
11295
|
+
ok: svcState.running || daemonOptionalForOpenclaw,
|
|
11296
|
+
warn: !svcState.running,
|
|
11297
|
+
detail: svcState.running ? `running${svcState.pid ? ` (pid ${svcState.pid})` : ""}` : daemonOptionalForOpenclaw ? "stopped (not required for OpenClaw plugin mode)" : "stopped",
|
|
11298
|
+
remediation: !svcState.running && standaloneServiceInstalled ? "Run `remnic daemon start`, or `remnic daemon uninstall` if you only use the OpenClaw plugin." : void 0
|
|
11299
|
+
});
|
|
11300
|
+
}
|
|
11110
11301
|
if (isMacOS()) {
|
|
11111
11302
|
const launchdInspection = selectLaunchdInspection(openclawPluginModeConfigured);
|
|
11112
11303
|
checks.push({
|
|
@@ -11188,12 +11379,12 @@ async function cmdDoctor() {
|
|
|
11188
11379
|
}
|
|
11189
11380
|
function cmdConfig() {
|
|
11190
11381
|
const configPath = resolveConfigPath();
|
|
11191
|
-
if (!
|
|
11382
|
+
if (!fs16.existsSync(configPath)) {
|
|
11192
11383
|
console.log("No config file found. Run `remnic init` to create one.");
|
|
11193
11384
|
return;
|
|
11194
11385
|
}
|
|
11195
11386
|
console.log(`Config: ${configPath}`);
|
|
11196
|
-
const rawConfig =
|
|
11387
|
+
const rawConfig = fs16.readFileSync(configPath, "utf8");
|
|
11197
11388
|
const redacted = rawConfig.replace(
|
|
11198
11389
|
/("(?:openaiApiKey|localLlmApiKey|authToken|apiKey|remoteSearchApiKey|meilisearchApiKey|opikApiKey)"\s*:\s*")([^"]*)(")/g,
|
|
11199
11390
|
"$1[REDACTED]$3"
|
|
@@ -11301,7 +11492,7 @@ async function cmdReview(action, rest) {
|
|
|
11301
11492
|
const configPath = resolveConfigPath();
|
|
11302
11493
|
let tombstonesConfig = null;
|
|
11303
11494
|
try {
|
|
11304
|
-
const rawCfg =
|
|
11495
|
+
const rawCfg = fs16.existsSync(configPath) ? JSON.parse(fs16.readFileSync(configPath, "utf8")) : {};
|
|
11305
11496
|
const remnicCfg = resolveRemnicConfigRecord6(rawCfg);
|
|
11306
11497
|
const config = parseConfig7(remnicCfg);
|
|
11307
11498
|
tombstonesConfig = {
|
|
@@ -12045,7 +12236,7 @@ async function pushOfflineFileContent(args) {
|
|
|
12045
12236
|
}
|
|
12046
12237
|
async function pushOfflineFileContentFromChunkReader(args) {
|
|
12047
12238
|
const filePath = resolveOfflineDirectHydrationPath(args.memoryDir, args.file.path);
|
|
12048
|
-
const stat2 =
|
|
12239
|
+
const stat2 = fs16.statSync(filePath);
|
|
12049
12240
|
if (stat2.mtimeMs !== args.file.mtimeMs) {
|
|
12050
12241
|
throw new Error(`local file changed while pushing offline content: ${args.file.path}`);
|
|
12051
12242
|
}
|
|
@@ -12536,7 +12727,7 @@ function advanceOfflineBaseFilesForSuccessfulPush(options) {
|
|
|
12536
12727
|
return [...next.values()].sort((left, right) => left.path.localeCompare(right.path));
|
|
12537
12728
|
}
|
|
12538
12729
|
async function runOfflineSyncOnce(options) {
|
|
12539
|
-
|
|
12730
|
+
fs16.mkdirSync(options.memoryDir, { recursive: true });
|
|
12540
12731
|
let activeStatePath = options.statePath;
|
|
12541
12732
|
let priorState = await readOfflineSyncState(activeStatePath);
|
|
12542
12733
|
let syncNamespace = options.namespace ?? priorState?.namespace;
|
|
@@ -13169,7 +13360,7 @@ Environment fallbacks:
|
|
|
13169
13360
|
const configPath = resolveConfigPath();
|
|
13170
13361
|
let config;
|
|
13171
13362
|
try {
|
|
13172
|
-
const rawConfig =
|
|
13363
|
+
const rawConfig = fs16.existsSync(configPath) ? JSON.parse(fs16.readFileSync(configPath, "utf8")) : {};
|
|
13173
13364
|
config = parseConfigQuietly(pickOfflineConfigRecord(rawConfig));
|
|
13174
13365
|
} catch {
|
|
13175
13366
|
throw new Error(
|
|
@@ -13184,7 +13375,7 @@ Environment fallbacks:
|
|
|
13184
13375
|
const statePath = statePathExplicit ? path18.resolve(expandTilde(stateOverride)) : remoteUrl !== void 0 ? defaultOfflineSyncStatePath(memoryDir, remoteUrl, namespace) : void 0;
|
|
13185
13376
|
if (action === "prepare") {
|
|
13186
13377
|
if (!remoteUrl || !token || !statePath) throw new Error("offline prepare requires remote URL and token");
|
|
13187
|
-
|
|
13378
|
+
fs16.mkdirSync(memoryDir, { recursive: true });
|
|
13188
13379
|
const remoteSnapshot = await fetchOfflineSnapshot({
|
|
13189
13380
|
remoteUrl,
|
|
13190
13381
|
token,
|
|
@@ -13283,7 +13474,7 @@ Environment fallbacks:
|
|
|
13283
13474
|
return;
|
|
13284
13475
|
}
|
|
13285
13476
|
if (action === "status") {
|
|
13286
|
-
|
|
13477
|
+
fs16.mkdirSync(memoryDir, { recursive: true });
|
|
13287
13478
|
const state = statePath ? await readOfflineSyncState(statePath) : null;
|
|
13288
13479
|
if (state && remoteUrl && statePath) {
|
|
13289
13480
|
assertOfflineStateMatches({
|
|
@@ -13421,7 +13612,7 @@ function cmdDedup(json) {
|
|
|
13421
13612
|
function readInstalledConnectorConfig(configPath, fallback) {
|
|
13422
13613
|
if (!configPath) return fallback;
|
|
13423
13614
|
try {
|
|
13424
|
-
const parsed = JSON.parse(
|
|
13615
|
+
const parsed = JSON.parse(fs16.readFileSync(configPath, "utf8"));
|
|
13425
13616
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return fallback;
|
|
13426
13617
|
const { token: _token, ...config } = parsed;
|
|
13427
13618
|
return config;
|
|
@@ -13599,7 +13790,7 @@ async function cmdConnectors(action, rest, json) {
|
|
|
13599
13790
|
const pub = factory();
|
|
13600
13791
|
const available = await pub.isHostAvailable();
|
|
13601
13792
|
const extRoot = available ? await pub.resolveExtensionRoot() : "(host not installed)";
|
|
13602
|
-
const extensionExists = available && extRoot ?
|
|
13793
|
+
const extensionExists = available && extRoot ? fs16.existsSync(extRoot) : false;
|
|
13603
13794
|
publisherChecks.push({
|
|
13604
13795
|
name: `Publisher: ${targetHostId}`,
|
|
13605
13796
|
ok: !available || extensionExists,
|
|
@@ -13673,7 +13864,7 @@ async function cmdConnectors(action, rest, json) {
|
|
|
13673
13864
|
let connectorsCfg;
|
|
13674
13865
|
const configPath = resolveConfigPath();
|
|
13675
13866
|
try {
|
|
13676
|
-
const raw =
|
|
13867
|
+
const raw = fs16.existsSync(configPath) ? JSON.parse(fs16.readFileSync(configPath, "utf8")) : {};
|
|
13677
13868
|
connectorsCfg = parseConfigQuietly(raw).connectors;
|
|
13678
13869
|
} catch {
|
|
13679
13870
|
process.stderr.write(
|
|
@@ -13749,7 +13940,7 @@ async function cmdConnectors(action, rest, json) {
|
|
|
13749
13940
|
}
|
|
13750
13941
|
initLogger3();
|
|
13751
13942
|
const configPath = resolveConfigPath();
|
|
13752
|
-
const raw =
|
|
13943
|
+
const raw = fs16.existsSync(configPath) ? JSON.parse(fs16.readFileSync(configPath, "utf8")) : {};
|
|
13753
13944
|
const remnicCfg = resolveRemnicConfigRecord6(raw);
|
|
13754
13945
|
const config = parseConfig7(remnicCfg);
|
|
13755
13946
|
const orchestrator = new Orchestrator4(config);
|
|
@@ -13874,7 +14065,7 @@ async function cmdConnectorsMarketplace(subAction, rest, json) {
|
|
|
13874
14065
|
console.error(`connectors marketplace: ${err instanceof Error ? err.message : String(err)}`);
|
|
13875
14066
|
process.exit(1);
|
|
13876
14067
|
}
|
|
13877
|
-
const rawConfig =
|
|
14068
|
+
const rawConfig = fs16.existsSync(configPath) ? JSON.parse(fs16.readFileSync(configPath, "utf8")) : {};
|
|
13878
14069
|
const pluginConfig = resolveRemnicConfigRecord6(rawConfig);
|
|
13879
14070
|
const config = parseConfig7(pluginConfig);
|
|
13880
14071
|
if (subAction === "generate") {
|
|
@@ -13896,13 +14087,13 @@ async function cmdConnectorsMarketplace(subAction, rest, json) {
|
|
|
13896
14087
|
} else if (subAction === "validate") {
|
|
13897
14088
|
const targetPath = rest.filter((a) => !a.startsWith("--"))[0] ?? path18.join(process.cwd(), "marketplace.json");
|
|
13898
14089
|
const resolved = path18.resolve(targetPath);
|
|
13899
|
-
if (!
|
|
14090
|
+
if (!fs16.existsSync(resolved)) {
|
|
13900
14091
|
console.error(`File not found: ${resolved}`);
|
|
13901
14092
|
process.exit(1);
|
|
13902
14093
|
}
|
|
13903
14094
|
let parsed;
|
|
13904
14095
|
try {
|
|
13905
|
-
parsed = JSON.parse(
|
|
14096
|
+
parsed = JSON.parse(fs16.readFileSync(resolved, "utf8"));
|
|
13906
14097
|
} catch {
|
|
13907
14098
|
console.error(`Invalid JSON in ${resolved}`);
|
|
13908
14099
|
process.exit(1);
|
|
@@ -14103,7 +14294,7 @@ async function cmdSpace(action, rest, json) {
|
|
|
14103
14294
|
async function cmdLegacyBenchmark(action, rest, json) {
|
|
14104
14295
|
initLogger3();
|
|
14105
14296
|
const configPath = resolveConfigPath();
|
|
14106
|
-
const raw =
|
|
14297
|
+
const raw = fs16.existsSync(configPath) ? JSON.parse(fs16.readFileSync(configPath, "utf8")) : {};
|
|
14107
14298
|
const remnicCfg = resolveRemnicConfigRecord6(raw);
|
|
14108
14299
|
const config = parseConfig7(remnicCfg);
|
|
14109
14300
|
const orchestrator = new Orchestrator4(config);
|
|
@@ -14508,7 +14699,7 @@ function readPid() {
|
|
|
14508
14699
|
function inferPort() {
|
|
14509
14700
|
try {
|
|
14510
14701
|
const configPath = resolveConfigPath();
|
|
14511
|
-
const raw = JSON.parse(
|
|
14702
|
+
const raw = JSON.parse(fs16.readFileSync(configPath, "utf8"));
|
|
14512
14703
|
return raw.server?.port ?? 4318;
|
|
14513
14704
|
} catch {
|
|
14514
14705
|
return 4318;
|
|
@@ -14603,13 +14794,13 @@ function daemonInstall() {
|
|
|
14603
14794
|
process.exit(1);
|
|
14604
14795
|
}
|
|
14605
14796
|
const vars = { HOME: home, NODE_PATH: nodePath, REMNIC_SERVER_BIN: serverBin };
|
|
14606
|
-
|
|
14797
|
+
fs16.mkdirSync(LOGS_DIR, { recursive: true });
|
|
14607
14798
|
if (isMacOS()) {
|
|
14608
14799
|
const templatePath = path18.resolve(import.meta.dirname, "../templates/launchd/ai.remnic.daemon.plist");
|
|
14609
|
-
const template =
|
|
14800
|
+
const template = fs16.readFileSync(templatePath, "utf8");
|
|
14610
14801
|
const plist = renderTemplate(template, vars);
|
|
14611
|
-
|
|
14612
|
-
|
|
14802
|
+
fs16.mkdirSync(path18.dirname(LAUNCHD_PLIST_PATH), { recursive: true });
|
|
14803
|
+
fs16.writeFileSync(LAUNCHD_PLIST_PATH, plist);
|
|
14613
14804
|
try {
|
|
14614
14805
|
launchdLoadPlist(LAUNCHD_PLIST_PATH);
|
|
14615
14806
|
} catch (err) {
|
|
@@ -14626,10 +14817,10 @@ function daemonInstall() {
|
|
|
14626
14817
|
console.log(` Logs: ${LOGS_DIR}/daemon.log`);
|
|
14627
14818
|
} else if (isLinux()) {
|
|
14628
14819
|
const templatePath = path18.resolve(import.meta.dirname, "../templates/systemd/remnic.service");
|
|
14629
|
-
const template =
|
|
14820
|
+
const template = fs16.readFileSync(templatePath, "utf8");
|
|
14630
14821
|
const unit = renderTemplate(template, vars);
|
|
14631
|
-
|
|
14632
|
-
|
|
14822
|
+
fs16.mkdirSync(path18.dirname(SYSTEMD_UNIT_PATH), { recursive: true });
|
|
14823
|
+
fs16.writeFileSync(SYSTEMD_UNIT_PATH, unit);
|
|
14633
14824
|
try {
|
|
14634
14825
|
childProcess2.execSync("systemctl --user daemon-reload", { stdio: "pipe" });
|
|
14635
14826
|
} catch (err) {
|
|
@@ -14665,7 +14856,7 @@ function daemonUninstall() {
|
|
|
14665
14856
|
} catch {
|
|
14666
14857
|
}
|
|
14667
14858
|
try {
|
|
14668
|
-
|
|
14859
|
+
fs16.unlinkSync(plistPath);
|
|
14669
14860
|
removed = true;
|
|
14670
14861
|
console.log(`Removed launchd service: ${plistPath}`);
|
|
14671
14862
|
} catch {
|
|
@@ -14685,7 +14876,7 @@ function daemonUninstall() {
|
|
|
14685
14876
|
let removed = false;
|
|
14686
14877
|
for (const unitPath of SYSTEMD_UNIT_PATHS) {
|
|
14687
14878
|
try {
|
|
14688
|
-
|
|
14879
|
+
fs16.unlinkSync(unitPath);
|
|
14689
14880
|
removed = true;
|
|
14690
14881
|
console.log(`Removed systemd service: ${unitPath}`);
|
|
14691
14882
|
} catch {
|
|
@@ -14752,11 +14943,11 @@ async function daemonStatus() {
|
|
|
14752
14943
|
console.log(` Port: ${port}`);
|
|
14753
14944
|
console.log(` Service: ${serviceInstalled ? "installed" : "not installed"}`);
|
|
14754
14945
|
console.log(` Platform: ${process.platform}`);
|
|
14755
|
-
console.log(` PID file: ${
|
|
14756
|
-
console.log(` Log file: ${
|
|
14946
|
+
console.log(` PID file: ${fs16.existsSync(PID_FILE) ? PID_FILE : LEGACY_PID_FILE}`);
|
|
14947
|
+
console.log(` Log file: ${fs16.existsSync(LOG_FILE) ? LOG_FILE : LEGACY_LOG_FILE}`);
|
|
14757
14948
|
try {
|
|
14758
14949
|
const configPath = resolveConfigPath();
|
|
14759
|
-
const raw =
|
|
14950
|
+
const raw = fs16.existsSync(configPath) ? JSON.parse(fs16.readFileSync(configPath, "utf8")) : {};
|
|
14760
14951
|
const remnicCfg = resolveRemnicConfigRecord6(raw);
|
|
14761
14952
|
const config = parseConfig7(remnicCfg);
|
|
14762
14953
|
const extRoot = resolveExtensionsRoot(config);
|
|
@@ -14797,9 +14988,9 @@ function daemonStart() {
|
|
|
14797
14988
|
return;
|
|
14798
14989
|
}
|
|
14799
14990
|
}
|
|
14800
|
-
|
|
14801
|
-
|
|
14802
|
-
const logStream =
|
|
14991
|
+
fs16.mkdirSync(PID_DIR, { recursive: true });
|
|
14992
|
+
fs16.mkdirSync(LOGS_DIR, { recursive: true });
|
|
14993
|
+
const logStream = fs16.openSync(LOG_FILE, "a");
|
|
14803
14994
|
const serverBin = resolveServerBin();
|
|
14804
14995
|
const isSource = serverBin.endsWith(".ts");
|
|
14805
14996
|
let cmd;
|
|
@@ -14821,7 +15012,7 @@ function daemonStart() {
|
|
|
14821
15012
|
}
|
|
14822
15013
|
});
|
|
14823
15014
|
child.unref();
|
|
14824
|
-
|
|
15015
|
+
fs16.writeFileSync(PID_FILE, String(child.pid));
|
|
14825
15016
|
console.log(`Started remnic server (pid ${child.pid})`);
|
|
14826
15017
|
console.log(` Log: ${LOG_FILE}`);
|
|
14827
15018
|
}
|
|
@@ -14855,11 +15046,11 @@ function daemonStop() {
|
|
|
14855
15046
|
console.log("Process not found (cleaning up PID file)");
|
|
14856
15047
|
}
|
|
14857
15048
|
try {
|
|
14858
|
-
|
|
15049
|
+
fs16.unlinkSync(PID_FILE);
|
|
14859
15050
|
} catch {
|
|
14860
15051
|
}
|
|
14861
15052
|
try {
|
|
14862
|
-
|
|
15053
|
+
fs16.unlinkSync(LEGACY_PID_FILE);
|
|
14863
15054
|
} catch {
|
|
14864
15055
|
}
|
|
14865
15056
|
}
|
|
@@ -14987,7 +15178,7 @@ async function promptYesNo(question, defaultYes = true) {
|
|
|
14987
15178
|
async function cmdBinary(rest) {
|
|
14988
15179
|
initLogger3();
|
|
14989
15180
|
const configPath = resolveConfigPath();
|
|
14990
|
-
const raw =
|
|
15181
|
+
const raw = fs16.existsSync(configPath) ? JSON.parse(fs16.readFileSync(configPath, "utf8")) : {};
|
|
14991
15182
|
const remnicCfg = resolveRemnicConfigRecord6(raw);
|
|
14992
15183
|
const config = parseConfig7(remnicCfg);
|
|
14993
15184
|
const memoryDir = resolveMemoryDir();
|
|
@@ -15178,7 +15369,7 @@ async function cmdOpenclawInstall(opts) {
|
|
|
15178
15369
|
} else if (slotIsActiveLegacy) {
|
|
15179
15370
|
changes.push(` Slot left as "${REMNIC_OPENCLAW_LEGACY_PLUGIN_ID}" \u2014 re-run with --yes to activate the new entry`);
|
|
15180
15371
|
}
|
|
15181
|
-
if (!
|
|
15372
|
+
if (!fs16.existsSync(memoryDir)) changes.push(`+ Will create memory directory: ${memoryDir}`);
|
|
15182
15373
|
if (hasLegacy && migrateLegacy) {
|
|
15183
15374
|
changes.push(`~ Legacy '${REMNIC_OPENCLAW_LEGACY_PLUGIN_ID}' entry retained (safe to remove after verifying hooks fire)`);
|
|
15184
15375
|
}
|
|
@@ -15198,8 +15389,8 @@ async function cmdOpenclawInstall(opts) {
|
|
|
15198
15389
|
Resulting plugins.slots.memory: ${dryRunPlugins.slots?.memory ?? "(unset)"}`);
|
|
15199
15390
|
return;
|
|
15200
15391
|
}
|
|
15201
|
-
if (
|
|
15202
|
-
const st =
|
|
15392
|
+
if (fs16.existsSync(memoryDir)) {
|
|
15393
|
+
const st = fs16.statSync(memoryDir);
|
|
15203
15394
|
if (!st.isDirectory()) {
|
|
15204
15395
|
throw new Error(
|
|
15205
15396
|
`Cannot use ${memoryDir} as the memory directory \u2014 a file already exists at that path.
|
|
@@ -15207,12 +15398,12 @@ Remove it first and re-run, or choose a different path with --memory-dir.`
|
|
|
15207
15398
|
);
|
|
15208
15399
|
}
|
|
15209
15400
|
} else {
|
|
15210
|
-
|
|
15401
|
+
fs16.mkdirSync(memoryDir, { recursive: true });
|
|
15211
15402
|
console.log(`Created memory directory: ${memoryDir}`);
|
|
15212
15403
|
}
|
|
15213
15404
|
const configDir = path18.dirname(configPath);
|
|
15214
|
-
if (!
|
|
15215
|
-
|
|
15405
|
+
if (!fs16.existsSync(configDir)) {
|
|
15406
|
+
fs16.mkdirSync(configDir, { recursive: true });
|
|
15216
15407
|
}
|
|
15217
15408
|
atomicWriteFileSync(configPath, JSON.stringify(updatedConfig, null, 2) + "\n");
|
|
15218
15409
|
console.log("\nDone! Summary of changes:");
|
|
@@ -15241,7 +15432,7 @@ async function cmdOpenclawUpgrade(opts) {
|
|
|
15241
15432
|
const legacyPluginDirForBackup = opts.legacyPluginDirForBackup ? resolveOpenclawLegacyPluginDir(opts.legacyPluginDirForBackup) : void 0;
|
|
15242
15433
|
const fallbackMemoryDir = path18.join(resolveOpenclawStateDir(), "workspace", "memory", "local");
|
|
15243
15434
|
const packageSpec = buildOpenclawManagedUpgradePackageSpec(opts.version);
|
|
15244
|
-
const configExistedBefore =
|
|
15435
|
+
const configExistedBefore = fs16.existsSync(configPath);
|
|
15245
15436
|
const existingConfig = readOpenclawConfig(configPath);
|
|
15246
15437
|
const { entries, slots } = parseOpenclawPluginState(existingConfig, configPath);
|
|
15247
15438
|
const preservedMemoryDir = opts.memoryDir ? path18.resolve(expandTilde(opts.memoryDir)) : resolveCurrentOpenclawMemoryDir(entries, slots, fallbackMemoryDir);
|
|
@@ -15466,13 +15657,13 @@ async function cmdOpenclawMigrateEngram(opts) {
|
|
|
15466
15657
|
}
|
|
15467
15658
|
function createOpenclawUpgradeBackupDir() {
|
|
15468
15659
|
const backupsRoot = path18.join(resolveOpenclawStateDir(), "backups");
|
|
15469
|
-
|
|
15470
|
-
return
|
|
15660
|
+
fs16.mkdirSync(backupsRoot, { recursive: true });
|
|
15661
|
+
return fs16.mkdtempSync(path18.join(backupsRoot, `remnic-openclaw-upgrade-${formatOpenclawUpgradeStamp()}-`));
|
|
15471
15662
|
}
|
|
15472
15663
|
async function cmdTaxonomy(rest) {
|
|
15473
15664
|
initLogger3();
|
|
15474
15665
|
const configPath = resolveConfigPath();
|
|
15475
|
-
const raw =
|
|
15666
|
+
const raw = fs16.existsSync(configPath) ? JSON.parse(fs16.readFileSync(configPath, "utf8")) : {};
|
|
15476
15667
|
const remnicCfg = resolveRemnicConfigRecord6(raw);
|
|
15477
15668
|
const config = parseConfig7(remnicCfg);
|
|
15478
15669
|
if (!config.taxonomyEnabled) {
|
|
@@ -15510,8 +15701,8 @@ async function cmdTaxonomy(rest) {
|
|
|
15510
15701
|
console.log(doc);
|
|
15511
15702
|
if (config.taxonomyAutoGenResolver) {
|
|
15512
15703
|
const resolverPath = path18.join(config.memoryDir, ".taxonomy", "RESOLVER.md");
|
|
15513
|
-
|
|
15514
|
-
|
|
15704
|
+
fs16.mkdirSync(path18.dirname(resolverPath), { recursive: true });
|
|
15705
|
+
fs16.writeFileSync(resolverPath, doc);
|
|
15515
15706
|
console.error(`Written: ${resolverPath}`);
|
|
15516
15707
|
}
|
|
15517
15708
|
break;
|
|
@@ -15557,7 +15748,7 @@ async function cmdTaxonomy(rest) {
|
|
|
15557
15748
|
if (config.taxonomyAutoGenResolver) {
|
|
15558
15749
|
const doc = generateResolverDocument(taxonomy);
|
|
15559
15750
|
const resolverPath = path18.join(config.memoryDir, ".taxonomy", "RESOLVER.md");
|
|
15560
|
-
|
|
15751
|
+
fs16.writeFileSync(resolverPath, doc);
|
|
15561
15752
|
console.error(`Regenerated: ${resolverPath}`);
|
|
15562
15753
|
}
|
|
15563
15754
|
break;
|
|
@@ -15588,7 +15779,7 @@ async function cmdTaxonomy(rest) {
|
|
|
15588
15779
|
if (config.taxonomyAutoGenResolver) {
|
|
15589
15780
|
const doc = generateResolverDocument(taxonomy);
|
|
15590
15781
|
const resolverPath = path18.join(config.memoryDir, ".taxonomy", "RESOLVER.md");
|
|
15591
|
-
|
|
15782
|
+
fs16.writeFileSync(resolverPath, doc);
|
|
15592
15783
|
console.error(`Regenerated: ${resolverPath}`);
|
|
15593
15784
|
}
|
|
15594
15785
|
break;
|
|
@@ -15779,12 +15970,12 @@ async function runTrainingExport(args, stdout = process.stdout) {
|
|
|
15779
15970
|
`Unknown training-export format "${args.format}". ${validList}`
|
|
15780
15971
|
);
|
|
15781
15972
|
}
|
|
15782
|
-
if (!
|
|
15973
|
+
if (!fs16.existsSync(args.memoryDir)) {
|
|
15783
15974
|
throw new Error(
|
|
15784
15975
|
`--memory-dir "${args.memoryDir}" does not exist. Provide the path to an existing memory directory.`
|
|
15785
15976
|
);
|
|
15786
15977
|
}
|
|
15787
|
-
if (!
|
|
15978
|
+
if (!fs16.statSync(args.memoryDir).isDirectory()) {
|
|
15788
15979
|
throw new Error(
|
|
15789
15980
|
`--memory-dir "${args.memoryDir}" is not a directory. Provide the path to a memory directory, not a file.`
|
|
15790
15981
|
);
|
|
@@ -15870,10 +16061,10 @@ async function runTrainingExport(args, stdout = process.stdout) {
|
|
|
15870
16061
|
}
|
|
15871
16062
|
const formatted = adapter.formatRecords(records);
|
|
15872
16063
|
const outDir = path18.dirname(args.output);
|
|
15873
|
-
|
|
16064
|
+
fs16.mkdirSync(outDir, { recursive: true });
|
|
15874
16065
|
const tmpPath = `${args.output}.tmp-${process.pid}-${Date.now()}`;
|
|
15875
|
-
|
|
15876
|
-
|
|
16066
|
+
fs16.writeFileSync(tmpPath, formatted, "utf-8");
|
|
16067
|
+
fs16.renameSync(tmpPath, args.output);
|
|
15877
16068
|
stdout.write(
|
|
15878
16069
|
`Exported ${records.length} records to ${args.output} (${adapter.name} format)
|
|
15879
16070
|
`
|
|
@@ -16045,7 +16236,7 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
16045
16236
|
}
|
|
16046
16237
|
}, 500);
|
|
16047
16238
|
};
|
|
16048
|
-
|
|
16239
|
+
fs16.watch(memoryDir, { recursive: true }, (_event, filename) => {
|
|
16049
16240
|
if (filename && filename.startsWith(".")) return;
|
|
16050
16241
|
rebuild();
|
|
16051
16242
|
});
|
|
@@ -16053,12 +16244,12 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
16053
16244
|
});
|
|
16054
16245
|
} else if (subAction === "validate") {
|
|
16055
16246
|
const treeDir = outputDir;
|
|
16056
|
-
if (!
|
|
16247
|
+
if (!fs16.existsSync(treeDir)) {
|
|
16057
16248
|
console.error(`Context tree not found at ${treeDir}. Run 'remnic tree generate' first.`);
|
|
16058
16249
|
process.exit(1);
|
|
16059
16250
|
}
|
|
16060
16251
|
const indexPath = path18.join(treeDir, "INDEX.md");
|
|
16061
|
-
if (!
|
|
16252
|
+
if (!fs16.existsSync(indexPath)) {
|
|
16062
16253
|
console.error(`INDEX.md missing in ${treeDir}. Tree may be corrupt \u2014 regenerate.`);
|
|
16063
16254
|
process.exit(1);
|
|
16064
16255
|
}
|
|
@@ -16240,7 +16431,7 @@ Other:
|
|
|
16240
16431
|
let wearablesService;
|
|
16241
16432
|
try {
|
|
16242
16433
|
const configPath = resolveConfigPath();
|
|
16243
|
-
const raw =
|
|
16434
|
+
const raw = fs16.existsSync(configPath) ? JSON.parse(fs16.readFileSync(configPath, "utf8")) : {};
|
|
16244
16435
|
const remnicCfg = resolveRemnicConfigRecord6(raw);
|
|
16245
16436
|
const config = parseConfig7(remnicCfg);
|
|
16246
16437
|
wearablesOrchestrator = new Orchestrator4(config);
|
|
@@ -16295,7 +16486,7 @@ Other:
|
|
|
16295
16486
|
const targetFactory = async () => {
|
|
16296
16487
|
if (!orchestratorSingleton) {
|
|
16297
16488
|
const configPath = resolveConfigPath();
|
|
16298
|
-
const raw =
|
|
16489
|
+
const raw = fs16.existsSync(configPath) ? JSON.parse(fs16.readFileSync(configPath, "utf8")) : {};
|
|
16299
16490
|
const remnicCfg = resolveRemnicConfigRecord6(raw);
|
|
16300
16491
|
const config = parseConfig7(remnicCfg);
|
|
16301
16492
|
orchestratorSingleton = new Orchestrator4(config);
|