diff --git a/packages/coding-agent/src/utils/clipboard-image.ts b/packages/coding-agent/src/utils/clipboard-image.ts index 96905a6f..58cd5913 100644 --- a/packages/coding-agent/src/utils/clipboard-image.ts +++ b/packages/coding-agent/src/utils/clipboard-image.ts @@ -1,22 +1,8 @@ import { spawnSync } from "child_process"; -import { createRequire } from "module"; +import { clipboard } from "./clipboard-native.js"; import { loadPhoton } from "./photon.js"; -type ClipboardModule = { - hasImage: () => boolean; - getImageBinary: () => Promise>; -}; - -const require = createRequire(import.meta.url); -let Clipboard: ClipboardModule | null = null; - -try { - Clipboard = require("@mariozechner/clipboard") as ClipboardModule; -} catch { - Clipboard = null; -} - export type ClipboardImage = { bytes: Uint8Array; mimeType: string; @@ -191,11 +177,11 @@ export async function readClipboardImage(options?: { if (platform === "linux" && isWaylandSession(env)) { image = readClipboardImageViaWlPaste() ?? readClipboardImageViaXclip(); } else { - if (!Clipboard || !Clipboard.hasImage()) { + if (!clipboard || !clipboard.hasImage()) { return null; } - const imageData = await Clipboard.getImageBinary(); + const imageData = await clipboard.getImageBinary(); if (!imageData || imageData.length === 0) { return null; } diff --git a/packages/coding-agent/src/utils/clipboard-native.ts b/packages/coding-agent/src/utils/clipboard-native.ts new file mode 100644 index 00000000..e176d47c --- /dev/null +++ b/packages/coding-agent/src/utils/clipboard-native.ts @@ -0,0 +1,21 @@ +import { createRequire } from "module"; + +export type ClipboardModule = { + hasImage: () => boolean; + getImageBinary: () => Promise>; +}; + +const require = createRequire(import.meta.url); +let clipboard: ClipboardModule | null = null; + +const hasDisplay = process.platform !== "linux" || Boolean(process.env.DISPLAY || process.env.WAYLAND_DISPLAY); + +if (!process.env.TERMUX_VERSION && hasDisplay) { + try { + clipboard = require("@mariozechner/clipboard") as ClipboardModule; + } catch { + clipboard = null; + } +} + +export { clipboard }; diff --git a/packages/coding-agent/test/clipboard-image.test.ts b/packages/coding-agent/test/clipboard-image.test.ts index a146820c..ad2ba5de 100644 --- a/packages/coding-agent/test/clipboard-image.test.ts +++ b/packages/coding-agent/test/clipboard-image.test.ts @@ -17,9 +17,9 @@ vi.mock("child_process", () => { }; }); -vi.mock("@mariozechner/clipboard", () => { +vi.mock("../src/utils/clipboard-native.js", () => { return { - default: mocks.clipboard, + clipboard: mocks.clipboard, }; }); @@ -54,7 +54,7 @@ describe("readClipboardImage", () => { mocks.clipboard.getImageBinary.mockReset(); }); - test("Wayland: uses wl-paste and never calls @mariozechner/clipboard", async () => { + test("Wayland: uses wl-paste and never calls clipboard", async () => { mocks.clipboard.hasImage.mockImplementation(() => { throw new Error("clipboard.hasImage should not be called on Wayland"); }); @@ -107,7 +107,7 @@ describe("readClipboardImage", () => { expect(Array.from(result?.bytes ?? [])).toEqual([9, 8]); }); - test("Non-Wayland: uses @mariozechner/clipboard", async () => { + test("Non-Wayland: uses clipboard", async () => { mocks.spawnSync.mockImplementation(() => { throw new Error("spawnSync should not be called for non-Wayland sessions"); });