From d6a7a3ab0880b61187e25b52aecdc3a878680865 Mon Sep 17 00:00:00 2001 From: TommyFang Date: Sun, 16 Aug 2026 12:46:10 +0800 Subject: [PATCH] fix: do not cancel HTML or text paste when no image is in the event Empty text/plain used to preventDefault before native clipboard read, which discarded HTML-only paste if no image was recovered. Co-authored-by: Cursor --- THIRD_PARTY.md | 2 +- tests/test_plugins.py | 3 +++ ui/inject/chrome.js | 13 +++++++++---- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/THIRD_PARTY.md b/THIRD_PARTY.md index 5bb66e6..cb1cade 100644 --- a/THIRD_PARTY.md +++ b/THIRD_PARTY.md @@ -15,7 +15,7 @@ DeepSeek, liustack, xiaobright, or AgentRQ. | ModLens (`@liustack/modlens`) | [liustack/modlens](https://github.com/liustack/modlens) | `3.16.6` | MIT, © 2026 Leon Liu (liustack) | Copied into `~/.dsh/profiles/web` so text-only models can read images. See `docs/licenses/modlens.LICENSE`. | | Anchored Standard | [xiaobright/dsh-anchored-standard](https://github.com/xiaobright/dsh-anchored-standard) | commit `ffb845c5480adc953392a6db6f8a98ede621174b` | MIT, © 2026 xiaobright; portions © 2026 DeepSeek | Localized as **锚定式标准(实验)** and **零工具锚定式标准(实验)**, written to `~/.dsh/.agent-presets/`. See `docs/licenses/dsh-anchored-standard.LICENSE` and `.NOTICE`. | | `dsh-desktop-vision` | this repo `plugins/dsh-desktop-vision/` | `0.1.4` | MIT, © 2026 TommyFang2077 | Settings page **设置 → 视觉模型**; writes `~/.modlens/config.json`. | -| AgentRQ (`agentrq`) | [agentrq/agentrq](https://github.com/agentrq/agentrq) | `0.2.1` | Apache-2.0 | Copied into `~/.dsh/profiles/web` so Harness can manage AgentRQ tasks. Idle until `AGENTRQ_WORKSPACE_MCP_URL` or the profile `url` is set. See `docs/licenses/agentrq.LICENSE`. | +| AgentRQ (`agentrq`) | [agentrq/agentrq](https://github.com/agentrq/agentrq) | `0.2.1` | Apache-2.0, © AgentRQ authors | Copied into `~/.dsh/profiles/web` so Harness can manage AgentRQ tasks. Idle until `AGENTRQ_WORKSPACE_MCP_URL` or the profile `url` is set. See `docs/licenses/agentrq.LICENSE`. | The Anchored Standard NOTICE records that the presets adapt the DeepSeek Harness Standard agent preset from diff --git a/tests/test_plugins.py b/tests/test_plugins.py index f677eeb..eb9b8d7 100644 --- a/tests/test_plugins.py +++ b/tests/test_plugins.py @@ -46,10 +46,13 @@ class ClipboardIngestTests(unittest.TestCase): self.assertIn("navigator.clipboard.read", chrome) self.assertIn("read_clipboard_images", chrome) self.assertIn("__dshDesktopIngesting", chrome) + self.assertIn('clipboardText(e, "text/html")', chrome) self.assertNotIn( 'item.kind === "file" && item.getAsFile()', chrome, ) + self.assertNotIn("steal", chrome) + self.assertNotIn("|| !String(text).trim()", chrome) class BundledAttributionTests(unittest.TestCase): diff --git a/ui/inject/chrome.js b/ui/inject/chrome.js index 80e6c3c..69e0905 100644 --- a/ui/inject/chrome.js +++ b/ui/inject/chrome.js @@ -186,10 +186,15 @@ const local = fromEvent ? fromEvent(e) : []; const text = clipboardText(e, "text/plain"); const uris = clipboardText(e, "text/uri-list"); - const steal = local.length > 0 - || (pathLike && (pathLike(text) || pathLike(uris))) - || !String(text).trim(); - if (!steal) return; + const html = clipboardText(e, "text/html"); + const imagePath = Boolean(pathLike && (pathLike(text) || pathLike(uris))); + const hasText = Boolean(String(text).trim() || String(html).trim()); + // Image files in the event, or a pasted image path, are ours. Empty + // payload is the Linux case where the image is only on the native + // clipboard. Non-empty text/html must reach the page — do not cancel + // first and then fail to recover an image. + if (!local.length && !imagePath && hasText) return; + e.preventDefault(); e.stopImmediatePropagation(); window.__dshDesktopIngesting = true;