From 58a8d4dbf5a9dd84dbe00cfa3675ec0dd8a2afdf Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Wed, 15 Apr 2026 12:40:11 -0400 Subject: [PATCH] refactor(opencode): remove AppRuntime from tui file io --- .../cli/cmd/tui/component/prompt/frecency.tsx | 25 +++---------- .../cli/cmd/tui/component/prompt/history.tsx | 25 +++---------- .../cli/cmd/tui/component/prompt/stash.tsx | 29 ++++----------- .../opencode/src/cli/cmd/tui/context/kv.tsx | 22 ++--------- .../src/cli/cmd/tui/context/local.tsx | 37 +++++++------------ .../src/cli/cmd/tui/routes/session/index.tsx | 13 +------ .../src/cli/cmd/tui/util/clipboard.ts | 11 +----- .../opencode/src/cli/cmd/tui/util/editor.ts | 21 +---------- 8 files changed, 39 insertions(+), 144 deletions(-) diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/frecency.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/frecency.tsx index afb7d5c92a..052f33ca54 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/frecency.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/frecency.tsx @@ -1,8 +1,5 @@ import path from "path" import { Global } from "@/global" -import { AppRuntime } from "@/effect/app-runtime" -import { AppFileSystem } from "@opencode-ai/shared/filesystem" -import { Effect } from "effect" import { onMount } from "solid-js" import { createStore } from "solid-js/store" import { createSimpleContext } from "../../context/helper" @@ -21,22 +18,10 @@ export const { use: useFrecency, provider: FrecencyProvider } = createSimpleCont name: "Frecency", init: () => { const frecencyPath = path.join(Global.Path.state, "frecency.jsonl") - const read = () => - AppRuntime.runPromise( - Effect.gen(function* () { - const fs = yield* AppFileSystem.Service - return yield* fs.readFileString(frecencyPath) - }), - ) - const write = (content: string) => - AppRuntime.runPromise( - Effect.gen(function* () { - const fs = yield* AppFileSystem.Service - yield* fs.writeWithDirs(frecencyPath, content) - }), - ) onMount(async () => { - const text = await read().catch(() => "") + const text = await Bun.file(frecencyPath) + .text() + .catch(() => "") const lines = text .split("\n") .filter(Boolean) @@ -70,7 +55,7 @@ export const { use: useFrecency, provider: FrecencyProvider } = createSimpleCont if (sorted.length > 0) { const content = sorted.map((entry) => JSON.stringify(entry)).join("\n") + "\n" - write(content).catch(() => {}) + void Bun.write(frecencyPath, content) } }) @@ -93,7 +78,7 @@ export const { use: useFrecency, provider: FrecencyProvider } = createSimpleCont .slice(0, MAX_FRECENCY_ENTRIES) setStore("data", Object.fromEntries(sorted)) const content = sorted.map(([path, entry]) => JSON.stringify({ path, ...entry })).join("\n") + "\n" - write(content).catch(() => {}) + void Bun.write(frecencyPath, content) } } diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/history.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/history.tsx index 03c5fde505..f9aa97f9e3 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/history.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/history.tsx @@ -1,8 +1,5 @@ import path from "path" import { Global } from "@/global" -import { AppRuntime } from "@/effect/app-runtime" -import { AppFileSystem } from "@opencode-ai/shared/filesystem" -import { Effect } from "effect" import { onMount } from "solid-js" import { createStore, produce, unwrap } from "solid-js/store" import { createSimpleContext } from "../../context/helper" @@ -33,22 +30,10 @@ export const { use: usePromptHistory, provider: PromptHistoryProvider } = create name: "PromptHistory", init: () => { const historyPath = path.join(Global.Path.state, "prompt-history.jsonl") - const read = () => - AppRuntime.runPromise( - Effect.gen(function* () { - const fs = yield* AppFileSystem.Service - return yield* fs.readFileString(historyPath) - }), - ) - const write = (content: string) => - AppRuntime.runPromise( - Effect.gen(function* () { - const fs = yield* AppFileSystem.Service - yield* fs.writeWithDirs(historyPath, content) - }), - ) onMount(async () => { - const text = await read().catch(() => "") + const text = await Bun.file(historyPath) + .text() + .catch(() => "") const lines = text .split("\n") .filter(Boolean) @@ -67,7 +52,7 @@ export const { use: usePromptHistory, provider: PromptHistoryProvider } = create // Rewrite file with only valid entries to self-heal corruption if (lines.length > 0) { const content = lines.map((line) => JSON.stringify(line)).join("\n") + "\n" - write(content).catch(() => {}) + void Bun.write(historyPath, content) } }) @@ -113,7 +98,7 @@ export const { use: usePromptHistory, provider: PromptHistoryProvider } = create if (trimmed) { const content = store.history.map((line) => JSON.stringify(line)).join("\n") + "\n" - write(content).catch(() => {}) + void Bun.write(historyPath, content) return } diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/stash.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/stash.tsx index 93f6e8e9d7..8b155ecc12 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/stash.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/stash.tsx @@ -1,8 +1,5 @@ import path from "path" import { Global } from "@/global" -import { AppRuntime } from "@/effect/app-runtime" -import { AppFileSystem } from "@opencode-ai/shared/filesystem" -import { Effect } from "effect" import { onMount } from "solid-js" import { createStore, produce, unwrap } from "solid-js/store" import { createSimpleContext } from "../../context/helper" @@ -21,22 +18,10 @@ export const { use: usePromptStash, provider: PromptStashProvider } = createSimp name: "PromptStash", init: () => { const stashPath = path.join(Global.Path.state, "prompt-stash.jsonl") - const read = () => - AppRuntime.runPromise( - Effect.gen(function* () { - const fs = yield* AppFileSystem.Service - return yield* fs.readFileString(stashPath) - }), - ) - const write = (content: string) => - AppRuntime.runPromise( - Effect.gen(function* () { - const fs = yield* AppFileSystem.Service - yield* fs.writeWithDirs(stashPath, content) - }), - ) onMount(async () => { - const text = await read().catch(() => "") + const text = await Bun.file(stashPath) + .text() + .catch(() => "") const lines = text .split("\n") .filter(Boolean) @@ -55,7 +40,7 @@ export const { use: usePromptStash, provider: PromptStashProvider } = createSimp // Rewrite file with only valid entries to self-heal corruption if (lines.length > 0) { const content = lines.map((line) => JSON.stringify(line)).join("\n") + "\n" - write(content).catch(() => {}) + void Bun.write(stashPath, content) } }) @@ -82,7 +67,7 @@ export const { use: usePromptStash, provider: PromptStashProvider } = createSimp if (trimmed) { const content = store.entries.map((line) => JSON.stringify(line)).join("\n") + "\n" - write(content).catch(() => {}) + void Bun.write(stashPath, content) return } @@ -98,7 +83,7 @@ export const { use: usePromptStash, provider: PromptStashProvider } = createSimp ) const content = store.entries.length > 0 ? store.entries.map((line) => JSON.stringify(line)).join("\n") + "\n" : "" - write(content).catch(() => {}) + void Bun.write(stashPath, content) return entry }, remove(index: number) { @@ -110,7 +95,7 @@ export const { use: usePromptStash, provider: PromptStashProvider } = createSimp ) const content = store.entries.length > 0 ? store.entries.map((line) => JSON.stringify(line)).join("\n") + "\n" : "" - write(content).catch(() => {}) + void Bun.write(stashPath, content) }, } }, diff --git a/packages/opencode/src/cli/cmd/tui/context/kv.tsx b/packages/opencode/src/cli/cmd/tui/context/kv.tsx index 639da36378..6016a3fee1 100644 --- a/packages/opencode/src/cli/cmd/tui/context/kv.tsx +++ b/packages/opencode/src/cli/cmd/tui/context/kv.tsx @@ -1,7 +1,4 @@ import { Global } from "@/global" -import { AppRuntime } from "@/effect/app-runtime" -import { AppFileSystem } from "@opencode-ai/shared/filesystem" -import { Effect } from "effect" import { createSignal, type Setter } from "solid-js" import { createStore } from "solid-js/store" import { createSimpleContext } from "./helper" @@ -13,22 +10,9 @@ export const { use: useKV, provider: KVProvider } = createSimpleContext({ const [ready, setReady] = createSignal(false) const [store, setStore] = createStore>() const filePath = path.join(Global.Path.state, "kv.json") - const read = () => - AppRuntime.runPromise( - Effect.gen(function* () { - const fs = yield* AppFileSystem.Service - return yield* fs.readJson(filePath) - }), - ) - const write = (data: unknown) => - AppRuntime.runPromise( - Effect.gen(function* () { - const fs = yield* AppFileSystem.Service - yield* fs.writeJson(filePath, data) - }), - ) - read() + Bun.file(filePath) + .json() .then((x) => { if (typeof x === "object" && x !== null) setStore(x as Record) }) @@ -60,7 +44,7 @@ export const { use: useKV, provider: KVProvider } = createSimpleContext({ }, set(key: string, value: any) { setStore(key, value) - write(store) + void Bun.write(filePath, JSON.stringify(store, null, 2)) }, } return result diff --git a/packages/opencode/src/cli/cmd/tui/context/local.tsx b/packages/opencode/src/cli/cmd/tui/context/local.tsx index e1a28745cb..7c58f195e0 100644 --- a/packages/opencode/src/cli/cmd/tui/context/local.tsx +++ b/packages/opencode/src/cli/cmd/tui/context/local.tsx @@ -1,14 +1,11 @@ import { createStore } from "solid-js/store" import { batch, createEffect, createMemo } from "solid-js" -import { Effect } from "effect" import { useSync } from "@tui/context/sync" import { useTheme } from "@tui/context/theme" import { uniqueBy } from "remeda" import path from "path" import { Global } from "@/global" -import { AppRuntime } from "@/effect/app-runtime" import { iife } from "@/util/iife" -import { AppFileSystem } from "@opencode-ai/shared/filesystem" import { createSimpleContext } from "./helper" import { useToast } from "../ui/toast" import { Provider } from "@/provider/provider" @@ -126,20 +123,6 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({ const state = { pending: false, } - const read = () => - AppRuntime.runPromise( - Effect.gen(function* () { - const fs = yield* AppFileSystem.Service - return yield* fs.readJson(filePath) - }), - ) - const write = (data: unknown) => - AppRuntime.runPromise( - Effect.gen(function* () { - const fs = yield* AppFileSystem.Service - yield* fs.writeJson(filePath, data) - }), - ) function save() { if (!modelStore.ready) { @@ -147,14 +130,22 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({ return } state.pending = false - write({ - recent: modelStore.recent, - favorite: modelStore.favorite, - variant: modelStore.variant, - }) + void Bun.write( + filePath, + JSON.stringify( + { + recent: modelStore.recent, + favorite: modelStore.favorite, + variant: modelStore.variant, + }, + null, + 2, + ), + ) } - read() + Bun.file(filePath) + .json() .then((x: any) => { if (Array.isArray(x.recent)) setModelStore("recent", x.recent) if (Array.isArray(x.favorite)) setModelStore("favorite", x.favorite) diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx index 4d5d3adf31..584d0edcc6 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx @@ -75,7 +75,6 @@ import stripAnsi from "strip-ansi" import { usePromptRef } from "../../context/prompt" import { useExit } from "../../context/exit" import { Global } from "@/global" -import { AppRuntime } from "@/effect/app-runtime" import { AppFileSystem } from "@opencode-ai/shared/filesystem" import { PermissionPrompt } from "./permission" import { QuestionPrompt } from "./question" @@ -88,7 +87,6 @@ import { getScrollAcceleration } from "../../util/scroll" import { TuiPluginRuntime } from "../../plugin" import { DialogGoUpsell } from "../../component/dialog-go-upsell" import { SessionRetry } from "@/session/retry" -import { Effect } from "effect" addDefaultParsers(parsers.parsers) @@ -917,20 +915,13 @@ export function Session() { const exportDir = process.cwd() const filename = options.filename.trim() const filepath = path.join(exportDir, filename) - const write = (content: string) => - AppRuntime.runPromise( - Effect.gen(function* () { - const fs = yield* AppFileSystem.Service - yield* fs.writeWithDirs(filepath, content) - }), - ) - await write(transcript) + await Bun.write(filepath, transcript) // Open with EDITOR if available const result = await Editor.open({ value: transcript, renderer }) if (result !== undefined) { - await write(result) + await Bun.write(filepath, result) } toast.show({ message: `Session exported to ${filename}`, variant: "success" }) diff --git a/packages/opencode/src/cli/cmd/tui/util/clipboard.ts b/packages/opencode/src/cli/cmd/tui/util/clipboard.ts index df5786ed9a..4533ff9194 100644 --- a/packages/opencode/src/cli/cmd/tui/util/clipboard.ts +++ b/packages/opencode/src/cli/cmd/tui/util/clipboard.ts @@ -1,8 +1,5 @@ import { platform, release } from "os" import clipboardy from "clipboardy" -import { AppRuntime } from "@/effect/app-runtime" -import { AppFileSystem } from "@opencode-ai/shared/filesystem" -import { Effect } from "effect" import { lazy } from "../../../../util/lazy.js" import { tmpdir } from "os" import path from "path" @@ -60,13 +57,7 @@ export namespace Clipboard { ], { nothrow: true }, ) - const buffer = await AppRuntime.runPromise( - Effect.gen(function* () { - const fs = yield* AppFileSystem.Service - return yield* fs.readFile(tmpfile) - }), - ) - return { data: Buffer.from(buffer).toString("base64"), mime: "image/png" } + return { data: Buffer.from(await Bun.file(tmpfile).arrayBuffer()).toString("base64"), mime: "image/png" } } catch { } finally { await fs.rm(tmpfile, { force: true }).catch(() => {}) diff --git a/packages/opencode/src/cli/cmd/tui/util/editor.ts b/packages/opencode/src/cli/cmd/tui/util/editor.ts index 733d4c6a79..15bb07c579 100644 --- a/packages/opencode/src/cli/cmd/tui/util/editor.ts +++ b/packages/opencode/src/cli/cmd/tui/util/editor.ts @@ -1,7 +1,4 @@ import { defer } from "@/util/defer" -import { AppRuntime } from "@/effect/app-runtime" -import { AppFileSystem } from "@opencode-ai/shared/filesystem" -import { Effect } from "effect" import { rm } from "node:fs/promises" import { tmpdir } from "node:os" import { join } from "node:path" @@ -14,23 +11,9 @@ export namespace Editor { if (!editor) return const filepath = join(tmpdir(), `${Date.now()}.md`) - const write = (content: string) => - AppRuntime.runPromise( - Effect.gen(function* () { - const fs = yield* AppFileSystem.Service - yield* fs.writeWithDirs(filepath, content) - }), - ) - const read = () => - AppRuntime.runPromise( - Effect.gen(function* () { - const fs = yield* AppFileSystem.Service - return yield* fs.readFileString(filepath) - }), - ) await using _ = defer(async () => rm(filepath, { force: true })) - await write(opts.value) + await Bun.write(filepath, opts.value) opts.renderer.suspend() opts.renderer.currentRenderBuffer.clear() try { @@ -42,7 +25,7 @@ export namespace Editor { shell: process.platform === "win32", }) await proc.exited - const content = await read() + const content = await Bun.file(filepath).text() return content || undefined } finally { opts.renderer.currentRenderBuffer.clear()