diff --git a/apps/macos/Sources/Clawdis/GatewayEnvironment.swift b/apps/macos/Sources/Clawdis/GatewayEnvironment.swift
index 60343ea31..d552c3cdb 100644
--- a/apps/macos/Sources/Clawdis/GatewayEnvironment.swift
+++ b/apps/macos/Sources/Clawdis/GatewayEnvironment.swift
@@ -66,7 +66,7 @@ enum GatewayEnvironment {
static func bundledGatewayExecutable() -> String? {
guard let res = Bundle.main.resourceURL else { return nil }
- let path = res.appendingPathComponent("Relay/clawdis-gateway").path
+ let path = res.appendingPathComponent("Relay/clawdis").path
return FileManager.default.isExecutableFile(atPath: path) ? path : nil
}
@@ -198,7 +198,7 @@ enum GatewayEnvironment {
let port = self.gatewayPort()
if let bundled {
- let cmd = [bundled, "--port", "\(port)", "--bind", "loopback"]
+ let cmd = [bundled, "gateway-daemon", "--port", "\(port)", "--bind", "loopback"]
return GatewayCommandResolution(status: status, command: cmd)
}
if let gatewayBin {
diff --git a/apps/macos/Sources/Clawdis/GatewayLaunchAgentManager.swift b/apps/macos/Sources/Clawdis/GatewayLaunchAgentManager.swift
index 634d25806..050ea42da 100644
--- a/apps/macos/Sources/Clawdis/GatewayLaunchAgentManager.swift
+++ b/apps/macos/Sources/Clawdis/GatewayLaunchAgentManager.swift
@@ -7,7 +7,7 @@ enum GatewayLaunchAgentManager {
}
private static func gatewayExecutablePath(bundlePath: String) -> String {
- "\(bundlePath)/Contents/Resources/Relay/clawdis-gateway"
+ "\(bundlePath)/Contents/Resources/Relay/clawdis"
}
private static func relayDir(bundlePath: String) -> String {
@@ -62,6 +62,7 @@ enum GatewayLaunchAgentManager {
ProgramArguments
\(gatewayBin)
+ gateway-daemon
--port
\(port)
--bind
diff --git a/scripts/codesign-mac-app.sh b/scripts/codesign-mac-app.sh
index 98800055a..1d82d2798 100755
--- a/scripts/codesign-mac-app.sh
+++ b/scripts/codesign-mac-app.sh
@@ -136,11 +136,8 @@ if [ -d "$APP_BUNDLE/Contents/Resources/Relay" ]; then
find "$APP_BUNDLE/Contents/Resources/Relay" -type f \( -name "*.node" -o -name "*.dylib" \) -print0 | while IFS= read -r -d '' f; do
echo "Signing gateway payload: $f"; sign_item "$f" "$ENT_TMP_BASE"
done
- if [ -f "$APP_BUNDLE/Contents/Resources/Relay/clawdis-gateway" ]; then
- echo "Signing embedded gateway"; sign_item "$APP_BUNDLE/Contents/Resources/Relay/clawdis-gateway" "$ENT_TMP_BUN"
- fi
if [ -f "$APP_BUNDLE/Contents/Resources/Relay/clawdis" ]; then
- echo "Signing embedded CLI"; sign_item "$APP_BUNDLE/Contents/Resources/Relay/clawdis" "$ENT_TMP_BUN"
+ echo "Signing embedded relay"; sign_item "$APP_BUNDLE/Contents/Resources/Relay/clawdis" "$ENT_TMP_BUN"
fi
fi
diff --git a/scripts/package-mac-app.sh b/scripts/package-mac-app.sh
index da4f75777..6088d6775 100755
--- a/scripts/package-mac-app.sh
+++ b/scripts/package-mac-app.sh
@@ -131,28 +131,16 @@ if [[ "${SKIP_GATEWAY_PACKAGE:-0}" != "1" ]]; then
exit 1
fi
- echo "🧰 Building bundled gateway (bun --compile)"
+ echo "🧰 Building bundled relay (bun --compile)"
mkdir -p "$RELAY_DIR"
- BUN_OUT="$RELAY_DIR/clawdis-gateway"
- bun build "$ROOT_DIR/dist/macos/gateway-daemon.js" \
+ RELAY_OUT="$RELAY_DIR/clawdis"
+ bun build "$ROOT_DIR/dist/macos/relay.js" \
--compile \
--bytecode \
- --outfile "$BUN_OUT" \
+ --outfile "$RELAY_OUT" \
-e electron \
--define "__CLAWDIS_VERSION__=\\\"$PKG_VERSION\\\""
- chmod +x "$BUN_OUT"
-
- echo "🧰 Building bundled CLI (bun --compile)"
- CLI_OUT="$RELAY_DIR/clawdis"
- bun build "$ROOT_DIR/dist/index.js" \
- --compile \
- --bytecode \
- --outfile "$CLI_OUT" \
- -e playwright-core \
- -e electron \
- -e "chromium-bidi*" \
- --define "__CLAWDIS_VERSION__=\\\"$PKG_VERSION\\\""
- chmod +x "$CLI_OUT"
+ chmod +x "$RELAY_OUT"
echo "🎨 Copying gateway A2UI host assets"
rm -rf "$RELAY_DIR/a2ui"
diff --git a/src/infra/path-env.test.ts b/src/infra/path-env.test.ts
index b3dbf969f..686e3d641 100644
--- a/src/infra/path-env.test.ts
+++ b/src/infra/path-env.test.ts
@@ -12,11 +12,8 @@ describe("ensureClawdisCliOnPath", () => {
try {
const relayDir = path.join(tmp, "Relay");
await fs.mkdir(relayDir, { recursive: true });
- const gatewayPath = path.join(relayDir, "clawdis-gateway");
const cliPath = path.join(relayDir, "clawdis");
- await fs.writeFile(gatewayPath, "#!/bin/sh\nexit 0\n", "utf-8");
await fs.writeFile(cliPath, "#!/bin/sh\necho ok\n", "utf-8");
- await fs.chmod(gatewayPath, 0o755);
await fs.chmod(cliPath, 0o755);
const originalPath = process.env.PATH;
@@ -25,7 +22,7 @@ describe("ensureClawdisCliOnPath", () => {
delete process.env.CLAWDIS_PATH_BOOTSTRAPPED;
try {
ensureClawdisCliOnPath({
- execPath: gatewayPath,
+ execPath: cliPath,
cwd: tmp,
homeDir: tmp,
platform: "darwin",
diff --git a/src/infra/path-env.ts b/src/infra/path-env.ts
index f8703eba0..484b0ce9d 100644
--- a/src/infra/path-env.ts
+++ b/src/infra/path-env.ts
@@ -55,7 +55,7 @@ function candidateBinDirs(opts: EnsureClawdisPathOpts): string[] {
const candidates: string[] = [];
- // Bun bundled (macOS app): `clawdis` is shipped next to `clawdis-gateway`.
+ // Bun bundled (macOS app): `clawdis` lives in the Relay dir (process.execPath).
try {
const execDir = path.dirname(execPath);
const siblingClawdis = path.join(execDir, "clawdis");
diff --git a/src/macos/relay.ts b/src/macos/relay.ts
new file mode 100644
index 000000000..54416f8f1
--- /dev/null
+++ b/src/macos/relay.ts
@@ -0,0 +1,69 @@
+#!/usr/bin/env node
+import process from "node:process";
+
+declare const __CLAWDIS_VERSION__: string | undefined;
+
+const BUNDLED_VERSION =
+ typeof __CLAWDIS_VERSION__ === "string" ? __CLAWDIS_VERSION__ : "0.0.0";
+
+function hasFlag(args: string[], flag: string): boolean {
+ return args.includes(flag);
+}
+
+async function patchBunLongForProtobuf(): Promise {
+ // 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);
+ }
+
+ await patchBunLongForProtobuf();
+
+ const { default: dotenv } = await import("dotenv");
+ dotenv.config({ quiet: true });
+
+ const { ensureClawdisCliOnPath } = await import("../infra/path-env.js");
+ ensureClawdisCliOnPath();
+
+ const { enableConsoleCapture } = await import("../logging.js");
+ enableConsoleCapture();
+
+ const { assertSupportedRuntime } = await import("../infra/runtime-guard.js");
+ assertSupportedRuntime();
+
+ const { buildProgram } = await import("../cli/program.js");
+ const program = buildProgram();
+
+ process.on("unhandledRejection", (reason, _promise) => {
+ console.error(
+ "[clawdis] Unhandled promise rejection:",
+ reason instanceof Error ? (reason.stack ?? reason.message) : reason,
+ );
+ process.exit(1);
+ });
+
+ process.on("uncaughtException", (error) => {
+ console.error("[clawdis] Uncaught exception:", error.stack ?? error.message);
+ process.exit(1);
+ });
+
+ await program.parseAsync(process.argv);
+}
+
+void main();
+