mirror of
https://github.com/anomalyco/opencode.git
synced 2026-04-25 15:24:58 +00:00
102 lines
3.1 KiB
TypeScript
102 lines
3.1 KiB
TypeScript
import path from "path"
|
|
import { Global } from "@/global"
|
|
import { onMount } from "solid-js"
|
|
import { createStore, produce } from "solid-js/store"
|
|
import { clone } from "remeda"
|
|
import { createSimpleContext } from "../../context/helper"
|
|
import { appendFile, writeFile } from "fs/promises"
|
|
import type { PromptInfo } from "./history"
|
|
|
|
export type StashEntry = {
|
|
input: string
|
|
parts: PromptInfo["parts"]
|
|
timestamp: number
|
|
}
|
|
|
|
const MAX_STASH_ENTRIES = 50
|
|
|
|
export const { use: usePromptStash, provider: PromptStashProvider } = createSimpleContext({
|
|
name: "PromptStash",
|
|
init: () => {
|
|
const stashFile = Bun.file(path.join(Global.Path.state, "prompt-stash.jsonl"))
|
|
onMount(async () => {
|
|
const text = await stashFile.text().catch(() => "")
|
|
const lines = text
|
|
.split("\n")
|
|
.filter(Boolean)
|
|
.map((line) => {
|
|
try {
|
|
return JSON.parse(line)
|
|
} catch {
|
|
return null
|
|
}
|
|
})
|
|
.filter((line): line is StashEntry => line !== null)
|
|
.slice(-MAX_STASH_ENTRIES)
|
|
|
|
setStore("entries", lines)
|
|
|
|
// 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"
|
|
writeFile(stashFile.name!, content).catch(() => {})
|
|
}
|
|
})
|
|
|
|
const [store, setStore] = createStore({
|
|
entries: [] as StashEntry[],
|
|
})
|
|
|
|
return {
|
|
list() {
|
|
return store.entries
|
|
},
|
|
push(entry: Omit<StashEntry, "timestamp">) {
|
|
const stash = clone({ ...entry, timestamp: Date.now() })
|
|
let trimmed = false
|
|
setStore(
|
|
produce((draft) => {
|
|
draft.entries.push(stash)
|
|
if (draft.entries.length > MAX_STASH_ENTRIES) {
|
|
draft.entries = draft.entries.slice(-MAX_STASH_ENTRIES)
|
|
trimmed = true
|
|
}
|
|
}),
|
|
)
|
|
|
|
if (trimmed) {
|
|
const content = store.entries.map((line) => JSON.stringify(line)).join("\n") + "\n"
|
|
writeFile(stashFile.name!, content).catch(() => {})
|
|
return
|
|
}
|
|
|
|
appendFile(stashFile.name!, JSON.stringify(stash) + "\n").catch(() => {})
|
|
},
|
|
pop() {
|
|
if (store.entries.length === 0) return undefined
|
|
const entry = store.entries[store.entries.length - 1]
|
|
setStore(
|
|
produce((draft) => {
|
|
draft.entries.pop()
|
|
}),
|
|
)
|
|
const content =
|
|
store.entries.length > 0 ? store.entries.map((line) => JSON.stringify(line)).join("\n") + "\n" : ""
|
|
writeFile(stashFile.name!, content).catch(() => {})
|
|
return entry
|
|
},
|
|
remove(index: number) {
|
|
if (index < 0 || index >= store.entries.length) return
|
|
setStore(
|
|
produce((draft) => {
|
|
draft.entries.splice(index, 1)
|
|
}),
|
|
)
|
|
const content =
|
|
store.entries.length > 0 ? store.entries.map((line) => JSON.stringify(line)).join("\n") + "\n" : ""
|
|
writeFile(stashFile.name!, content).catch(() => {})
|
|
},
|
|
}
|
|
},
|
|
})
|