mirror of
https://github.com/getpaseo/paseo.git
synced 2026-10-23 17:52:49 +00:00
* feat(terminal): support image paste into agent TUIs, local and remote (#3725) Codex and OpenCode receive image pastes by binding Ctrl+V (\x16) and reading the OS clipboard of the machine they run on; no image bytes travel through the pty. Paseo's terminal swallowed that keystroke and only ever pasted text, so image paste silently did nothing. - web/Electron runtime: forward \x16 when the clipboard holds no text, keep the existing text-paste path otherwise (bash quoted-insert stays intact) - new terminal.clipboard.write_image RPC ships client clipboard bytes to the daemon, which writes them onto its host clipboard (osascript / wl-copy / xclip / Set-Clipboard) so remote clients work like local ones; gated by server_info.features.terminalClipboardImage with a bare-\x16 fallback for older daemons - clipboard tools are waited on via their exit event, not stream close: wl-copy and xclip fork a selection owner that inherits our pipes, so waiting for stream closure hung every Linux write until timeout - headless hosts without a clipboard get a temp-file fallback: the daemon materializes the image under os.tmpdir() and returns its path; the client injects it as bracket-pasted text - all four renderers covered (web DOM, Electron, native grid, WebView bridge); mobile Paste button enables for image clipboards and toasts failures in all 10 locales * fix(terminal): bind image paste to private retained files * fix(terminal): recover interrupted image metadata safely * fix(terminal): retire image files with background lifecycle maintenance * fix(terminal): check live paste modes and refresh native bridge * fix(terminal): order image paste input and isolate failures * fix(terminal): normalize paste and release failed creation reservations * fix(terminal): validate missing Windows launch paths before spawn * fix(terminal): keep input live during cancellable image uploads * test(terminal): follow streamed input-mode updates * feat(terminal): upload dropped images through the paste flow * feat(terminal): paste and drop images through file uploads Terminal image paste and drop now reuse the existing upload path (client.uploadFile -> file.upload.request -> FileUploadStore) and paste the quoted host path through the pane's input, bracketed when the app asked for it. This replaces the PR's daemon-side image store, RPCs, paste permits and file lifecycle, so the daemon, protocol and client diffs for this feature are empty. - terminal/image-paste owns a per-pane serial queue: gesture order, keystrokes stay live, Ctrl+C and pane/connection teardown cancel pending pastes, and a cancelled path is never pasted. - Clipboard text wins over an image; any image/* type is accepted up to the composer's 50MB upload limit. - Host paths are quoted for the host OS by path shape. - One failure toast; i18n keeps two keys. - Browser e2e covers two panes pasting distinct PNGs, drop, ordering, Ctrl+C cancel and disconnect against a real daemon. Co-authored-by: Gerard Balaoro <miogerard@yahoo.com> * fix(terminal): translate the disconnected image upload error * feat(terminal): report image uploads through toasts Show a lasting "Uploading image…" toast while an image uploads, replace it with "Image uploaded" or a failure toast that carries the reason, and dismiss it when Ctrl+C cancels the upload. Toast show now returns a dismiss scoped to that toast, so the pane can clear its own toast without removing a newer one. * build(terminal): regenerate the WebView HTML for the toast events * fix(terminal): keep i18n out of the terminal WebView bundle The image paste queue imported i18n for its size-limit message, which pulled every translation into the WebView HTML. The queue now reports a typed TerminalImageTooLargeError and the pane words it. * refactor(terminal): route dropped files by host locality and share the drop overlay A dropped file pastes its own path only when the host is the desktop app's own daemon (useIsLocalDaemon); anywhere else the host cannot read the client's disk, so the file uploads through client.uploadFile and the host path is pasted. File type no longer plays a part: images and other files take the same route, and clipboard images always upload because they have no path. The terminal pane now sits in the shared FileDropZone, so dragging files over it shows the agent panels' "Drop files here" overlay. The emulator's own drag listeners, blue tint and 180 ms timeout are gone. FileDropSink.onFiles is optional so a sink can take raw files without persisting raster images as attachments. terminal/image-paste becomes terminal/file-paste; the queue, callbacks, toasts and i18n keys say "file". * test(terminal): keep the fake desktop bridge in an e2e support helper The CI contract test forbids browser specs from installing paseoDesktop directly; the local-host drop scenario now imports it from support. --------- Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>