From 9b21be2561ec0990b498c26162c5adca29f1e1bf Mon Sep 17 00:00:00 2001 From: Nemanja Stojanovic Date: Mon, 22 Dec 2025 22:03:22 -0500 Subject: [PATCH] fix: handle uppercase image extensions when pasting file paths Bun.file() only recognizes lowercase file extensions for MIME type detection. When dragging images from Finder on macOS, files often have uppercase extensions like .PNG or .JPG, which causes Bun to return 'application/octet-stream' instead of the correct image MIME type. This meant pasted image paths were not recognized as images and wouldn't display the [Image 1] UI indicator. The fix adds a helper function that extracts the file extension, normalizes it to lowercase, and looks up the correct MIME type from a known list of image extensions. --- .../cli/cmd/tui/component/prompt/index.tsx | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx index 47940d0e234..b00e1008bc0 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx @@ -49,6 +49,22 @@ export type PromptRef = { const PLACEHOLDERS = ["Fix a TODO in the codebase", "What is the tech stack of this project?", "Fix broken tests"] +// Bun.file() only recognizes lowercase extensions, so uppercase extensions like .PNG, .JPG +// return "application/octet-stream". This function returns the correct MIME type. +const IMAGE_EXTENSIONS: Record = { + ".png": "image/png", + ".jpg": "image/jpeg", + ".jpeg": "image/jpeg", + ".gif": "image/gif", + ".webp": "image/webp", + ".svg": "image/svg+xml", +} + +function getImageMime(filepath: string): string | undefined { + const ext = filepath.slice(filepath.lastIndexOf(".")).toLowerCase() + return IMAGE_EXTENSIONS[ext] +} + const TEXTAREA_ACTIONS = [ "submit", "newline", @@ -836,8 +852,11 @@ export function Prompt(props: PromptProps) { if (!isUrl) { try { const file = Bun.file(filepath) + // Bun.file() only recognizes lowercase extensions, so use our helper + // to get the correct MIME type for uppercase extensions like .PNG, .JPG + const mime = getImageMime(filepath) ?? file.type // Handle SVG as raw text content, not as base64 image - if (file.type === "image/svg+xml") { + if (mime === "image/svg+xml") { event.preventDefault() const content = await file.text().catch(() => {}) if (content) { @@ -845,7 +864,7 @@ export function Prompt(props: PromptProps) { return } } - if (file.type.startsWith("image/")) { + if (mime.startsWith("image/")) { event.preventDefault() const content = await file .arrayBuffer() @@ -854,7 +873,7 @@ export function Prompt(props: PromptProps) { if (content) { await pasteImage({ filename: file.name, - mime: file.type, + mime, content, }) return