feat(desktop): attach images to a cloud workspace at create
Third of three, and the last gap in the attachment story. Stacked on #7622, which is stacked on #7620.
Desktop was worse than mobile here. Mobile refused with a visible error; desktop uploaded the files and then called create without them, so an attached image vanished with no signal at all. The reason was in a comment at the cloud branch of useSubmitWorkspace:
// Attachments stay behind — they are written to a host, and this
// workspace's host doesn't exist yet.
The change
An upload's target is now a host URL or CLOUD_UPLOAD_TARGET. For the cloud target the bytes go to cloud storage over a presigned PUT (attachment.createUpload) instead of to a host, and a ready entry carries a files.id the sandbox resolves rather than a host attachment id — the same id space mobile sends, which #7622 makes the box import on first boot.
The store already keyed uploads by (fileId, target) — that keying existed so switching hosts wouldn't re-upload — so the pill list, the pruning, and the await path all needed nothing. The only other change is the modal choosing the target when the destination is CLOUD_HOST_ID.
Where attachments stand after these three
| Create | Existing conversation | |
|---|---|---|
| Mobile | #7622 | already worked — materializeIntoWorkspace runs in the box |
| Desktop | this PR | already worked — setImagePasteOverride writes into the worktree for non-local hosts |
Verified
apps/desktoptypechecks clean; repo lint cleanbun teston the modal's tests: 4 pass / 0 fail- Not exercised against a real box yet — needs the same merge + release as the other two, which is the plan for all three together.
Summary by cubic
Fixes desktop silently dropping images attached to a new cloud workspace. Attachments now upload to cloud storage and their file IDs are passed to workspace creation.
Bug Fixes
- Uploads target
CLOUD_UPLOAD_TARGETinstead of a host when the destination is the cloud host. - Cloud uploads use a presigned PUT via
attachment.createUploadand carry afiles.idthe sandbox resolves on first boot. - Works with the existing
(fileId, target)upload keying, so switching targets does not re-upload.