diff --git a/scripts/package-mac-app.sh b/scripts/package-mac-app.sh index 593dd2536..c895b67a5 100755 --- a/scripts/package-mac-app.sh +++ b/scripts/package-mac-app.sh @@ -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" < { +async function loadTemplate(name: string, fallback: string): Promise { const templatePath = path.join(TEMPLATE_DIR, name); try { const content = await fs.readFile(templatePath, "utf-8"); diff --git a/src/macos/gateway-daemon.ts b/src/macos/gateway-daemon.ts index 8653708c6..e613869d0 100644 --- a/src/macos/gateway-daemon.ts +++ b/src/macos/gateway-daemon.ts @@ -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> | null = null; -let shuttingDown = false; -let forceExitTimer: ReturnType | 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> | null = null; + let shuttingDown = false; + let forceExitTimer: ReturnType | 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(() => {}); } -// Keep process alive -await new Promise(() => {}); +void main();