fix: clean up Hermes-visible OpenClaw leftovers (#97)
* cleanup openclaw session leftovers - hermes can breathe now * fix: load hermes adapter env from .env * fix: redact secrets from hermes adapter error output * addressed review findings * address luke findings #2
This commit is contained in:
@@ -27,6 +27,35 @@ const fs = require("fs");
|
||||
const path = require("path");
|
||||
const { WebSocketServer } = require("ws");
|
||||
|
||||
function loadDotenvFile(filePath) {
|
||||
if (!fs.existsSync(filePath)) return;
|
||||
const content = fs.readFileSync(filePath, "utf8");
|
||||
for (const rawLine of content.split(/\r?\n/)) {
|
||||
const line = rawLine.trim();
|
||||
if (!line || line.startsWith("#")) continue;
|
||||
const match = line.match(/^([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)$/);
|
||||
if (!match) continue;
|
||||
const [, key, rawValue] = match;
|
||||
if (process.env[key] !== undefined) continue;
|
||||
let value = rawValue.trim();
|
||||
if (
|
||||
(value.startsWith('"') && value.endsWith('"')) ||
|
||||
(value.startsWith("'") && value.endsWith("'"))
|
||||
) {
|
||||
value = value.slice(1, -1);
|
||||
}
|
||||
process.env[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
function loadRuntimeEnv() {
|
||||
const cwd = process.cwd();
|
||||
loadDotenvFile(path.join(cwd, ".env.local"));
|
||||
loadDotenvFile(path.join(cwd, ".env"));
|
||||
}
|
||||
|
||||
loadRuntimeEnv();
|
||||
|
||||
const HERMES_API_URL = (process.env.HERMES_API_URL || "http://localhost:8642").replace(/\/$/, "");
|
||||
const HERMES_API_KEY = process.env.HERMES_API_KEY || "";
|
||||
const ADAPTER_PORT = parseInt(process.env.HERMES_ADAPTER_PORT || "18789", 10);
|
||||
@@ -227,7 +256,7 @@ function loadHistoryFromDisk() {
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn("[hermes-adapter] Could not load history:", err.message);
|
||||
console.warn("[hermes-adapter] Could not load history:", sanitizeErrorMessage(err));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -242,7 +271,7 @@ function saveHistoryToDisk() {
|
||||
fs.mkdirSync(path.dirname(HISTORY_FILE), { recursive: true });
|
||||
fs.writeFileSync(HISTORY_FILE, JSON.stringify(data, null, 2), "utf8");
|
||||
} catch (err) {
|
||||
console.warn("[hermes-adapter] Could not save history:", err.message);
|
||||
console.warn("[hermes-adapter] Could not save history:", sanitizeErrorMessage(err));
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
@@ -261,6 +290,17 @@ function randomId() {
|
||||
return require("crypto").randomBytes(8).toString("hex");
|
||||
}
|
||||
|
||||
function redactSecrets(value) {
|
||||
if (typeof value !== "string" || !value) return value;
|
||||
let redacted = value;
|
||||
if (HERMES_API_KEY) {
|
||||
redacted = redacted.split(HERMES_API_KEY).join("[REDACTED]");
|
||||
}
|
||||
redacted = redacted.replace(/Bearer\s+[A-Za-z0-9._~+/=-]+/gi, "Bearer [REDACTED]");
|
||||
redacted = redacted.replace(/\b\d{8,12}:[A-Za-z0-9_-]{20,}\b/g, "[REDACTED]");
|
||||
return redacted;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Hermes HTTP API helpers
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -311,6 +351,12 @@ async function readJsonBody(res) {
|
||||
return JSON.parse(raw);
|
||||
}
|
||||
|
||||
function sanitizeErrorMessage(error) {
|
||||
if (!error) return "Unknown error";
|
||||
if (typeof error === "string") return redactSecrets(error);
|
||||
return redactSecrets(error.message || String(error));
|
||||
}
|
||||
|
||||
function extractOpenAiStyleError(payload, fallbackMessage) {
|
||||
if (payload && typeof payload === "object") {
|
||||
const message =
|
||||
@@ -607,8 +653,9 @@ async function execDelegateTask(args) {
|
||||
byAgent: [{ agentId: targetId, recent: [{ key: sessionKey, updatedAt: Date.now() }] }] } },
|
||||
});
|
||||
} catch (err) {
|
||||
emitSub("error", { errorMessage: err.message });
|
||||
return JSON.stringify({ ok: false, error: err.message });
|
||||
const message = sanitizeErrorMessage(err);
|
||||
emitSub("error", { errorMessage: message });
|
||||
return JSON.stringify({ ok: false, error: message });
|
||||
}
|
||||
|
||||
return JSON.stringify({ ok: true, agent_id: targetId, response: responseText });
|
||||
@@ -962,7 +1009,7 @@ async function handleMethod(method, params, id, sendEvent) {
|
||||
byAgent: [{ agentId: sessionAgentId, recent: [{ key: sessionKey, updatedAt: Date.now() }] }] } } });
|
||||
}
|
||||
} catch (err) {
|
||||
if (!aborted) emitChat("error", { errorMessage: err.message || "Hermes API error" });
|
||||
if (!aborted) emitChat("error", { errorMessage: sanitizeErrorMessage(err) || "Hermes API error" });
|
||||
else emitChat("aborted", {});
|
||||
} finally {
|
||||
activeRuns.delete(runId);
|
||||
@@ -1134,7 +1181,7 @@ function startAdapter() {
|
||||
|
||||
const wss = new WebSocketServer({ server: httpServer });
|
||||
wss.on("error", (err) => {
|
||||
if (err.code !== "EADDRINUSE") console.error("[hermes-adapter] Server error:", err.message);
|
||||
if (err.code !== "EADDRINUSE") console.error("[hermes-adapter] Server error:", sanitizeErrorMessage(err));
|
||||
});
|
||||
|
||||
wss.on("connection", (ws) => {
|
||||
@@ -1144,7 +1191,7 @@ function startAdapter() {
|
||||
const send = (frame) => {
|
||||
if (ws.readyState === ws.OPEN) {
|
||||
try { ws.send(JSON.stringify(frame)); }
|
||||
catch (e) { console.error("[hermes-adapter] send error:", e.message); }
|
||||
catch (e) { console.error("[hermes-adapter] send error:", sanitizeErrorMessage(e)); }
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1197,14 +1244,15 @@ function startAdapter() {
|
||||
const response = await handleMethod(method, params, id, sendEventFn);
|
||||
send(response);
|
||||
} catch (err) {
|
||||
console.error(`[hermes-adapter] Error handling ${method}:`, err.message);
|
||||
send(resErr(id, "internal_error", err.message || "Internal error"));
|
||||
const message = sanitizeErrorMessage(err);
|
||||
console.error(`[hermes-adapter] Error handling ${method}:`, message);
|
||||
send(resErr(id, "internal_error", message || "Internal error"));
|
||||
}
|
||||
});
|
||||
|
||||
ws.on("close", () => activeSendEventFns.delete(sendEventFn));
|
||||
ws.on("error", (err) => {
|
||||
console.error("[hermes-adapter] WebSocket error:", err.message);
|
||||
console.error("[hermes-adapter] WebSocket error:", sanitizeErrorMessage(err));
|
||||
activeSendEventFns.delete(sendEventFn);
|
||||
});
|
||||
});
|
||||
@@ -1221,7 +1269,7 @@ function startAdapter() {
|
||||
if (err.code === "EADDRINUSE") {
|
||||
console.error(`[hermes-adapter] Port ${ADAPTER_PORT} in use. Set HERMES_ADAPTER_PORT to change it.`);
|
||||
} else {
|
||||
console.error("[hermes-adapter] Server error:", err.message);
|
||||
console.error("[hermes-adapter] Server error:", sanitizeErrorMessage(err));
|
||||
}
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user