feat(app,cli): camera + file/PDF attachments with HEIC/size normalization#1387
feat(app,cli): camera + file/PDF attachments with HEIC/size normalization#1387jlixfeld wants to merge 11 commits into
Conversation
Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
|
Heads-up for maintainers on the feature flag: the This PR is aimed squarely at the "broken" part — it fixes the silent HEIC drop (the most common failure on iOS, since the gallery/camera hand back HEIC that the CLI's magic-byte check skips) and adds the camera + file/PDF sources. Once this lands, re-enabling that I deliberately did not un-comment it in this PR to keep the diff focused on functionality and let you decide the release timing. Happy to either flip it on here or leave it for a follow-up — your call. |
Add a "Paste from Clipboard" row to the native attachment action sheet. It appears only when the clipboard holds an image (gated by Clipboard.hasImageAsync, which is silent — no iOS paste banner until the user taps it). pasteImage() reads the image via expo-clipboard, stages the base64 to a cacheDirectory file (the upload path needs a file:// URI), then runs it through the existing normalize/thumbhash/size-cap pipeline so pasted images behave identically to picked ones. Native-only; web already has its own paste listener. Adds optionPaste + pasteFailed strings to _default and all 10 locales. Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
Summary
Extends the existing
expImageUploadattachment pipeline (gallery images only today) to the full scope of #1319:App (
packages/happy-app)Clipboard.hasImageAsyncso it only appears when relevant (and stays silent until tapped — no premature iOS paste banner). Pasted bytes are staged to a cache file (the upload path needs afile://URI) and run through the same normalize/thumbhash/upload pipeline as picked images. Web already had its own paste listener.expo-image-pickerlaunchCameraAsync+ camera permission flow (NSCameraUsageDescriptionadded)expo-document-picker(already a dependency, previously unused) — flows through the existing encrypted-blob upload andt:'file'session-event path unchangedattachmentNormalize.ts):detectClaudeImageMime) skips HEIC with only a debug log today, so iPhone photos often never reach the modelCLI (
packages/happy-cli)attachmentContentBlocks.tsand extended beyond images:%PDF-magic →documentcontent blocktext/*mime / known text extension / clean UTF-8 → fenced text block with filename[Note: attachment(s) … were omitted]) instead of today's silent dropTests
attachmentNormalize.spec.ts— 7 cases for the normalization decision logicattachmentContentBlocks.test.ts— 7 cases (image/PDF/text/extension-fallback/unsupported-notice/empty/HEIC)pnpm typecheckclean in happy-app; happy-app suite 594 passed; pre-existing codex/integration failures in happy-cli are untouched by this PR (nosrc/codexfiles in the diff)Test plan
Closes #1319. Related: #1270, #919, #70.
🤖 Generated with Claude Code