mirror of
https://gitea.toothfairyai.com/ToothFairyAI/tf_code.git
synced 2026-04-03 23:53:46 +00:00
tui: add persistent key-value storage for user preferences
- Add KVProvider context for storing user preferences like theme and warnings - Update theme context to use KV storage instead of sync config - Move openrouter warning to persistent KV storage - Refactor theme selection to persist user choice across sessions
This commit is contained in:
45
packages/opencode/src/cli/cmd/tui/context/kv.tsx
Normal file
45
packages/opencode/src/cli/cmd/tui/context/kv.tsx
Normal file
@@ -0,0 +1,45 @@
|
||||
import { Global } from "@/global"
|
||||
import { createSignal } from "solid-js"
|
||||
import { createStore } from "solid-js/store"
|
||||
import { createSimpleContext } from "./helper"
|
||||
import path from "path"
|
||||
|
||||
export const { use: useKV, provider: KVProvider } = createSimpleContext({
|
||||
name: "KV",
|
||||
init: () => {
|
||||
const [ready, setReady] = createSignal(false)
|
||||
const [kvStore, setKvStore] = createStore({
|
||||
openrouter_warning: false,
|
||||
theme: "opencode",
|
||||
})
|
||||
const file = Bun.file(path.join(Global.Path.state, "kv.json"))
|
||||
|
||||
file
|
||||
.json()
|
||||
.then((x) => {
|
||||
setKvStore(x)
|
||||
})
|
||||
.catch(() => {})
|
||||
.finally(() => {
|
||||
setReady(true)
|
||||
})
|
||||
|
||||
return {
|
||||
get data() {
|
||||
return kvStore
|
||||
},
|
||||
get ready() {
|
||||
return ready()
|
||||
},
|
||||
set(key: string, value: any) {
|
||||
setKvStore(key as any, value)
|
||||
Bun.write(
|
||||
file,
|
||||
JSON.stringify({
|
||||
[key]: value,
|
||||
}),
|
||||
)
|
||||
},
|
||||
}
|
||||
},
|
||||
})
|
||||
@@ -15,17 +15,18 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
|
||||
const sync = useSync()
|
||||
const toast = useToast()
|
||||
|
||||
function isModelValid(model: { providerID: string, modelID: string }) {
|
||||
function isModelValid(model: { providerID: string; modelID: string }) {
|
||||
const provider = sync.data.provider.find((x) => x.id === model.providerID)
|
||||
return !!provider?.models[model.modelID]
|
||||
}
|
||||
|
||||
function getFirstValidModel(...modelFns: (() => { providerID: string, modelID: string } | undefined)[]) {
|
||||
function getFirstValidModel(
|
||||
...modelFns: (() => { providerID: string; modelID: string } | undefined)[]
|
||||
) {
|
||||
for (const modelFn of modelFns) {
|
||||
const model = modelFn()
|
||||
if (!model) continue
|
||||
if (isModelValid(model))
|
||||
return model
|
||||
if (isModelValid(model)) return model
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,7 +142,7 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
|
||||
.then((x) => {
|
||||
setModelStore("recent", x.recent)
|
||||
})
|
||||
.catch(() => { })
|
||||
.catch(() => {})
|
||||
.finally(() => {
|
||||
setModelStore("ready", true)
|
||||
})
|
||||
@@ -227,49 +228,9 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
|
||||
}
|
||||
})
|
||||
|
||||
const kv = iife(() => {
|
||||
const [ready, setReady] = createSignal(false)
|
||||
const [kvStore, setKvStore] = createStore({
|
||||
openrouter_warning: false,
|
||||
})
|
||||
const file = Bun.file(path.join(Global.Path.state, "kv.json"))
|
||||
|
||||
file
|
||||
.json()
|
||||
.then((x) => {
|
||||
setKvStore(x)
|
||||
})
|
||||
.catch(() => { })
|
||||
.finally(() => {
|
||||
setReady(true)
|
||||
})
|
||||
|
||||
return {
|
||||
get data() {
|
||||
return kvStore
|
||||
},
|
||||
get ready() {
|
||||
return ready()
|
||||
},
|
||||
set(key: string, value: any) {
|
||||
setKvStore(key as any, value)
|
||||
Bun.write(
|
||||
file,
|
||||
JSON.stringify({
|
||||
[key]: value,
|
||||
}),
|
||||
)
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
const result = {
|
||||
model,
|
||||
agent,
|
||||
kv,
|
||||
get ready() {
|
||||
return kv.ready && model.ready
|
||||
},
|
||||
}
|
||||
return result
|
||||
},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { SyntaxStyle, RGBA } from "@opentui/core"
|
||||
import { createMemo, createSignal, createEffect } from "solid-js"
|
||||
import { createMemo } from "solid-js"
|
||||
import { useSync } from "@tui/context/sync"
|
||||
import { createSimpleContext } from "./helper"
|
||||
import aura from "../../../../../../tui/internal/theme/themes/aura.json" with { type: "json" }
|
||||
@@ -24,8 +24,7 @@ import synthwave84 from "../../../../../../tui/internal/theme/themes/synthwave84
|
||||
import tokyonight from "../../../../../../tui/internal/theme/themes/tokyonight.json" with { type: "json" }
|
||||
import vesper from "../../../../../../tui/internal/theme/themes/vesper.json" with { type: "json" }
|
||||
import zenburn from "../../../../../../tui/internal/theme/themes/zenburn.json" with { type: "json" }
|
||||
import { iife } from "@/util/iife"
|
||||
import { createStore, reconcile } from "solid-js/store"
|
||||
import { useKV } from "./kv"
|
||||
|
||||
type Theme = {
|
||||
primary: RGBA
|
||||
@@ -628,28 +627,28 @@ export const { use: useTheme, provider: ThemeProvider } = createSimpleContext({
|
||||
name: "Theme",
|
||||
init: () => {
|
||||
const sync = useSync()
|
||||
const [selectedTheme, setSelectedTheme] = createSignal<keyof typeof THEMES>("opencode")
|
||||
const [theme, setTheme] = createStore({} as Theme)
|
||||
createEffect(() => {
|
||||
if (!sync.ready) return
|
||||
setSelectedTheme(
|
||||
iife(() => {
|
||||
if (typeof sync.data.config.theme === "string" && sync.data.config.theme in THEMES) {
|
||||
return sync.data.config.theme as keyof typeof THEMES
|
||||
}
|
||||
return "opencode"
|
||||
}),
|
||||
)
|
||||
})
|
||||
const kv = useKV()
|
||||
|
||||
createEffect(() => {
|
||||
setTheme(reconcile(THEMES[selectedTheme()]))
|
||||
const theme = createMemo(() => {
|
||||
console.log(kv.data.theme)
|
||||
return { ...(THEMES[kv.data.theme as keyof typeof THEMES] ?? THEMES.opencode) }
|
||||
})
|
||||
|
||||
return {
|
||||
theme,
|
||||
selectedTheme,
|
||||
setSelectedTheme,
|
||||
get theme() {
|
||||
return new Proxy(theme(), {
|
||||
get(_target, prop) {
|
||||
// @ts-expect-error
|
||||
return theme()[prop]
|
||||
},
|
||||
})
|
||||
},
|
||||
get selectedTheme() {
|
||||
return kv.data.theme
|
||||
},
|
||||
setSelectedTheme(theme: string) {
|
||||
kv.set("theme", theme)
|
||||
},
|
||||
get ready() {
|
||||
return sync.ready
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user