@remnic/plugin-openclaw 9.57.3 → 9.57.5
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 +101 -46
- package/openclaw.plugin.json +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -5412,10 +5412,10 @@ function runHealthWorker(request, data) {
|
|
|
5412
5412
|
const READINESS_RETRY_MS = 250;
|
|
5413
5413
|
const view = new Int32Array(data.state);
|
|
5414
5414
|
let completed = false;
|
|
5415
|
-
function finish(ok, rejectedAuth = false) {
|
|
5415
|
+
function finish(ok, rejectedAuth = false, httpFailure = false) {
|
|
5416
5416
|
if (completed) return;
|
|
5417
5417
|
completed = true;
|
|
5418
|
-
Atomics.store(view, 0, ok ? 1 : rejectedAuth ? 3 : 2);
|
|
5418
|
+
Atomics.store(view, 0, ok ? 1 : rejectedAuth ? 3 : httpFailure ? 4 : 2);
|
|
5419
5419
|
Atomics.notify(view, 0);
|
|
5420
5420
|
}
|
|
5421
5421
|
function probe(pathname, fallbackPath) {
|
|
@@ -5480,7 +5480,7 @@ function runHealthWorker(request, data) {
|
|
|
5480
5480
|
} else if (statusCode === 401 || statusCode === 403) {
|
|
5481
5481
|
finish(false, true);
|
|
5482
5482
|
} else {
|
|
5483
|
-
finish(false);
|
|
5483
|
+
finish(false, false, true);
|
|
5484
5484
|
}
|
|
5485
5485
|
}
|
|
5486
5486
|
);
|
|
@@ -6256,8 +6256,11 @@ function coerceDaemonPort(value) {
|
|
|
6256
6256
|
}
|
|
6257
6257
|
var DAEMON_CAPTURE_BYTES = 1024;
|
|
6258
6258
|
function probeDaemonSync(options) {
|
|
6259
|
+
const auth = options.authToken === void 0 ? loadDaemonAuth(options.configPath) : { token: options.authToken, source: "daemon configuration" };
|
|
6259
6260
|
const { host, port, timeoutMs } = options;
|
|
6260
|
-
if (!host || !Number.isInteger(port) || port <= 0 || port > 65535)
|
|
6261
|
+
if (!host || !Number.isInteger(port) || port <= 0 || port > 65535) {
|
|
6262
|
+
return { ok: false, failure: "network" };
|
|
6263
|
+
}
|
|
6261
6264
|
const deadline = Date.now() + timeoutMs;
|
|
6262
6265
|
let worker;
|
|
6263
6266
|
try {
|
|
@@ -6272,7 +6275,7 @@ function probeDaemonSync(options) {
|
|
|
6272
6275
|
port,
|
|
6273
6276
|
path: options.path,
|
|
6274
6277
|
fallbackPath: options.fallbackPath,
|
|
6275
|
-
token:
|
|
6278
|
+
token: auth.token,
|
|
6276
6279
|
deadline,
|
|
6277
6280
|
state,
|
|
6278
6281
|
...capture ? { capture, captureField: options.captureField } : {}
|
|
@@ -6282,7 +6285,14 @@ function probeDaemonSync(options) {
|
|
|
6282
6285
|
Atomics.wait(view, 0, 0, Math.max(0, deadline - Date.now()));
|
|
6283
6286
|
const status = Atomics.load(view, 0);
|
|
6284
6287
|
if (status === 0) void worker.terminate();
|
|
6285
|
-
if (status !== 1)
|
|
6288
|
+
if (status !== 1) {
|
|
6289
|
+
const failure = status === 3 ? "auth" : status === 4 ? "http" : "network";
|
|
6290
|
+
return {
|
|
6291
|
+
ok: false,
|
|
6292
|
+
failure,
|
|
6293
|
+
...status === 3 ? { rejectedAuth: true, authSource: auth.source } : {}
|
|
6294
|
+
};
|
|
6295
|
+
}
|
|
6286
6296
|
if (!capture) return { ok: true };
|
|
6287
6297
|
const length = new DataView(capture).getUint32(0);
|
|
6288
6298
|
if (length === 0) return { ok: true };
|
|
@@ -6318,9 +6328,9 @@ function readDaemonMemoryDirSync(host, port, timeoutMs = DEFAULT_DAEMON_HEALTH_T
|
|
|
6318
6328
|
return {
|
|
6319
6329
|
healthy: probe.ok,
|
|
6320
6330
|
memoryDir: probe.captured,
|
|
6321
|
-
|
|
6322
|
-
|
|
6323
|
-
...probe.
|
|
6331
|
+
...probe.failure === void 0 ? {} : { failure: probe.failure },
|
|
6332
|
+
...probe.rejectedAuth === true ? { rejectedAuth: true } : {},
|
|
6333
|
+
...probe.authSource === void 0 ? {} : { authSource: probe.authSource }
|
|
6324
6334
|
};
|
|
6325
6335
|
}
|
|
6326
6336
|
function shouldProbeDaemonHealth(host) {
|
|
@@ -6509,7 +6519,8 @@ function detectDaemonBridgeMode(options) {
|
|
|
6509
6519
|
}
|
|
6510
6520
|
}
|
|
6511
6521
|
if (!health.healthy) {
|
|
6512
|
-
|
|
6522
|
+
const reason = health.failure === "auth" ? `daemon authentication failed at ${daemonHost}:${daemonPort} using ${health.authSource ?? "the configured credential"}` : health.failure === "http" ? `daemon health at ${daemonHost}:${daemonPort} returned an HTTP error; no healthy daemon` : `daemon network probe failed at ${daemonHost}:${daemonPort}; no healthy daemon`;
|
|
6523
|
+
options.onSkip?.(reason);
|
|
6513
6524
|
continue;
|
|
6514
6525
|
}
|
|
6515
6526
|
if (health.memoryDir === void 0) {
|
|
@@ -6609,7 +6620,9 @@ function selectedDaemonConfigPath() {
|
|
|
6609
6620
|
function isOpenClawTokenEntry(value) {
|
|
6610
6621
|
return value !== null && typeof value === "object" && "connector" in value && value.connector === "openclaw" && "token" in value && typeof value.token === "string";
|
|
6611
6622
|
}
|
|
6612
|
-
|
|
6623
|
+
var daemonAuthKey = (source, token) => `${source}\0${token}`;
|
|
6624
|
+
function loadDaemonAuth(configPath, excludedSources) {
|
|
6625
|
+
const excluded = (source, token) => excludedSources?.has(source) === true || excludedSources?.has(daemonAuthKey(source, token)) === true;
|
|
6613
6626
|
const environmentTokens = [
|
|
6614
6627
|
["OPENCLAW_REMNIC_ACCESS_TOKEN", readEnv("OPENCLAW_REMNIC_ACCESS_TOKEN")],
|
|
6615
6628
|
["REMNIC_AUTH_TOKEN", readEnv("REMNIC_AUTH_TOKEN")],
|
|
@@ -6617,7 +6630,7 @@ function loadDaemonAuth(configPath) {
|
|
|
6617
6630
|
["ENGRAM_AUTH_TOKEN", readEnv("ENGRAM_AUTH_TOKEN")]
|
|
6618
6631
|
];
|
|
6619
6632
|
for (const [source, token] of environmentTokens) {
|
|
6620
|
-
if (token) return { token, source };
|
|
6633
|
+
if (token && !excluded(source, token)) return { token, source };
|
|
6621
6634
|
}
|
|
6622
6635
|
const tokenStores = [
|
|
6623
6636
|
{ path: path6.join(resolveHomeDir2(), ".remnic", "tokens.json"), source: "remnic token store" },
|
|
@@ -6629,10 +6642,10 @@ function loadDaemonAuth(configPath) {
|
|
|
6629
6642
|
const store = JSON.parse(fs3.readFileSync(tokenStore.path, "utf8"));
|
|
6630
6643
|
const tokens = Array.isArray(store.tokens) ? store.tokens : [];
|
|
6631
6644
|
const openClawToken = tokens.find(isOpenClawTokenEntry)?.token;
|
|
6632
|
-
if (typeof openClawToken === "string" && openClawToken.length > 0) {
|
|
6645
|
+
if (typeof openClawToken === "string" && openClawToken.length > 0 && !excluded(tokenStore.source, openClawToken)) {
|
|
6633
6646
|
return { token: openClawToken, source: tokenStore.source };
|
|
6634
6647
|
}
|
|
6635
|
-
if (typeof store === "object" && store !== null && "openclaw" in store && typeof store.openclaw === "string" && store.openclaw.length > 0 && (store.openclaw.startsWith("remnic_") || store.openclaw.startsWith("engram_"))) {
|
|
6648
|
+
if (typeof store === "object" && store !== null && "openclaw" in store && typeof store.openclaw === "string" && store.openclaw.length > 0 && (store.openclaw.startsWith("remnic_") || store.openclaw.startsWith("engram_")) && !excluded(tokenStore.source, store.openclaw)) {
|
|
6636
6649
|
return { token: store.openclaw, source: tokenStore.source };
|
|
6637
6650
|
}
|
|
6638
6651
|
} catch {
|
|
@@ -6645,7 +6658,7 @@ function loadDaemonAuth(configPath) {
|
|
|
6645
6658
|
const raw = JSON.parse(fs3.readFileSync(candidate, "utf8"));
|
|
6646
6659
|
const server = raw?.server;
|
|
6647
6660
|
const token = server?.authToken;
|
|
6648
|
-
if (typeof token === "string" && token.length > 0) {
|
|
6661
|
+
if (typeof token === "string" && token.length > 0 && !excluded("daemon configuration", token)) {
|
|
6649
6662
|
return { token, source: "daemon configuration" };
|
|
6650
6663
|
}
|
|
6651
6664
|
} catch {
|
|
@@ -6655,15 +6668,24 @@ function loadDaemonAuth(configPath) {
|
|
|
6655
6668
|
}
|
|
6656
6669
|
return { token: "", source: "no configured token" };
|
|
6657
6670
|
}
|
|
6658
|
-
|
|
6659
|
-
if (
|
|
6671
|
+
function classifyDaemonHealthStatus(status, tokenSource) {
|
|
6672
|
+
if (status === 200) return { ok: true };
|
|
6673
|
+
if (status === 401 || status === 403) {
|
|
6674
|
+
return { ok: false, failure: "auth", status, tokenSource };
|
|
6675
|
+
}
|
|
6676
|
+
if (status === void 0) return { ok: false, failure: "network" };
|
|
6677
|
+
return { ok: false, failure: "http", status };
|
|
6678
|
+
}
|
|
6679
|
+
async function checkDaemonHealthDetailed(host, port, timeoutMs = DEFAULT_DAEMON_HEALTH_TIMEOUT_MS) {
|
|
6680
|
+
if (!host || !Number.isInteger(port) || port <= 0 || port > 65535) {
|
|
6681
|
+
return { ok: false, failure: "network" };
|
|
6682
|
+
}
|
|
6660
6683
|
const deadline = Date.now() + timeoutMs;
|
|
6661
6684
|
try {
|
|
6662
6685
|
const { request } = await import("http");
|
|
6663
|
-
|
|
6664
|
-
const
|
|
6665
|
-
|
|
6666
|
-
const probe = (requestPath) => new Promise((resolve) => {
|
|
6686
|
+
let auth = loadDaemonAuth();
|
|
6687
|
+
const fallbackAuth = auth.token === "" ? void 0 : loadDaemonAuth(void 0, /* @__PURE__ */ new Set([auth.source]));
|
|
6688
|
+
const probe = (requestPath, token) => new Promise((resolve) => {
|
|
6667
6689
|
const remainingMs = deadline - Date.now();
|
|
6668
6690
|
if (remainingMs <= 0) {
|
|
6669
6691
|
resolve(void 0);
|
|
@@ -6675,6 +6697,8 @@ async function checkDaemonHealth(host, port, timeoutMs = DEFAULT_DAEMON_HEALTH_T
|
|
|
6675
6697
|
settled = true;
|
|
6676
6698
|
resolve(statusCode);
|
|
6677
6699
|
};
|
|
6700
|
+
const headers = {};
|
|
6701
|
+
if (token) headers.Authorization = `Bearer ${token}`;
|
|
6678
6702
|
const req = request(
|
|
6679
6703
|
{ hostname: host, port, path: requestPath, method: "GET", timeout: remainingMs, headers },
|
|
6680
6704
|
(res) => {
|
|
@@ -6689,14 +6713,28 @@ async function checkDaemonHealth(host, port, timeoutMs = DEFAULT_DAEMON_HEALTH_T
|
|
|
6689
6713
|
});
|
|
6690
6714
|
req.end();
|
|
6691
6715
|
});
|
|
6692
|
-
const
|
|
6693
|
-
|
|
6694
|
-
|
|
6695
|
-
|
|
6716
|
+
const probeWithFallback = async (requestPath) => {
|
|
6717
|
+
let status = await probe(requestPath, auth.token);
|
|
6718
|
+
if ((status === 401 || status === 403) && fallbackAuth?.token && fallbackAuth.token !== auth.token) {
|
|
6719
|
+
auth = fallbackAuth;
|
|
6720
|
+
status = await probe(requestPath, auth.token);
|
|
6721
|
+
}
|
|
6722
|
+
return status;
|
|
6723
|
+
};
|
|
6724
|
+
const livenessStatus = await probeWithFallback(LIVENESS_PATH);
|
|
6725
|
+
if (livenessStatus === 200) return { ok: true };
|
|
6726
|
+
if (livenessStatus !== 404) return classifyDaemonHealthStatus(livenessStatus, auth.source);
|
|
6727
|
+
return classifyDaemonHealthStatus(
|
|
6728
|
+
await probeWithFallback(LEGACY_HEALTH_PATH),
|
|
6729
|
+
auth.source
|
|
6730
|
+
);
|
|
6696
6731
|
} catch {
|
|
6697
|
-
return false;
|
|
6732
|
+
return { ok: false, failure: "network" };
|
|
6698
6733
|
}
|
|
6699
6734
|
}
|
|
6735
|
+
async function checkDaemonHealth(host, port, timeoutMs = DEFAULT_DAEMON_HEALTH_TIMEOUT_MS) {
|
|
6736
|
+
return (await checkDaemonHealthDetailed(host, port, timeoutMs)).ok;
|
|
6737
|
+
}
|
|
6700
6738
|
|
|
6701
6739
|
// src/delegate-authorization.ts
|
|
6702
6740
|
var DEFAULT_DELEGATE_AUTHORIZATION_OPERATIONS = [
|
|
@@ -6824,32 +6862,37 @@ async function lifecycleSessionNamespacesFrom(sessionKey, event, ctx, fallback,
|
|
|
6824
6862
|
|
|
6825
6863
|
// src/delegate-daemon-target.ts
|
|
6826
6864
|
function daemonTargetFor(bridge) {
|
|
6865
|
+
const invalidatedCredentials = /* @__PURE__ */ new Set();
|
|
6866
|
+
const invalidated = (token) => invalidatedCredentials.has(`daemon configuration\0${token}`);
|
|
6827
6867
|
return {
|
|
6828
6868
|
host: bridge.daemonHost,
|
|
6829
6869
|
port: bridge.daemonPort,
|
|
6870
|
+
invalidateAuthToken: (auth) => {
|
|
6871
|
+
invalidatedCredentials.add(`${auth.source}\0${auth.token}`);
|
|
6872
|
+
},
|
|
6830
6873
|
resolveAuthToken: () => {
|
|
6831
|
-
if (bridge.daemonAuthTokenOverride !== void 0) {
|
|
6874
|
+
if (bridge.daemonAuthTokenOverride !== void 0 && !invalidated(bridge.daemonAuthTokenOverride)) {
|
|
6832
6875
|
const unit = bridge.daemonAuthUnit === void 0 ? void 0 : readUnitAuthToken(bridge.daemonAuthUnit);
|
|
6833
|
-
if (unit?.readable === true && unit.token !== void 0) {
|
|
6876
|
+
if (unit?.readable === true && unit.token !== void 0 && !invalidated(unit.token)) {
|
|
6834
6877
|
return { token: unit.token, source: "daemon configuration" };
|
|
6835
6878
|
}
|
|
6836
|
-
if (unit === void 0 || unit.readable === false) {
|
|
6879
|
+
if ((unit === void 0 || unit.readable === false) && !invalidated(bridge.daemonAuthTokenOverride)) {
|
|
6837
6880
|
return { token: bridge.daemonAuthTokenOverride, source: "daemon configuration" };
|
|
6838
6881
|
}
|
|
6839
6882
|
if (bridge.daemonConfigPath !== void 0) {
|
|
6840
6883
|
const configToken = readDaemonConfigAuthToken(bridge.daemonConfigPath);
|
|
6841
|
-
if (configToken !== void 0) {
|
|
6884
|
+
if (configToken !== void 0 && !invalidated(configToken)) {
|
|
6842
6885
|
return { token: configToken, source: "daemon configuration" };
|
|
6843
6886
|
}
|
|
6844
6887
|
}
|
|
6845
6888
|
}
|
|
6846
6889
|
if (bridge.daemonAuthPrefersConfig && bridge.daemonConfigPath !== void 0) {
|
|
6847
6890
|
const configToken = readDaemonConfigAuthToken(bridge.daemonConfigPath);
|
|
6848
|
-
if (configToken !== void 0) {
|
|
6891
|
+
if (configToken !== void 0 && !invalidated(configToken)) {
|
|
6849
6892
|
return { token: configToken, source: "daemon configuration" };
|
|
6850
6893
|
}
|
|
6851
6894
|
}
|
|
6852
|
-
return loadDaemonAuth(bridge.daemonConfigPath);
|
|
6895
|
+
return loadDaemonAuth(bridge.daemonConfigPath, invalidatedCredentials);
|
|
6853
6896
|
}
|
|
6854
6897
|
};
|
|
6855
6898
|
}
|
|
@@ -6892,15 +6935,33 @@ async function noteRefusal(res, serviceId, pathname, source) {
|
|
|
6892
6935
|
}
|
|
6893
6936
|
return { status: res.status, body: null };
|
|
6894
6937
|
}
|
|
6895
|
-
async function
|
|
6896
|
-
const
|
|
6938
|
+
async function fetchWithAuthRetry(target, pathname, timeoutMs, init = {}) {
|
|
6939
|
+
const deadline = Date.now() + timeoutMs;
|
|
6940
|
+
const request = async (auth2) => {
|
|
6941
|
+
const remainingMs = deadline - Date.now();
|
|
6942
|
+
if (remainingMs <= 0) throw new Error("daemon request deadline exceeded");
|
|
6943
|
+
const headers = new Headers(init.headers);
|
|
6944
|
+
if (auth2.token) headers.set("Authorization", `Bearer ${auth2.token}`);
|
|
6945
|
+
return fetch(daemonUrl(target, pathname), {
|
|
6946
|
+
...init,
|
|
6947
|
+
headers,
|
|
6948
|
+
signal: AbortSignal.timeout(remainingMs)
|
|
6949
|
+
});
|
|
6950
|
+
};
|
|
6897
6951
|
const auth = target.resolveAuthToken();
|
|
6898
|
-
|
|
6899
|
-
|
|
6952
|
+
const response = await request(auth);
|
|
6953
|
+
if (response.status !== 401) return { response, auth };
|
|
6954
|
+
await response.body?.cancel();
|
|
6955
|
+
target.invalidateAuthToken?.(auth);
|
|
6956
|
+
const refreshedAuth = target.resolveAuthToken();
|
|
6957
|
+
if (refreshedAuth.token === auth.token) return { response, auth };
|
|
6958
|
+
return { response: await request(refreshedAuth), auth: refreshedAuth };
|
|
6959
|
+
}
|
|
6960
|
+
async function postJsonWithStatus(target, serviceId, pathname, body, timeoutMs) {
|
|
6961
|
+
const { response: res, auth } = await fetchWithAuthRetry(target, pathname, timeoutMs, {
|
|
6900
6962
|
method: "POST",
|
|
6901
|
-
headers,
|
|
6902
|
-
body: JSON.stringify(body)
|
|
6903
|
-
signal: AbortSignal.timeout(timeoutMs)
|
|
6963
|
+
headers: { "Content-Type": "application/json" },
|
|
6964
|
+
body: JSON.stringify(body)
|
|
6904
6965
|
});
|
|
6905
6966
|
if (!res.ok) return noteRefusal(res, serviceId, pathname, auth.source);
|
|
6906
6967
|
return { status: res.status, body: await readJsonObject(res) };
|
|
@@ -6914,13 +6975,7 @@ async function postJson(target, serviceId, pathname, body, timeoutMs) {
|
|
|
6914
6975
|
return response.body;
|
|
6915
6976
|
}
|
|
6916
6977
|
async function getJson(target, serviceId, pathname, timeoutMs) {
|
|
6917
|
-
const
|
|
6918
|
-
const auth = target.resolveAuthToken();
|
|
6919
|
-
if (auth.token) headers.Authorization = `Bearer ${auth.token}`;
|
|
6920
|
-
const res = await fetch(daemonUrl(target, pathname), {
|
|
6921
|
-
headers,
|
|
6922
|
-
signal: AbortSignal.timeout(timeoutMs)
|
|
6923
|
-
});
|
|
6978
|
+
const { response: res, auth } = await fetchWithAuthRetry(target, pathname, timeoutMs);
|
|
6924
6979
|
if (!res.ok) return noteRefusal(res, serviceId, pathname, auth.source);
|
|
6925
6980
|
return { status: res.status, body: await readJsonObject(res) };
|
|
6926
6981
|
}
|