summaryrefslogtreecommitdiffhomepage
path: root/packages
diff options
context:
space:
mode:
authorkcrommett <[email protected]>2025-10-20 22:52:39 -0700
committerGitHub <[email protected]>2025-10-21 00:52:39 -0500
commita99bd3aa2c0f7100d0bcbfa4a11d818b7c753661 (patch)
tree9557598fbba0d2908f4fce1a46de8f889360b073 /packages
parent96efede846f26c71d2e678d30e88d18c7dafc0d9 (diff)
downloadopencode-a99bd3aa2c0f7100d0bcbfa4a11d818b7c753661.tar.gz
opencode-a99bd3aa2c0f7100d0bcbfa4a11d818b7c753661.zip
tweak: adjust file api to encode images (#3292)
Diffstat (limited to 'packages')
-rw-r--r--packages/opencode/src/file/index.ts67
1 files changed, 63 insertions, 4 deletions
diff --git a/packages/opencode/src/file/index.ts b/packages/opencode/src/file/index.ts
index e5023f0dc..1478de86c 100644
--- a/packages/opencode/src/file/index.ts
+++ b/packages/opencode/src/file/index.ts
@@ -1,6 +1,7 @@
import z from "zod/v4"
import { Bus } from "../bus"
import { $ } from "bun"
+import type { BunFile } from "bun"
import { formatPatch, structuredPatch } from "diff"
import path from "path"
import fs from "fs"
@@ -41,6 +42,7 @@ export namespace File {
export const Content = z
.object({
+ type: z.literal("text"),
content: z.string(),
diff: z.string().optional(),
patch: z
@@ -61,12 +63,53 @@ export namespace File {
index: z.string().optional(),
})
.optional(),
+ encoding: z.literal("base64").optional(),
+ mimeType: z.string().optional(),
})
.meta({
ref: "FileContent",
})
export type Content = z.infer<typeof Content>
+ async function shouldEncode(file: BunFile): Promise<boolean> {
+ const type = file.type?.toLowerCase()
+ if (!type) return false
+
+ if (type.startsWith("text/")) return false
+ if (type.includes("charset=")) return false
+
+ const parts = type.split("/", 2)
+ const top = parts[0]
+ const rest = parts[1] ?? ""
+ const sub = rest.split(";", 1)[0]
+
+ const tops = ["image", "audio", "video", "font", "model", "multipart"]
+ if (tops.includes(top)) return true
+
+ if (type === "application/octet-stream") return true
+
+ const bins = [
+ "zip",
+ "gzip",
+ "bzip",
+ "compressed",
+ "binary",
+ "stream",
+ "pdf",
+ "msword",
+ "powerpoint",
+ "excel",
+ "ogg",
+ "exe",
+ "dmg",
+ "iso",
+ "rar",
+ ]
+ if (bins.some((mark) => sub.includes(mark))) return true
+
+ return false
+ }
+
export const Event = {
Edited: Bus.event(
"file.edited",
@@ -188,14 +231,30 @@ export namespace File {
}))
}
- export async function read(file: string) {
+ export async function read(file: string): Promise<Content> {
using _ = log.time("read", { file })
const project = Instance.project
const full = path.join(Instance.directory, file)
- const content = await Bun.file(full)
+ const bunFile = Bun.file(full)
+
+ if (!(await bunFile.exists())) {
+ return { type: "text", content: "" }
+ }
+
+ const encode = await shouldEncode(bunFile)
+
+ if (encode) {
+ const buffer = await bunFile.arrayBuffer().catch(() => new ArrayBuffer(0))
+ const content = Buffer.from(buffer).toString("base64")
+ const mimeType = bunFile.type || "application/octet-stream"
+ return { type: "text", content, mimeType, encoding: "base64" }
+ }
+
+ const content = await bunFile
.text()
.catch(() => "")
.then((x) => x.trim())
+
if (project.vcs === "git") {
let diff = await $`git diff ${file}`.cwd(Instance.directory).quiet().nothrow().text()
if (!diff.trim()) diff = await $`git diff --staged ${file}`.cwd(Instance.directory).quiet().nothrow().text()
@@ -206,10 +265,10 @@ export namespace File {
ignoreWhitespace: true,
})
const diff = formatPatch(patch)
- return { content, patch, diff }
+ return { type: "text", content, patch, diff }
}
}
- return { content }
+ return { type: "text", content }
}
export async function list(dir?: string) {