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 <cursoragent@cursor.com>
This commit is contained in:
2026-08-16 12:46:10 +08:00
parent 00209d55e6
commit d6a7a3ab08
3 changed files with 13 additions and 5 deletions

View File

@@ -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

View File

@@ -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):

View File

@@ -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;