perf(macos): compile embedded gateway with bytecode

This commit is contained in:
Peter Steinberger
2025-12-19 22:11:41 +01:00
parent 96be450cbb
commit 836f645621
3 changed files with 114 additions and 112 deletions

View File

@@ -135,15 +135,16 @@ if [[ "${SKIP_GATEWAY_PACKAGE:-0}" != "1" ]]; then
echo "🧰 Building bundled gateway (bun --compile)"
mkdir -p "$RELAY_DIR"
BUN_OUT="$RELAY_DIR/clawdis-gateway"
bun build "$ROOT_DIR/dist/macos/gateway-daemon.js" \
--compile \
--outfile "$BUN_OUT" \
-e playwright-core \
-e electron \
-e "chromium-bidi*" \
--define "__CLAWDIS_VERSION__=\\\"$PKG_VERSION\\\""
chmod +x "$BUN_OUT"
BUN_OUT="$RELAY_DIR/clawdis-gateway"
bun build "$ROOT_DIR/dist/macos/gateway-daemon.js" \
--compile \
--bytecode \
--outfile "$BUN_OUT" \
-e playwright-core \
-e electron \
-e "chromium-bidi*" \
--define "__CLAWDIS_VERSION__=\\\"$PKG_VERSION\\\""
chmod +x "$BUN_OUT"
echo "📄 Writing embedded runtime package.json (Pi compatibility)"
cat > "$RELAY_DIR/package.json" <<JSON

View File

@@ -79,10 +79,7 @@ function stripFrontMatter(content: string): string {
return trimmed;
}
async function loadTemplate(
name: string,
fallback: string,
): Promise<string> {
async function loadTemplate(name: string, fallback: string): Promise<string> {
const templatePath = path.join(TEMPLATE_DIR, name);
try {
const content = await fs.readFile(templatePath, "utf-8");

View File

@@ -19,117 +19,121 @@ function hasFlag(args: string[], flag: string): boolean {
const args = process.argv.slice(2);
if (hasFlag(args, "--version") || hasFlag(args, "-v")) {
// Match `clawdis --version` behavior for Swift env/version checks.
// Keep output a single line.
console.log(BUNDLED_VERSION);
process.exit(0);
}
type GatewayWsLogStyle = "auto" | "full" | "compact";
const [
{ loadConfig },
{ startGatewayServer },
{ setGatewayWsLogStyle },
{ setVerbose },
{ defaultRuntime },
] = await Promise.all([
import("../config/config.js"),
import("../gateway/server.js"),
import("../gateway/ws-logging.js"),
import("../globals.js"),
import("../runtime.js"),
]);
setVerbose(hasFlag(args, "--verbose"));
const wsLogRaw = (
hasFlag(args, "--compact") ? "compact" : argValue(args, "--ws-log")
) as string | undefined;
const wsLogStyle: GatewayWsLogStyle =
wsLogRaw === "compact" ? "compact" : wsLogRaw === "full" ? "full" : "auto";
setGatewayWsLogStyle(wsLogStyle);
const portRaw =
argValue(args, "--port") ?? process.env.CLAWDIS_GATEWAY_PORT ?? "18789";
const port = Number.parseInt(portRaw, 10);
if (Number.isNaN(port) || port <= 0) {
defaultRuntime.error(`Invalid --port (${portRaw})`);
process.exit(1);
}
const cfg = loadConfig();
const bindRaw =
argValue(args, "--bind") ??
process.env.CLAWDIS_GATEWAY_BIND ??
cfg.gateway?.bind ??
"loopback";
const bind =
bindRaw === "loopback" ||
bindRaw === "tailnet" ||
bindRaw === "lan" ||
bindRaw === "auto"
? bindRaw
: null;
if (!bind) {
defaultRuntime.error(
'Invalid --bind (use "loopback", "tailnet", "lan", or "auto")',
);
process.exit(1);
}
const token = argValue(args, "--token");
if (token) process.env.CLAWDIS_GATEWAY_TOKEN = token;
let server: Awaited<ReturnType<typeof startGatewayServer>> | null = null;
let shuttingDown = false;
let forceExitTimer: ReturnType<typeof setTimeout> | null = null;
const shutdown = (signal: string) => {
process.removeListener("SIGTERM", onSigterm);
process.removeListener("SIGINT", onSigint);
if (shuttingDown) {
defaultRuntime.log(
`gateway: received ${signal} during shutdown; exiting now`,
);
async function main() {
if (hasFlag(args, "--version") || hasFlag(args, "-v")) {
// Match `clawdis --version` behavior for Swift env/version checks.
// Keep output a single line.
console.log(BUNDLED_VERSION);
process.exit(0);
}
shuttingDown = true;
defaultRuntime.log(`gateway: received ${signal}; shutting down`);
forceExitTimer = setTimeout(() => {
const [
{ loadConfig },
{ startGatewayServer },
{ setGatewayWsLogStyle },
{ setVerbose },
{ defaultRuntime },
] = await Promise.all([
import("../config/config.js"),
import("../gateway/server.js"),
import("../gateway/ws-logging.js"),
import("../globals.js"),
import("../runtime.js"),
]);
setVerbose(hasFlag(args, "--verbose"));
const wsLogRaw = (
hasFlag(args, "--compact") ? "compact" : argValue(args, "--ws-log")
) as string | undefined;
const wsLogStyle: GatewayWsLogStyle =
wsLogRaw === "compact" ? "compact" : wsLogRaw === "full" ? "full" : "auto";
setGatewayWsLogStyle(wsLogStyle);
const portRaw =
argValue(args, "--port") ?? process.env.CLAWDIS_GATEWAY_PORT ?? "18789";
const port = Number.parseInt(portRaw, 10);
if (Number.isNaN(port) || port <= 0) {
defaultRuntime.error(`Invalid --port (${portRaw})`);
process.exit(1);
}
const cfg = loadConfig();
const bindRaw =
argValue(args, "--bind") ??
process.env.CLAWDIS_GATEWAY_BIND ??
cfg.gateway?.bind ??
"loopback";
const bind =
bindRaw === "loopback" ||
bindRaw === "tailnet" ||
bindRaw === "lan" ||
bindRaw === "auto"
? bindRaw
: null;
if (!bind) {
defaultRuntime.error(
"gateway: shutdown timed out; exiting without full cleanup",
'Invalid --bind (use "loopback", "tailnet", "lan", or "auto")',
);
process.exit(0);
}, 5000);
process.exit(1);
}
void (async () => {
try {
await server?.close();
} catch (err) {
defaultRuntime.error(`gateway: shutdown error: ${String(err)}`);
} finally {
if (forceExitTimer) clearTimeout(forceExitTimer);
const token = argValue(args, "--token");
if (token) process.env.CLAWDIS_GATEWAY_TOKEN = token;
let server: Awaited<ReturnType<typeof startGatewayServer>> | null = null;
let shuttingDown = false;
let forceExitTimer: ReturnType<typeof setTimeout> | null = null;
const shutdown = (signal: string) => {
process.removeListener("SIGTERM", onSigterm);
process.removeListener("SIGINT", onSigint);
if (shuttingDown) {
defaultRuntime.log(
`gateway: received ${signal} during shutdown; exiting now`,
);
process.exit(0);
}
})();
};
shuttingDown = true;
defaultRuntime.log(`gateway: received ${signal}; shutting down`);
const onSigterm = () => shutdown("SIGTERM");
const onSigint = () => shutdown("SIGINT");
forceExitTimer = setTimeout(() => {
defaultRuntime.error(
"gateway: shutdown timed out; exiting without full cleanup",
);
process.exit(0);
}, 5000);
process.once("SIGTERM", onSigterm);
process.once("SIGINT", onSigint);
void (async () => {
try {
await server?.close();
} catch (err) {
defaultRuntime.error(`gateway: shutdown error: ${String(err)}`);
} finally {
if (forceExitTimer) clearTimeout(forceExitTimer);
process.exit(0);
}
})();
};
try {
server = await startGatewayServer(port, { bind });
} catch (err) {
defaultRuntime.error(`Gateway failed to start: ${String(err)}`);
process.exit(1);
const onSigterm = () => shutdown("SIGTERM");
const onSigint = () => shutdown("SIGINT");
process.once("SIGTERM", onSigterm);
process.once("SIGINT", onSigint);
try {
server = await startGatewayServer(port, { bind });
} catch (err) {
defaultRuntime.error(`Gateway failed to start: ${String(err)}`);
process.exit(1);
}
// Keep process alive
await new Promise<never>(() => {});
}
// Keep process alive
await new Promise<never>(() => {});
void main();