feat(mobile): pick, share, and receive files in threads - #8237
Conversation
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Comment |
Thread transfer impact✅ Thread transfer remains within every enforced ceiling.
Baseline: Scenario and decoded snapshot size10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.
Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed. |
ApprovabilityVerdict: Not approved Macroscope's review found this PR not approvable — This PR adds an end-to-end mobile file attachment and sharing capability across native registration, local storage, uploads, thread rendering, and outbox recovery. It also changes share-target defaults and introduces significant lifecycle and native-runtime side effects, warranting human review. You can add or adjust custom eligibility rules. Learn more. |
06b5157 to
37945fe
Compare
e99ece8 to
eb637e6
Compare
eb637e6 to
9ae4de9
Compare
c88f3df to
33d67f9
Compare
9ae4de9 to
330b66c
Compare
7abf833 to
1dd3cc0
Compare
330b66c to
959a32f
Compare
959a32f to
1974134
Compare
1974134 to
ddb9bef
Compare
Appending to a draft now caps against the live state and releases the overflow, so a pick raced by concurrent adds cannot enqueue an over-limit message. Send defers the file sweep until the durable outbox write settles, so a failed write cannot delete the bytes its restore is about to reference. Blank picker display names fall back before they can fail the wire contract. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A failed enqueue with no surviving same-id message now removes its disk entry, so a compensating write from a racing update cannot resurrect it after restart. Partial merge rollbacks return merge-written settings to the snapshot while keeping user edits. Shared files record the stored copy's measured size instead of trusting an under-reporting content source. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Review round on the mobile file-attachments PR: - Delivery cleanup is now revision-checked. An edit accepted while the turn delivered stays queued with the uploads it references, and the drain retries instead of releasing them. - A failed restore rolls its draft merge back (keeping edits typed since), so the retry cannot append the recovered text twice. - Send blocks a draft over the attachment cap instead of enqueueing a message that outbox recovery rejects forever. The allowOverflow restore stays, so a failed send never drops its own files. - Review-comment attachments go through the capped append; overflow is released and reported. - A persisted share copy that measures zero bytes is rejected as empty and released instead of shipping with the source's claimed size. - A failed external open of a message attachment now alerts. - The file picker reports both a picker error and a cap rejection from the same pick. - The new-task file pick reports the rejected count like the thread composer does. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A creation delivered while its queue entry was being edited now hands the edited content to the new thread's composer instead of losing it to the next drain's duplicate-creation removal. Cancelling a share import sweeps the merged-in files. Unnamed shared files fall back to their mime family instead of an image-style name. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A dismissed editor session's unmount flush carries the revision it took the task at, so it cannot overwrite a newer edit. The creation recovery flushes the draft before removing the queue entry and backs off cleanly on failure. Cancel sweeps share files only after the inbox entry was consumed. The drain re-reads shell state after the confirmation await, so a vanished or busy thread defers instead of receiving a stale dispatch. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A creation delivered while its entry is open in the editor defers recovery until the editor saves, then hands the edits to the new thread's composer instead of discarding them as a duplicate. Environment clears release exactly the messages they removed. The new-task start refuses over-cap drafts. Docs note the Files control needs server support. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The attachment sweep aborts when outbox hydration fails instead of treating an unreadable store as empty. Removal releases the payload that actually left the queue and leaves a revision tombstone so stale CAS writers lose after a same-id retry. Duplicate-creation cleanup always recovers the payload into the thread draft, which keeps edits across restarts without an in-memory marker. A lost editor-flush CAS keeps the draft and lock. Recovery restores editor settings, and image picks report cap rejections like file picks. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Remove the temporary image-only filter now that each attachment type has a dedicated renderer. Original work by Theo Browne <me@t3.gg> with Claude Fable 5 in the Claude Code harness. Modernized by GPT-5.6 Sol in the Codex harness.
Capture the queued revision before draft persistence, keep newer edits and open editor state, and retry persistence or removal failures through the existing drain backoff. Recovery also skips attachment ids already present in the draft. Modernized by GPT-5.6 Sol in the Codex harness.
Chain editor saves for the same queued task so each reopened editor writes from its predecessor's accepted revision. Preserve that known revision through a failed editor write, while still rejecting the failed save. Keep the draft and drain hold when another queue write wins or a newer editor changes the draft before an older save finishes. Original work by Theo Browne <me@t3.gg> with Claude Fable 5 in the Claude Code harness. Modernized by GPT-5.6 Sol in the Codex harness.
Treat persisted incoming shares as attachment owners before cleanup deletes files. Stop the cleanup batch when the inbox cannot be read or decoded. Keep text appended after a recovery merge when rollback removes the merged content. Changes authored by GPT-5.6 Sol in the Codex harness.
Clear cached pending-task editor drafts only after their queued creation leaves the outbox. Persist draft removal before scheduling one combined attachment cleanup, and leave drafts for retained or requeued messages. Keep outbox removal successful when the secondary draft cleanup fails. Changes authored by GPT-5.6 Sol in the Codex harness.
c7b48be to
e42c5fd
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 470c8d5. Configure here.
Intent: Expose the generic-file backend shipped in v0.0.36 through the web and desktop composer while following the official client implementation closely enough for its upstream PR to replace this patch cleanly. Behavior: - Accept images and generic files through the paperclip button, paste, and drag-and-drop; share the eight-attachment limit and use the server-advertised generic-file limit, currently 50 MB. - Upload while the user composes, show progress/retry/reattach states, and render sent files as signed downloads with their original names. - Preserve file drafts and stashes as server upload references or explicit needs-reattach markers instead of storing generic-file bytes in localStorage. - Keep upload verification, cleanup, retry, environment moves, and unknown attachment rendering explicit. - Show file names in the current mobile feed and include attachment names in transcript bootstrap context. Design constraints: - Backport official upstream PR pingdotgg#8236 at 129f2ad, rebased onto v0.0.36, rather than maintaining a parallel client upload architecture. - Use packages/client-runtime for the shared upload lifecycle and clamp file sizes to the server capability and contract maximum. - Require direct-upload support for generic files. Do not retain the fork inline-file protocol or serialize generic-file bytes into drafts and stashes. - Upload local workspace drops like the official client; do not retain the competing desktop-only drop-to-mention behavior. - Keep images on their established compression and compatibility path. Integration: - Shared client-runtime upload lifecycle and web environment atoms. - Web composer, drafts, prompt stashes, upload queue, message timeline, signed asset downloads, sidebar counts, project cleanup, and user documentation. - Minimal current mobile feed visibility and transcript bootstrap naming remain fork-only until the official follow-up covers them. Verification: - Official attachment-focused web and client-runtime tests pass (7 files, 196 tests). - Targeted client-runtime, web, and mobile typechecks pass; the existing client-runtime Effect diagnostic remains advisory. Rebase notes: - Upstream PR pingdotgg#8236 should supersede the web/client-runtime implementation wholesale once merged. - Upstream PR pingdotgg#8237 should supersede the temporary mobile filename row with signed mobile downloads and full mobile file picking/sharing. - Recheck only the transcript-bootstrap filename summary after both PRs land. - The v0.0.36 stashShortcutLabel test fixture is the only adaptation to the rebased official PR tree.
Intent: Expose the generic-file backend shipped in v0.0.36 through the web and desktop composer while following the official client implementation closely enough for its upstream PR to replace this patch cleanly. Behavior: - Accept images and generic files through the paperclip button, paste, and drag-and-drop; share the eight-attachment limit and use the server-advertised generic-file limit, currently 50 MB. - Upload while the user composes, show progress/retry/reattach states, and render sent files as signed downloads with their original names. - Preserve file drafts and stashes as server upload references or explicit needs-reattach markers instead of storing generic-file bytes in localStorage. - Keep upload verification, cleanup, retry, environment moves, and unknown attachment rendering explicit. - Show file names in the current mobile feed and include attachment names in transcript bootstrap context. Design constraints: - Backport official upstream PR pingdotgg#8236 at 129f2ad, rebased onto v0.0.36, rather than maintaining a parallel client upload architecture. - Use packages/client-runtime for the shared upload lifecycle and clamp file sizes to the server capability and contract maximum. - Require direct-upload support for generic files. Do not retain the fork inline-file protocol or serialize generic-file bytes into drafts and stashes. - Upload local workspace drops like the official client; do not retain the competing desktop-only drop-to-mention behavior. - Keep images on their established compression and compatibility path. Integration: - Shared client-runtime upload lifecycle and web environment atoms. - Web composer, drafts, prompt stashes, upload queue, message timeline, signed asset downloads, sidebar counts, project cleanup, and user documentation. - Minimal current mobile feed visibility and transcript bootstrap naming remain fork-only until the official follow-up covers them. Verification: - Official attachment-focused web and client-runtime tests pass (7 files, 196 tests). - Targeted client-runtime, web, and mobile typechecks pass; the existing client-runtime Effect diagnostic remains advisory. Rebase notes: - Upstream PR pingdotgg#8236 should supersede the web/client-runtime implementation wholesale once merged. - Upstream PR pingdotgg#8237 should supersede the temporary mobile filename row with signed mobile downloads and full mobile file picking/sharing. - Recheck only the transcript-bootstrap filename summary after both PRs land. - The v0.0.36 stashShortcutLabel test fixture is the only adaptation to the rebased official PR tree.
|
@juliusmarminge you down to push this one over the finish line? |

The web file attachment foundation is now merged in #8236. This PR now contains only the mobile client work. Mobile can attach photos today, but it cannot pick documents or keep files shared from other apps.
The composer offers Photos and Files when the connected server supports file uploads. The native share sheet accepts files, audio, and video, then routes them into a project draft. The thread feed renders file attachments as rows that open with the original filename. Unknown attachment types render as inert rows.
The shared upload flow verifies, transfers, and releases pending uploads. One outbox removal path releases local files. Revision checks prevent stale outbox writes from replacing newer edits. Share cleanup deletes only files under app-owned directories, so an iOS open-in-place share cannot delete the sender's document.
The Android share fix now patches
expo-sharing@57.0.16for Expo SDK 57. It keeps the source filename, treats shared text streams as files, and keeps accompanying text.Native release requirement: the share registration and native module patch need new iOS and Android builds. Ship those builds before a compatible OTA relies on file share registration. Device verification is still required for native sharing, the Android patch, file picking, and download naming.
Release warning: clients with the old image-only attachment contract cannot decode threads that contain file attachments. The tolerant contract in #8235 and the feed support in this PR must ship before the web client exposes file uploads.
Original work by Theo Browne with Claude Fable 5 in the Claude Code harness. Modernized by GPT-5.6 Sol in the Codex harness.
Note
Medium Risk
Touches native share intents, local file lifecycle, and server upload/delete paths; mistakes could leak storage or mishandle user-owned URIs, though ownership checks and extensive tests mitigate this. Requires new native builds for broad share MIME registration and the patched
expo-sharingmodule.Overview
Extends the mobile composer beyond images to generic file attachments end-to-end: pick/copy into app-owned storage, show file chips in the attachment strip, upload pending server bytes before
startTurn, and render downloadable file rows in the thread feed (with inert rows for unknown types).Share sheet and system share targets now accept documents (iOS
supportsFileWithMaxCount, Android*/*). Incoming shares persist PDFs and similar without base64, enforce size limits, filter by destination server capabilities, and only delete files under owned sandbox/App Group paths so open-in-place shares cannot wipe the sender’s document. The share inbox rolls back persisted copies if the durable draft write fails.Composer UX adds Photos vs Files when the server advertises
fileAttachments, gates share import until server config is known for file shares, and sweeps unused local files after import/cancel/send. Outbox/editor reliability moves removal helpers tothread-outbox-removal, chains pending-task editor flushes with revision CAS, and reuses pending uploads across retry attempts viaprepareTurnAttachments.Reviewed by Cursor Bugbot for commit ae9086c. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Add file picking, sharing, and receiving to mobile threads
DraftComposerAttachmentacross the composer, outbox, and incoming share flowspickComposerFilesandpersistComposerAttachmentFilein composerImages.ts to copy picked files to app storage while enforcing per-message count and size limitsupdate,remove, andclearEnvironmentto handle concurrent edits safelyexpo-sharingin expo-sharing@57.0.16.patch to extractoriginalNamevia the Android content resolver and handle mixed text/file payloadsupdateandremovenow conditionally requireexpectedRevision; removal and environment clear logic moved to thread-outbox-removal.ts and callers bypassing it will miss automatic attachment cleanupMacroscope summarized ae9086c.