hub-client: paste images from the clipboard into the source editor (bd-706b0ixu) - #623
Merged
Merged
Conversation
…0ixu) Design exploration + decision log for pasting images from the clipboard into the hub-client source editor: clipboard format landscape, Monaco pass-through behavior (verified against monaco 0.55.1 sources), SVG security analysis, filename/concurrency scheme (content-hash names to sidestep index-map LWW races), and scoped v1 rules. Follow-ups filed: bd-yspyic32 (mixed payloads), bd-myoj9kp5 (SVG posture). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Bs2YW5vUbm1krBkQicB5nr
…d-706b0ixu) Cmd/Ctrl-V with an image on the clipboard now ingests it silently — no dialog: the file is created next to the current document with a content-hash name (pasted-<hash8>.<ext>) and a markdown image reference is inserted at the cursor (selection becomes alt text for single-file pastes; multi-file pastes join references with spaces). Decision logic is pure and DOM-free (fileUpload/pasteImages.ts): take over only when every clipboard file is an accepted raster type (png/jpeg/gif/webp/avif, non-empty) and text/plain is empty or merely the OS file-copy filename rider. Text and mixed payloads (Office, Excel — which ship a PNG rendition alongside the TSV) fall through to Monaco's own paste handling. SVG is deliberately excluded from the silent path (it can carry script; ingestion stays available via the deliberate dialog flows) — pipeline-wide SVG posture is bd-myoj9kp5, mixed-payload image offering is bd-yspyic32. Content-hash naming makes concurrent pastes CRDT-safe: different content hashes to different index keys, so no last-writer-wins clobber; identical content converges (and dedups sequentially). Ingest orchestration (fileUpload/pasteImageHandler.ts) is a factory over injected deps, unit-tested without Monaco/jsdom: size limits, per-file error isolation, rename-on-conflict path use, and a file-switch guard that drops the insertion if the user changed documents mid-flight. Editor.tsx wiring is a capture-phase listener on the editor container (runs before Monaco's textarea handler), attached once at mount via identity-stable callbacks. buildDropMarkdown gains an optional altText parameter. Verified: tsc -b, eslint (no new findings), vitest 1049 unit + 114 integration + 133 wasm, npm run build:all — all green. Design + decision log: claude-notes/plans/2026-08-27-paste-image-clipboard.md Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Bs2YW5vUbm1krBkQicB5nr
…ste (e0e2d2b) Changelog entry for the paste-image feature, and the plan's end-to-end verification record: exercised in the production bundle via local-prod (bundle commit e0e2d2b confirmed in the page footer) — file creation with content-hash name, markdown insertion, preview rendering of the pasted bytes, repeat-paste dedup, SVG decline, and mixed-payload pass-through all observed live; zero console errors. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Bs2YW5vUbm1krBkQicB5nr
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Bs2YW5vUbm1krBkQicB5nr
Contributor
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Cmd/Ctrl-V with an image on the clipboard now ingests it into the project silently — no dialog: the binary file is created next to the current document under a content-hash name (
pasted-<hash8>.<ext>) and a markdown image reference is inserted at the cursor, so the image appears in the live preview immediately. Selected text becomes the alt text for single-file pastes; multi-file pastes insert space-separated references.Design + decision log:
claude-notes/plans/2026-08-27-paste-image-clipboard.md(braid bd-706b0ixu, closed).Behavior
fileUpload/pasteImages.ts): the paste is handled iff every clipboard file is an accepted raster type (png/jpeg/gif/webp/avif, non-empty) andtext/plainis empty or merely the OS file-copy filename rider. Everything else — plain text, Office/Excel payloads (which carry a PNG rendition alongside the TSV text), SVG, PDFs — falls through to Monaco's own paste handling, unchanged.image/svg+xmlcan carry executable script); SVG ingestion stays available via the existing drag/drop + asset-dialog flows. Pipeline-wide SVG posture: bd-myoj9kp5. Offering the image rendition of mixed payloads: bd-yspyic32.createBinaryFile's existence check is check-then-act on the local replica, so two peers claiming the same index key with different content would race to last-writer-wins and silently lose an image. Different content → different hash → different key: no race. Identical content converges and dedups.fileUpload/pasteImageHandler.ts) is a dependency-injected factory: 10 MB size limit, per-file error isolation, rename-on-conflict path use, and a file-switch guard that drops the insertion if the user changed documents mid-flight.Editor.tsxwiring is a capture-phasepastelistener on the editor container (runs before Monaco's own handler, which otherwise inserts the filename rider as stray text), attached once at mount via identity-stable callbacks.Testing
tsc -b, eslint (no new findings vs. baseline), hub-client 1049 unit + 114 integration + 133 wasm tests,npm run build:all, and fullcargo xtask verify --skip-hub-build(13,480 Rust tests) — all green.local-prod(bundle commit verified in the page footer): pasted a deterministic PNG →pasted-f613c380.pngcreated (name matches the file's true SHA-256 prefix), reference inserted, preview rendered the exact bytes (16×16,naturalWidthconfirmed); repeat paste deduped to one file; SVG-with-<script>and Excel-style mixed payloads passed through untouched; zero console errors. Full record in plan §6.🤖 Generated with Claude Code
https://claude.ai/code/session_01Bs2YW5vUbm1krBkQicB5nr