chore: remove dead macos relay and daemon code

This commit is contained in:
Peter Steinberger
2026-02-22 09:35:21 +01:00
parent c99e7696e6
commit 902544cf2d
4 changed files with 0 additions and 452 deletions

View File

@@ -1,279 +0,0 @@
#!/usr/bin/env node
import process from "node:process";
import type { GatewayLockHandle } from "../infra/gateway-lock.js";
import { restartGatewayProcessWithFreshPid } from "../infra/process-respawn.js";
declare const __OPENCLAW_VERSION__: string | undefined;
const BUNDLED_VERSION =
(typeof __OPENCLAW_VERSION__ === "string" && __OPENCLAW_VERSION__) ||
process.env.OPENCLAW_BUNDLED_VERSION ||
"0.0.0";
function argValue(args: string[], flag: string): string | undefined {
const idx = args.indexOf(flag);
if (idx < 0) {
return undefined;
}
const value = args[idx + 1];
return value && !value.startsWith("-") ? value : undefined;
}
function hasFlag(args: string[], flag: string): boolean {
return args.includes(flag);
}
const args = process.argv.slice(2);
type GatewayWsLogStyle = "auto" | "full" | "compact";
async function main() {
if (hasFlag(args, "--version") || hasFlag(args, "-v")) {
// Match `openclaw --version` behavior for Swift env/version checks.
// Keep output a single line.
console.log(BUNDLED_VERSION);
process.exit(0);
}
// Bun runtime ships a global `Long` that protobufjs detects, but it does not
// implement the long.js API that Baileys/WAProto expects (fromBits, ...).
// Ensure we use long.js so the embedded gateway doesn't crash at startup.
if (typeof process.versions.bun === "string") {
const mod = await import("long");
const Long = (mod as unknown as { default?: unknown }).default ?? mod;
(globalThis as unknown as { Long?: unknown }).Long = Long;
}
const [
{ loadConfig },
{ startGatewayServer },
{ setGatewayWsLogStyle },
{ setVerbose },
{ acquireGatewayLock, GatewayLockError },
{
consumeGatewaySigusr1RestartAuthorization,
isGatewaySigusr1RestartExternallyAllowed,
markGatewaySigusr1RestartHandled,
},
{ defaultRuntime },
{ enableConsoleCapture, setConsoleTimestampPrefix },
commandQueueMod,
{ createRestartIterationHook },
] = await Promise.all([
import("../config/config.js"),
import("../gateway/server.js"),
import("../gateway/ws-logging.js"),
import("../globals.js"),
import("../infra/gateway-lock.js"),
import("../infra/restart.js"),
import("../runtime.js"),
import("../logging.js"),
import("../process/command-queue.js"),
import("../process/restart-recovery.js"),
] as const);
enableConsoleCapture();
setConsoleTimestampPrefix(true);
setVerbose(hasFlag(args, "--verbose"));
const wsLogRaw = hasFlag(args, "--compact") ? "compact" : argValue(args, "--ws-log");
const wsLogStyle: GatewayWsLogStyle =
wsLogRaw === "compact" ? "compact" : wsLogRaw === "full" ? "full" : "auto";
setGatewayWsLogStyle(wsLogStyle);
const cfg = loadConfig();
const portRaw =
argValue(args, "--port") ??
process.env.OPENCLAW_GATEWAY_PORT ??
process.env.CLAWDBOT_GATEWAY_PORT ??
(typeof cfg.gateway?.port === "number" ? String(cfg.gateway.port) : "") ??
"18789";
const port = Number.parseInt(portRaw, 10);
if (Number.isNaN(port) || port <= 0) {
defaultRuntime.error(`Invalid --port (${portRaw})`);
process.exit(1);
}
const bindRaw =
argValue(args, "--bind") ??
process.env.OPENCLAW_GATEWAY_BIND ??
process.env.CLAWDBOT_GATEWAY_BIND ??
cfg.gateway?.bind ??
"loopback";
const bind =
bindRaw === "loopback" ||
bindRaw === "lan" ||
bindRaw === "auto" ||
bindRaw === "custom" ||
bindRaw === "tailnet"
? bindRaw
: null;
if (!bind) {
defaultRuntime.error('Invalid --bind (use "loopback", "lan", "tailnet", "auto", or "custom")');
process.exit(1);
}
const token = argValue(args, "--token");
if (token) {
process.env.OPENCLAW_GATEWAY_TOKEN = token;
}
let server: Awaited<ReturnType<typeof startGatewayServer>> | null = null;
let lock: GatewayLockHandle | null = null;
let shuttingDown = false;
let forceExitTimer: ReturnType<typeof setTimeout> | null = null;
let restartResolver: (() => void) | null = null;
const cleanupSignals = () => {
process.removeListener("SIGTERM", onSigterm);
process.removeListener("SIGINT", onSigint);
process.removeListener("SIGUSR1", onSigusr1);
};
const request = (action: "stop" | "restart", signal: string) => {
if (shuttingDown) {
defaultRuntime.log(`gateway: received ${signal} during shutdown; ignoring`);
return;
}
shuttingDown = true;
const isRestart = action === "restart";
defaultRuntime.log(
`gateway: received ${signal}; ${isRestart ? "restarting" : "shutting down"}`,
);
const DRAIN_TIMEOUT_MS = 30_000;
const SHUTDOWN_TIMEOUT_MS = 5_000;
const forceExitMs = isRestart ? DRAIN_TIMEOUT_MS + SHUTDOWN_TIMEOUT_MS : SHUTDOWN_TIMEOUT_MS;
forceExitTimer = setTimeout(() => {
defaultRuntime.error("gateway: shutdown timed out; exiting without full cleanup");
cleanupSignals();
process.exit(0);
}, forceExitMs);
void (async () => {
try {
if (isRestart) {
const activeTasks = commandQueueMod.getActiveTaskCount();
if (activeTasks > 0) {
defaultRuntime.log(
`gateway: draining ${activeTasks} active task(s) before restart (timeout ${DRAIN_TIMEOUT_MS}ms)`,
);
const { drained } = await commandQueueMod.waitForActiveTasks(DRAIN_TIMEOUT_MS);
if (drained) {
defaultRuntime.log("gateway: all active tasks drained");
} else {
defaultRuntime.log("gateway: drain timeout reached; proceeding with restart");
}
}
}
await server?.close({
reason: isRestart ? "gateway restarting" : "gateway stopping",
restartExpectedMs: isRestart ? 1500 : null,
});
} catch (err) {
defaultRuntime.error(`gateway: shutdown error: ${String(err)}`);
} finally {
if (forceExitTimer) {
clearTimeout(forceExitTimer);
}
server = null;
if (isRestart) {
const respawn = restartGatewayProcessWithFreshPid();
if (respawn.mode === "spawned" || respawn.mode === "supervised") {
const modeLabel =
respawn.mode === "spawned"
? `spawned pid ${respawn.pid ?? "unknown"}`
: "supervisor restart";
defaultRuntime.log(`gateway: restart mode full process restart (${modeLabel})`);
cleanupSignals();
process.exit(0);
} else {
if (respawn.mode === "failed") {
defaultRuntime.log(
`gateway: full process restart failed (${respawn.detail ?? "unknown error"}); falling back to in-process restart`,
);
} else {
defaultRuntime.log("gateway: restart mode in-process restart (OPENCLAW_NO_RESPAWN)");
}
shuttingDown = false;
restartResolver?.();
}
} else {
cleanupSignals();
process.exit(0);
}
}
})();
};
const onSigterm = () => {
defaultRuntime.log("gateway: signal SIGTERM received");
request("stop", "SIGTERM");
};
const onSigint = () => {
defaultRuntime.log("gateway: signal SIGINT received");
request("stop", "SIGINT");
};
const onSigusr1 = () => {
defaultRuntime.log("gateway: signal SIGUSR1 received");
const authorized = consumeGatewaySigusr1RestartAuthorization();
if (!authorized && !isGatewaySigusr1RestartExternallyAllowed()) {
defaultRuntime.log(
"gateway: SIGUSR1 restart ignored (not authorized; commands.restart=false or use gateway tool).",
);
return;
}
markGatewaySigusr1RestartHandled();
request("restart", "SIGUSR1");
};
process.on("SIGTERM", onSigterm);
process.on("SIGINT", onSigint);
process.on("SIGUSR1", onSigusr1);
try {
try {
lock = await acquireGatewayLock();
} catch (err) {
if (err instanceof GatewayLockError) {
defaultRuntime.error(`Gateway start blocked: ${err.message}`);
process.exit(1);
}
throw err;
}
const onIteration = createRestartIterationHook(() => {
// After an in-process restart (SIGUSR1), reset command-queue lane state.
// Interrupted tasks from the previous lifecycle may have left `active`
// counts elevated (their finally blocks never ran), permanently blocking
// new work from draining.
commandQueueMod.resetAllLanes();
});
// eslint-disable-next-line no-constant-condition
while (true) {
onIteration();
try {
server = await startGatewayServer(port, { bind });
} catch (err) {
cleanupSignals();
defaultRuntime.error(`Gateway failed to start: ${String(err)}`);
process.exit(1);
}
await new Promise<void>((resolve) => {
restartResolver = resolve;
});
}
} finally {
await lock?.release();
cleanupSignals();
}
}
void main().catch((err) => {
console.error(
"[openclaw] Gateway daemon failed:",
err instanceof Error ? (err.stack ?? err.message) : err,
);
process.exit(1);
});

View File

@@ -1,54 +0,0 @@
import { describe, expect, it, vi } from "vitest";
import { parseRelaySmokeTest, runRelaySmokeTest } from "./relay-smoke.js";
vi.mock("../web/qr-image.js", () => ({
renderQrPngBase64: vi.fn(async () => "base64"),
}));
describe("parseRelaySmokeTest", () => {
it("parses --smoke qr", () => {
expect(parseRelaySmokeTest(["--smoke", "qr"], {})).toBe("qr");
});
it("rejects --smoke without a value", () => {
expect(() => parseRelaySmokeTest(["--smoke"], {})).toThrow(
"Missing value for --smoke (expected: qr)",
);
});
it("rejects --smoke when the next arg is another flag", () => {
expect(() => parseRelaySmokeTest(["--smoke", "--smoke-qr"], {})).toThrow(
"Missing value for --smoke (expected: qr)",
);
});
it("parses --smoke-qr", () => {
expect(parseRelaySmokeTest(["--smoke-qr"], {})).toBe("qr");
});
it("parses env var smoke mode only when no args", () => {
expect(parseRelaySmokeTest([], { OPENCLAW_SMOKE_QR: "1" })).toBe("qr");
expect(parseRelaySmokeTest(["send"], { OPENCLAW_SMOKE_QR: "1" })).toBe(null);
});
it("supports OPENCLAW_SMOKE=qr only when no args", () => {
expect(parseRelaySmokeTest([], { OPENCLAW_SMOKE: "qr" })).toBe("qr");
expect(parseRelaySmokeTest(["send"], { OPENCLAW_SMOKE: "qr" })).toBe(null);
});
it("rejects unknown smoke values", () => {
expect(() => parseRelaySmokeTest(["--smoke", "nope"], {})).toThrow("Unknown smoke test");
});
it("prefers explicit --smoke over env vars", () => {
expect(parseRelaySmokeTest(["--smoke", "qr"], { OPENCLAW_SMOKE: "nope" })).toBe("qr");
});
});
describe("runRelaySmokeTest", () => {
it("runs qr smoke test", async () => {
await runRelaySmokeTest("qr");
const mod = await import("../web/qr-image.js");
expect(mod.renderQrPngBase64).toHaveBeenCalledWith("smoke-test");
});
});

View File

@@ -1,37 +0,0 @@
export type RelaySmokeTest = "qr";
export function parseRelaySmokeTest(args: string[], env: NodeJS.ProcessEnv): RelaySmokeTest | null {
const smokeIdx = args.indexOf("--smoke");
if (smokeIdx !== -1) {
const value = args[smokeIdx + 1];
if (!value || value.startsWith("-")) {
throw new Error("Missing value for --smoke (expected: qr)");
}
if (value === "qr") {
return "qr";
}
throw new Error(`Unknown smoke test: ${value}`);
}
if (args.includes("--smoke-qr")) {
return "qr";
}
// Back-compat: only run env-based smoke mode when no CLI args are present,
// to avoid surprising early-exit when users set env vars globally.
if (args.length === 0 && (env.OPENCLAW_SMOKE_QR === "1" || env.OPENCLAW_SMOKE === "qr")) {
return "qr";
}
return null;
}
export async function runRelaySmokeTest(test: RelaySmokeTest): Promise<void> {
switch (test) {
case "qr": {
const { renderQrPngBase64 } = await import("../web/qr-image.js");
await renderQrPngBase64("smoke-test");
return;
}
}
}

View File

@@ -1,82 +0,0 @@
#!/usr/bin/env node
import process from "node:process";
declare const __OPENCLAW_VERSION__: string | undefined;
const BUNDLED_VERSION =
(typeof __OPENCLAW_VERSION__ === "string" && __OPENCLAW_VERSION__) ||
process.env.OPENCLAW_BUNDLED_VERSION ||
"0.0.0";
function hasFlag(args: string[], flag: string): boolean {
return args.includes(flag);
}
async function patchBunLongForProtobuf(): Promise<void> {
// Bun ships a global `Long` that protobufjs detects, but it is not long.js and
// misses critical APIs (fromBits, ...). Baileys WAProto expects long.js.
if (typeof process.versions.bun !== "string") {
return;
}
const mod = await import("long");
const Long = (mod as unknown as { default?: unknown }).default ?? mod;
(globalThis as unknown as { Long?: unknown }).Long = Long;
}
async function main() {
const args = process.argv.slice(2);
// Swift side expects `--version` to return a plain semver string.
if (hasFlag(args, "--version") || hasFlag(args, "-V") || hasFlag(args, "-v")) {
console.log(BUNDLED_VERSION);
process.exit(0);
}
const { parseRelaySmokeTest, runRelaySmokeTest } = await import("./relay-smoke.js");
const smokeTest = parseRelaySmokeTest(args, process.env);
if (smokeTest) {
try {
await runRelaySmokeTest(smokeTest);
process.exit(0);
} catch (err) {
console.error(`Relay smoke test failed (${smokeTest}):`, err);
process.exit(1);
}
}
await patchBunLongForProtobuf();
const { loadDotEnv } = await import("../infra/dotenv.js");
loadDotEnv({ quiet: true });
const { ensureOpenClawCliOnPath } = await import("../infra/path-env.js");
ensureOpenClawCliOnPath();
const { enableConsoleCapture } = await import("../logging.js");
enableConsoleCapture();
const { assertSupportedRuntime } = await import("../infra/runtime-guard.js");
assertSupportedRuntime();
const { formatUncaughtError } = await import("../infra/errors.js");
const { installUnhandledRejectionHandler } = await import("../infra/unhandled-rejections.js");
const { buildProgram } = await import("../cli/program.js");
const program = buildProgram();
installUnhandledRejectionHandler();
process.on("uncaughtException", (error) => {
console.error("[openclaw] Uncaught exception:", formatUncaughtError(error));
process.exit(1);
});
await program.parseAsync(process.argv);
}
void main().catch((err) => {
console.error(
"[openclaw] Relay failed:",
err instanceof Error ? (err.stack ?? err.message) : err,
);
process.exit(1);
});