Skip to content

hub-client: paste images from the clipboard into the source editor (bd-706b0ixu) - #623

Merged
cscheid merged 4 commits into
mainfrom
feature/bd-706b0ixu-paste-image-clipboard
Aug 27, 2026
Merged

hub-client: paste images from the clipboard into the source editor (bd-706b0ixu)#623
cscheid merged 4 commits into
mainfrom
feature/bd-706b0ixu-paste-image-clipboard

Conversation

@cscheid

@cscheid cscheid commented Aug 27, 2026

Copy link
Copy Markdown
Member

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

  • Take-over rule (pure, DOM-free fileUpload/pasteImages.ts): the paste is handled iff 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. 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.
  • SVG is deliberately excluded from the silent path (image/svg+xml can 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.
  • Content-hash naming makes concurrent CRDT pastes safe: 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.
  • Ingest orchestration (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.tsx wiring is a capture-phase paste listener 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

  • 41 new unit tests (classification matrix, filename/extension map, alt-text sanitization, full ingest orchestration incl. dedup/rename/guard paths), written and confirmed failing before implementation.
  • Gates: tsc -b, eslint (no new findings vs. baseline), hub-client 1049 unit + 114 integration + 133 wasm tests, npm run build:all, and full cargo xtask verify --skip-hub-build (13,480 Rust tests) — all green.
  • End-to-end in the production bundle via local-prod (bundle commit verified in the page footer): pasted a deterministic PNG → pasted-f613c380.png created (name matches the file's true SHA-256 prefix), reference inserted, preview rendered the exact bytes (16×16, naturalWidth confirmed); 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

cscheid and others added 4 commits August 27, 2026 12:54
…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
@cscheid
cscheid merged commit dcd3994 into main Aug 27, 2026
8 checks passed
@cscheid
cscheid deleted the feature/bd-706b0ixu-paste-image-clipboard branch August 27, 2026 19:40
@posit-snyk-bot

posit-snyk-bot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants