Compare commits
2 commits
dev
...
kit/fs-tui
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
58a8d4dbf5 | ||
|
|
d8070f7f23 |
8 changed files with 45 additions and 38 deletions
|
|
@ -1,10 +1,9 @@
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import { Global } from "@/global"
|
import { Global } from "@/global"
|
||||||
import { Filesystem } from "@/util/filesystem"
|
|
||||||
import { onMount } from "solid-js"
|
import { onMount } from "solid-js"
|
||||||
import { createStore } from "solid-js/store"
|
import { createStore } from "solid-js/store"
|
||||||
import { createSimpleContext } from "../../context/helper"
|
import { createSimpleContext } from "../../context/helper"
|
||||||
import { appendFile, writeFile } from "fs/promises"
|
import { appendFile } from "fs/promises"
|
||||||
|
|
||||||
function calculateFrecency(entry?: { frequency: number; lastOpen: number }): number {
|
function calculateFrecency(entry?: { frequency: number; lastOpen: number }): number {
|
||||||
if (!entry) return 0
|
if (!entry) return 0
|
||||||
|
|
@ -20,7 +19,9 @@ export const { use: useFrecency, provider: FrecencyProvider } = createSimpleCont
|
||||||
init: () => {
|
init: () => {
|
||||||
const frecencyPath = path.join(Global.Path.state, "frecency.jsonl")
|
const frecencyPath = path.join(Global.Path.state, "frecency.jsonl")
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
const text = await Filesystem.readText(frecencyPath).catch(() => "")
|
const text = await Bun.file(frecencyPath)
|
||||||
|
.text()
|
||||||
|
.catch(() => "")
|
||||||
const lines = text
|
const lines = text
|
||||||
.split("\n")
|
.split("\n")
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
|
|
@ -54,7 +55,7 @@ export const { use: useFrecency, provider: FrecencyProvider } = createSimpleCont
|
||||||
|
|
||||||
if (sorted.length > 0) {
|
if (sorted.length > 0) {
|
||||||
const content = sorted.map((entry) => JSON.stringify(entry)).join("\n") + "\n"
|
const content = sorted.map((entry) => JSON.stringify(entry)).join("\n") + "\n"
|
||||||
writeFile(frecencyPath, content).catch(() => {})
|
void Bun.write(frecencyPath, content)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -77,7 +78,7 @@ export const { use: useFrecency, provider: FrecencyProvider } = createSimpleCont
|
||||||
.slice(0, MAX_FRECENCY_ENTRIES)
|
.slice(0, MAX_FRECENCY_ENTRIES)
|
||||||
setStore("data", Object.fromEntries(sorted))
|
setStore("data", Object.fromEntries(sorted))
|
||||||
const content = sorted.map(([path, entry]) => JSON.stringify({ path, ...entry })).join("\n") + "\n"
|
const content = sorted.map(([path, entry]) => JSON.stringify({ path, ...entry })).join("\n") + "\n"
|
||||||
writeFile(frecencyPath, content).catch(() => {})
|
void Bun.write(frecencyPath, content)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import { Global } from "@/global"
|
import { Global } from "@/global"
|
||||||
import { Filesystem } from "@/util/filesystem"
|
|
||||||
import { onMount } from "solid-js"
|
import { onMount } from "solid-js"
|
||||||
import { createStore, produce, unwrap } from "solid-js/store"
|
import { createStore, produce, unwrap } from "solid-js/store"
|
||||||
import { createSimpleContext } from "../../context/helper"
|
import { createSimpleContext } from "../../context/helper"
|
||||||
import { appendFile, writeFile } from "fs/promises"
|
import { appendFile } from "fs/promises"
|
||||||
import type { AgentPart, FilePart, TextPart } from "@opencode-ai/sdk/v2"
|
import type { AgentPart, FilePart, TextPart } from "@opencode-ai/sdk/v2"
|
||||||
|
|
||||||
export type PromptInfo = {
|
export type PromptInfo = {
|
||||||
|
|
@ -32,7 +31,9 @@ export const { use: usePromptHistory, provider: PromptHistoryProvider } = create
|
||||||
init: () => {
|
init: () => {
|
||||||
const historyPath = path.join(Global.Path.state, "prompt-history.jsonl")
|
const historyPath = path.join(Global.Path.state, "prompt-history.jsonl")
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
const text = await Filesystem.readText(historyPath).catch(() => "")
|
const text = await Bun.file(historyPath)
|
||||||
|
.text()
|
||||||
|
.catch(() => "")
|
||||||
const lines = text
|
const lines = text
|
||||||
.split("\n")
|
.split("\n")
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
|
|
@ -51,7 +52,7 @@ export const { use: usePromptHistory, provider: PromptHistoryProvider } = create
|
||||||
// Rewrite file with only valid entries to self-heal corruption
|
// Rewrite file with only valid entries to self-heal corruption
|
||||||
if (lines.length > 0) {
|
if (lines.length > 0) {
|
||||||
const content = lines.map((line) => JSON.stringify(line)).join("\n") + "\n"
|
const content = lines.map((line) => JSON.stringify(line)).join("\n") + "\n"
|
||||||
writeFile(historyPath, content).catch(() => {})
|
void Bun.write(historyPath, content)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -97,7 +98,7 @@ export const { use: usePromptHistory, provider: PromptHistoryProvider } = create
|
||||||
|
|
||||||
if (trimmed) {
|
if (trimmed) {
|
||||||
const content = store.history.map((line) => JSON.stringify(line)).join("\n") + "\n"
|
const content = store.history.map((line) => JSON.stringify(line)).join("\n") + "\n"
|
||||||
writeFile(historyPath, content).catch(() => {})
|
void Bun.write(historyPath, content)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import { Global } from "@/global"
|
import { Global } from "@/global"
|
||||||
import { Filesystem } from "@/util/filesystem"
|
|
||||||
import { onMount } from "solid-js"
|
import { onMount } from "solid-js"
|
||||||
import { createStore, produce, unwrap } from "solid-js/store"
|
import { createStore, produce, unwrap } from "solid-js/store"
|
||||||
import { createSimpleContext } from "../../context/helper"
|
import { createSimpleContext } from "../../context/helper"
|
||||||
import { appendFile, writeFile } from "fs/promises"
|
import { appendFile } from "fs/promises"
|
||||||
import type { PromptInfo } from "./history"
|
import type { PromptInfo } from "./history"
|
||||||
|
|
||||||
export type StashEntry = {
|
export type StashEntry = {
|
||||||
|
|
@ -20,7 +19,9 @@ export const { use: usePromptStash, provider: PromptStashProvider } = createSimp
|
||||||
init: () => {
|
init: () => {
|
||||||
const stashPath = path.join(Global.Path.state, "prompt-stash.jsonl")
|
const stashPath = path.join(Global.Path.state, "prompt-stash.jsonl")
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
const text = await Filesystem.readText(stashPath).catch(() => "")
|
const text = await Bun.file(stashPath)
|
||||||
|
.text()
|
||||||
|
.catch(() => "")
|
||||||
const lines = text
|
const lines = text
|
||||||
.split("\n")
|
.split("\n")
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
|
|
@ -39,7 +40,7 @@ export const { use: usePromptStash, provider: PromptStashProvider } = createSimp
|
||||||
// Rewrite file with only valid entries to self-heal corruption
|
// Rewrite file with only valid entries to self-heal corruption
|
||||||
if (lines.length > 0) {
|
if (lines.length > 0) {
|
||||||
const content = lines.map((line) => JSON.stringify(line)).join("\n") + "\n"
|
const content = lines.map((line) => JSON.stringify(line)).join("\n") + "\n"
|
||||||
writeFile(stashPath, content).catch(() => {})
|
void Bun.write(stashPath, content)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -66,7 +67,7 @@ export const { use: usePromptStash, provider: PromptStashProvider } = createSimp
|
||||||
|
|
||||||
if (trimmed) {
|
if (trimmed) {
|
||||||
const content = store.entries.map((line) => JSON.stringify(line)).join("\n") + "\n"
|
const content = store.entries.map((line) => JSON.stringify(line)).join("\n") + "\n"
|
||||||
writeFile(stashPath, content).catch(() => {})
|
void Bun.write(stashPath, content)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -82,7 +83,7 @@ export const { use: usePromptStash, provider: PromptStashProvider } = createSimp
|
||||||
)
|
)
|
||||||
const content =
|
const content =
|
||||||
store.entries.length > 0 ? store.entries.map((line) => JSON.stringify(line)).join("\n") + "\n" : ""
|
store.entries.length > 0 ? store.entries.map((line) => JSON.stringify(line)).join("\n") + "\n" : ""
|
||||||
writeFile(stashPath, content).catch(() => {})
|
void Bun.write(stashPath, content)
|
||||||
return entry
|
return entry
|
||||||
},
|
},
|
||||||
remove(index: number) {
|
remove(index: number) {
|
||||||
|
|
@ -94,7 +95,7 @@ export const { use: usePromptStash, provider: PromptStashProvider } = createSimp
|
||||||
)
|
)
|
||||||
const content =
|
const content =
|
||||||
store.entries.length > 0 ? store.entries.map((line) => JSON.stringify(line)).join("\n") + "\n" : ""
|
store.entries.length > 0 ? store.entries.map((line) => JSON.stringify(line)).join("\n") + "\n" : ""
|
||||||
writeFile(stashPath, content).catch(() => {})
|
void Bun.write(stashPath, content)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import { Global } from "@/global"
|
import { Global } from "@/global"
|
||||||
import { Filesystem } from "@/util/filesystem"
|
|
||||||
import { createSignal, type Setter } from "solid-js"
|
import { createSignal, type Setter } from "solid-js"
|
||||||
import { createStore } from "solid-js/store"
|
import { createStore } from "solid-js/store"
|
||||||
import { createSimpleContext } from "./helper"
|
import { createSimpleContext } from "./helper"
|
||||||
|
|
@ -12,9 +11,10 @@ export const { use: useKV, provider: KVProvider } = createSimpleContext({
|
||||||
const [store, setStore] = createStore<Record<string, any>>()
|
const [store, setStore] = createStore<Record<string, any>>()
|
||||||
const filePath = path.join(Global.Path.state, "kv.json")
|
const filePath = path.join(Global.Path.state, "kv.json")
|
||||||
|
|
||||||
Filesystem.readJson(filePath)
|
Bun.file(filePath)
|
||||||
|
.json()
|
||||||
.then((x) => {
|
.then((x) => {
|
||||||
setStore(x)
|
if (typeof x === "object" && x !== null) setStore(x as Record<string, any>)
|
||||||
})
|
})
|
||||||
.catch(() => {})
|
.catch(() => {})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
|
|
@ -44,7 +44,7 @@ export const { use: useKV, provider: KVProvider } = createSimpleContext({
|
||||||
},
|
},
|
||||||
set(key: string, value: any) {
|
set(key: string, value: any) {
|
||||||
setStore(key, value)
|
setStore(key, value)
|
||||||
Filesystem.writeJson(filePath, store)
|
void Bun.write(filePath, JSON.stringify(store, null, 2))
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,6 @@ import { Provider } from "@/provider/provider"
|
||||||
import { useArgs } from "./args"
|
import { useArgs } from "./args"
|
||||||
import { useSDK } from "./sdk"
|
import { useSDK } from "./sdk"
|
||||||
import { RGBA } from "@opentui/core"
|
import { RGBA } from "@opentui/core"
|
||||||
import { Filesystem } from "@/util/filesystem"
|
|
||||||
|
|
||||||
export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
|
export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
|
||||||
name: "Local",
|
name: "Local",
|
||||||
|
|
@ -131,14 +130,22 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
state.pending = false
|
state.pending = false
|
||||||
Filesystem.writeJson(filePath, {
|
void Bun.write(
|
||||||
recent: modelStore.recent,
|
filePath,
|
||||||
favorite: modelStore.favorite,
|
JSON.stringify(
|
||||||
variant: modelStore.variant,
|
{
|
||||||
})
|
recent: modelStore.recent,
|
||||||
|
favorite: modelStore.favorite,
|
||||||
|
variant: modelStore.variant,
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
2,
|
||||||
|
),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Filesystem.readJson(filePath)
|
Bun.file(filePath)
|
||||||
|
.json()
|
||||||
.then((x: any) => {
|
.then((x: any) => {
|
||||||
if (Array.isArray(x.recent)) setModelStore("recent", x.recent)
|
if (Array.isArray(x.recent)) setModelStore("recent", x.recent)
|
||||||
if (Array.isArray(x.favorite)) setModelStore("favorite", x.favorite)
|
if (Array.isArray(x.favorite)) setModelStore("favorite", x.favorite)
|
||||||
|
|
|
||||||
|
|
@ -74,8 +74,8 @@ import { Editor } from "../../util/editor"
|
||||||
import stripAnsi from "strip-ansi"
|
import stripAnsi from "strip-ansi"
|
||||||
import { usePromptRef } from "../../context/prompt"
|
import { usePromptRef } from "../../context/prompt"
|
||||||
import { useExit } from "../../context/exit"
|
import { useExit } from "../../context/exit"
|
||||||
import { Filesystem } from "@/util/filesystem"
|
|
||||||
import { Global } from "@/global"
|
import { Global } from "@/global"
|
||||||
|
import { AppFileSystem } from "@opencode-ai/shared/filesystem"
|
||||||
import { PermissionPrompt } from "./permission"
|
import { PermissionPrompt } from "./permission"
|
||||||
import { QuestionPrompt } from "./question"
|
import { QuestionPrompt } from "./question"
|
||||||
import { DialogExportOptions } from "../../ui/dialog-export-options"
|
import { DialogExportOptions } from "../../ui/dialog-export-options"
|
||||||
|
|
@ -916,12 +916,12 @@ export function Session() {
|
||||||
const filename = options.filename.trim()
|
const filename = options.filename.trim()
|
||||||
const filepath = path.join(exportDir, filename)
|
const filepath = path.join(exportDir, filename)
|
||||||
|
|
||||||
await Filesystem.write(filepath, transcript)
|
await Bun.write(filepath, transcript)
|
||||||
|
|
||||||
// Open with EDITOR if available
|
// Open with EDITOR if available
|
||||||
const result = await Editor.open({ value: transcript, renderer })
|
const result = await Editor.open({ value: transcript, renderer })
|
||||||
if (result !== undefined) {
|
if (result !== undefined) {
|
||||||
await Filesystem.write(filepath, result)
|
await Bun.write(filepath, result)
|
||||||
}
|
}
|
||||||
|
|
||||||
toast.show({ message: `Session exported to ${filename}`, variant: "success" })
|
toast.show({ message: `Session exported to ${filename}`, variant: "success" })
|
||||||
|
|
@ -2236,7 +2236,7 @@ function Skill(props: ToolProps<typeof SkillTool>) {
|
||||||
function Diagnostics(props: { diagnostics?: Record<string, Record<string, any>[]>; filePath: string }) {
|
function Diagnostics(props: { diagnostics?: Record<string, Record<string, any>[]>; filePath: string }) {
|
||||||
const { theme } = useTheme()
|
const { theme } = useTheme()
|
||||||
const errors = createMemo(() => {
|
const errors = createMemo(() => {
|
||||||
const normalized = Filesystem.normalizePath(props.filePath)
|
const normalized = AppFileSystem.normalizePath(props.filePath)
|
||||||
const arr = props.diagnostics?.[normalized] ?? []
|
const arr = props.diagnostics?.[normalized] ?? []
|
||||||
return arr.filter((x) => x.severity === 1).slice(0, 3)
|
return arr.filter((x) => x.severity === 1).slice(0, 3)
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ import { lazy } from "../../../../util/lazy.js"
|
||||||
import { tmpdir } from "os"
|
import { tmpdir } from "os"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import fs from "fs/promises"
|
import fs from "fs/promises"
|
||||||
import { Filesystem } from "../../../../util/filesystem"
|
|
||||||
import { Process } from "../../../../util/process"
|
import { Process } from "../../../../util/process"
|
||||||
import { which } from "../../../../util/which"
|
import { which } from "../../../../util/which"
|
||||||
|
|
||||||
|
|
@ -58,8 +57,7 @@ export namespace Clipboard {
|
||||||
],
|
],
|
||||||
{ nothrow: true },
|
{ nothrow: true },
|
||||||
)
|
)
|
||||||
const buffer = await Filesystem.readBytes(tmpfile)
|
return { data: Buffer.from(await Bun.file(tmpfile).arrayBuffer()).toString("base64"), mime: "image/png" }
|
||||||
return { data: buffer.toString("base64"), mime: "image/png" }
|
|
||||||
} catch {
|
} catch {
|
||||||
} finally {
|
} finally {
|
||||||
await fs.rm(tmpfile, { force: true }).catch(() => {})
|
await fs.rm(tmpfile, { force: true }).catch(() => {})
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ import { rm } from "node:fs/promises"
|
||||||
import { tmpdir } from "node:os"
|
import { tmpdir } from "node:os"
|
||||||
import { join } from "node:path"
|
import { join } from "node:path"
|
||||||
import { CliRenderer } from "@opentui/core"
|
import { CliRenderer } from "@opentui/core"
|
||||||
import { Filesystem } from "@/util/filesystem"
|
|
||||||
import { Process } from "@/util/process"
|
import { Process } from "@/util/process"
|
||||||
|
|
||||||
export namespace Editor {
|
export namespace Editor {
|
||||||
|
|
@ -14,7 +13,7 @@ export namespace Editor {
|
||||||
const filepath = join(tmpdir(), `${Date.now()}.md`)
|
const filepath = join(tmpdir(), `${Date.now()}.md`)
|
||||||
await using _ = defer(async () => rm(filepath, { force: true }))
|
await using _ = defer(async () => rm(filepath, { force: true }))
|
||||||
|
|
||||||
await Filesystem.write(filepath, opts.value)
|
await Bun.write(filepath, opts.value)
|
||||||
opts.renderer.suspend()
|
opts.renderer.suspend()
|
||||||
opts.renderer.currentRenderBuffer.clear()
|
opts.renderer.currentRenderBuffer.clear()
|
||||||
try {
|
try {
|
||||||
|
|
@ -26,7 +25,7 @@ export namespace Editor {
|
||||||
shell: process.platform === "win32",
|
shell: process.platform === "win32",
|
||||||
})
|
})
|
||||||
await proc.exited
|
await proc.exited
|
||||||
const content = await Filesystem.readText(filepath)
|
const content = await Bun.file(filepath).text()
|
||||||
return content || undefined
|
return content || undefined
|
||||||
} finally {
|
} finally {
|
||||||
opts.renderer.currentRenderBuffer.clear()
|
opts.renderer.currentRenderBuffer.clear()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue