diff --git a/scripts/package-mac-app.sh b/scripts/package-mac-app.sh index f90d530c7..884e1c842 100755 --- a/scripts/package-mac-app.sh +++ b/scripts/package-mac-app.sh @@ -251,6 +251,9 @@ if [[ "${SKIP_GATEWAY_PACKAGE:-0}" != "1" ]]; then fi rm -rf "$RELAY_BUILD_DIR" + echo "🧪 Smoke testing bundled relay QR modules" + CLAWDBOT_SMOKE_QR=1 "$RELAY_OUT" >/dev/null + echo "🎨 Copying gateway A2UI host assets" rm -rf "$RELAY_DIR/a2ui" cp -R "$ROOT_DIR/src/canvas-host/a2ui" "$RELAY_DIR/a2ui" diff --git a/src/macos/relay.ts b/src/macos/relay.ts index 8448d92b0..d431f576e 100644 --- a/src/macos/relay.ts +++ b/src/macos/relay.ts @@ -32,6 +32,13 @@ async function main() { process.exit(0); } + if (process.env.CLAWDBOT_SMOKE_QR === "1") { + const { renderQrPngBase64 } = await import("../web/qr-image.js"); + await renderQrPngBase64("clawdbot-smoke"); + console.log("smoke: qr ok"); + return; + } + await patchBunLongForProtobuf(); const { loadDotEnv } = await import("../infra/dotenv.js"); diff --git a/src/web/qr-image.test.ts b/src/web/qr-image.test.ts index 8b0d585a4..866e09734 100644 --- a/src/web/qr-image.test.ts +++ b/src/web/qr-image.test.ts @@ -1,3 +1,6 @@ +import { readFile } from "node:fs/promises"; +import { resolve } from "node:path"; + import { describe, expect, it } from "vitest"; import { renderQrPngBase64 } from "./qr-image.js"; @@ -8,4 +11,11 @@ describe("renderQrPngBase64", () => { const buf = Buffer.from(b64, "base64"); expect(buf.subarray(0, 8).toString("hex")).toBe("89504e470d0a1a0a"); }); + + it("avoids dynamic require of qrcode-terminal vendor modules", async () => { + const sourcePath = resolve(process.cwd(), "src/web/qr-image.ts"); + const source = await readFile(sourcePath, "utf-8"); + expect(source).not.toContain("createRequire("); + expect(source).not.toContain('require("qrcode-terminal/vendor/QRCode")'); + }); }); diff --git a/src/web/qr-image.ts b/src/web/qr-image.ts index c4e2a501f..14aa25244 100644 --- a/src/web/qr-image.ts +++ b/src/web/qr-image.ts @@ -1,5 +1,6 @@ -import { createRequire } from "node:module"; import { deflateSync } from "node:zlib"; +import QRCodeModule from "qrcode-terminal/vendor/QRCode"; +import QRErrorCorrectLevelModule from "qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel"; type QRCodeConstructor = new ( typeNumber: number, @@ -11,13 +12,8 @@ type QRCodeConstructor = new ( isDark: (row: number, col: number) => boolean; }; -const require = createRequire(import.meta.url); -const QRCode = require("qrcode-terminal/vendor/QRCode") as QRCodeConstructor; -const QRErrorCorrectLevel = - require("qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel") as Record< - string, - unknown - >; +const QRCode = QRCodeModule as unknown as QRCodeConstructor; +const QRErrorCorrectLevel = QRErrorCorrectLevelModule as Record; function createQrMatrix(input: string) { const qr = new QRCode(-1, QRErrorCorrectLevel.L);