feat(app): persist workspace branch
This commit is contained in:
@@ -19,15 +19,27 @@ import {
|
|||||||
type QuestionRequest,
|
type QuestionRequest,
|
||||||
createOpencodeClient,
|
createOpencodeClient,
|
||||||
} from "@opencode-ai/sdk/v2/client"
|
} from "@opencode-ai/sdk/v2/client"
|
||||||
import { createStore, produce, reconcile } from "solid-js/store"
|
import { createStore, produce, reconcile, type SetStoreFunction, type Store } from "solid-js/store"
|
||||||
import { Binary } from "@opencode-ai/util/binary"
|
import { Binary } from "@opencode-ai/util/binary"
|
||||||
import { retry } from "@opencode-ai/util/retry"
|
import { retry } from "@opencode-ai/util/retry"
|
||||||
import { useGlobalSDK } from "./global-sdk"
|
import { useGlobalSDK } from "./global-sdk"
|
||||||
import { ErrorPage, type InitError } from "../pages/error"
|
import { ErrorPage, type InitError } from "../pages/error"
|
||||||
import { batch, createContext, useContext, onCleanup, onMount, type ParentProps, Switch, Match } from "solid-js"
|
import {
|
||||||
|
batch,
|
||||||
|
createContext,
|
||||||
|
createEffect,
|
||||||
|
useContext,
|
||||||
|
onCleanup,
|
||||||
|
onMount,
|
||||||
|
type Accessor,
|
||||||
|
type ParentProps,
|
||||||
|
Switch,
|
||||||
|
Match,
|
||||||
|
} from "solid-js"
|
||||||
import { showToast } from "@opencode-ai/ui/toast"
|
import { showToast } from "@opencode-ai/ui/toast"
|
||||||
import { getFilename } from "@opencode-ai/util/path"
|
import { getFilename } from "@opencode-ai/util/path"
|
||||||
import { usePlatform } from "./platform"
|
import { usePlatform } from "./platform"
|
||||||
|
import { Persist, persisted } from "@/utils/persist"
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
status: "loading" | "partial" | "complete"
|
status: "loading" | "partial" | "complete"
|
||||||
@@ -68,9 +80,16 @@ type State = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type VcsCache = {
|
||||||
|
store: Store<{ value: VcsInfo | undefined }>
|
||||||
|
setStore: SetStoreFunction<{ value: VcsInfo | undefined }>
|
||||||
|
ready: Accessor<boolean>
|
||||||
|
}
|
||||||
|
|
||||||
function createGlobalSync() {
|
function createGlobalSync() {
|
||||||
const globalSDK = useGlobalSDK()
|
const globalSDK = useGlobalSDK()
|
||||||
const platform = usePlatform()
|
const platform = usePlatform()
|
||||||
|
const vcsCache = new Map<string, VcsCache>()
|
||||||
const [globalStore, setGlobalStore] = createStore<{
|
const [globalStore, setGlobalStore] = createStore<{
|
||||||
ready: boolean
|
ready: boolean
|
||||||
error?: InitError
|
error?: InitError
|
||||||
@@ -86,10 +105,16 @@ function createGlobalSync() {
|
|||||||
provider_auth: {},
|
provider_auth: {},
|
||||||
})
|
})
|
||||||
|
|
||||||
const children: Record<string, ReturnType<typeof createStore<State>>> = {}
|
const children: Record<string, [Store<State>, SetStoreFunction<State>]> = {}
|
||||||
function child(directory: string) {
|
function child(directory: string) {
|
||||||
if (!directory) console.error("No directory provided")
|
if (!directory) console.error("No directory provided")
|
||||||
if (!children[directory]) {
|
if (!children[directory]) {
|
||||||
|
const cache = persisted(
|
||||||
|
Persist.workspace(directory, "vcs", ["vcs.v1"]),
|
||||||
|
createStore({ value: undefined as VcsInfo | undefined }),
|
||||||
|
)
|
||||||
|
vcsCache.set(directory, { store: cache[0], setStore: cache[1], ready: cache[3] })
|
||||||
|
|
||||||
children[directory] = createStore<State>({
|
children[directory] = createStore<State>({
|
||||||
project: "",
|
project: "",
|
||||||
provider: { all: [], connected: [], default: {} },
|
provider: { all: [], connected: [], default: {} },
|
||||||
@@ -107,14 +132,16 @@ function createGlobalSync() {
|
|||||||
question: {},
|
question: {},
|
||||||
mcp: {},
|
mcp: {},
|
||||||
lsp: [],
|
lsp: [],
|
||||||
vcs: undefined,
|
vcs: cache[0].value,
|
||||||
limit: 5,
|
limit: 5,
|
||||||
message: {},
|
message: {},
|
||||||
part: {},
|
part: {},
|
||||||
})
|
})
|
||||||
bootstrapInstance(directory)
|
bootstrapInstance(directory)
|
||||||
}
|
}
|
||||||
return children[directory]
|
const childStore = children[directory]
|
||||||
|
if (!childStore) throw new Error("Failed to create store")
|
||||||
|
return childStore
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadSessions(directory: string) {
|
async function loadSessions(directory: string) {
|
||||||
@@ -157,6 +184,8 @@ function createGlobalSync() {
|
|||||||
async function bootstrapInstance(directory: string) {
|
async function bootstrapInstance(directory: string) {
|
||||||
if (!directory) return
|
if (!directory) return
|
||||||
const [store, setStore] = child(directory)
|
const [store, setStore] = child(directory)
|
||||||
|
const cache = vcsCache.get(directory)
|
||||||
|
if (!cache) return
|
||||||
const sdk = createOpencodeClient({
|
const sdk = createOpencodeClient({
|
||||||
baseUrl: globalSDK.url,
|
baseUrl: globalSDK.url,
|
||||||
fetch: platform.fetch,
|
fetch: platform.fetch,
|
||||||
@@ -164,6 +193,13 @@ function createGlobalSync() {
|
|||||||
throwOnError: true,
|
throwOnError: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
createEffect(() => {
|
||||||
|
if (!cache.ready()) return
|
||||||
|
const cached = cache.store.value
|
||||||
|
if (!cached?.branch) return
|
||||||
|
setStore("vcs", (value) => value ?? cached)
|
||||||
|
})
|
||||||
|
|
||||||
const blockingRequests = {
|
const blockingRequests = {
|
||||||
project: () => sdk.project.current().then((x) => setStore("project", x.data!.id)),
|
project: () => sdk.project.current().then((x) => setStore("project", x.data!.id)),
|
||||||
provider: () =>
|
provider: () =>
|
||||||
@@ -193,7 +229,11 @@ function createGlobalSync() {
|
|||||||
loadSessions(directory),
|
loadSessions(directory),
|
||||||
sdk.mcp.status().then((x) => setStore("mcp", x.data!)),
|
sdk.mcp.status().then((x) => setStore("mcp", x.data!)),
|
||||||
sdk.lsp.status().then((x) => setStore("lsp", x.data!)),
|
sdk.lsp.status().then((x) => setStore("lsp", x.data!)),
|
||||||
sdk.vcs.get().then((x) => setStore("vcs", x.data)),
|
sdk.vcs.get().then((x) => {
|
||||||
|
const next = x.data ?? store.vcs
|
||||||
|
setStore("vcs", next)
|
||||||
|
if (next?.branch) cache.setStore("value", next)
|
||||||
|
}),
|
||||||
sdk.permission.list().then((x) => {
|
sdk.permission.list().then((x) => {
|
||||||
const grouped: Record<string, PermissionRequest[]> = {}
|
const grouped: Record<string, PermissionRequest[]> = {}
|
||||||
for (const perm of x.data ?? []) {
|
for (const perm of x.data ?? []) {
|
||||||
@@ -406,7 +446,10 @@ function createGlobalSync() {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
case "vcs.branch.updated": {
|
case "vcs.branch.updated": {
|
||||||
setStore("vcs", { branch: event.properties.branch })
|
const next = { branch: event.properties.branch }
|
||||||
|
setStore("vcs", next)
|
||||||
|
const cache = vcsCache.get(directory)
|
||||||
|
if (cache) cache.setStore("value", next)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case "permission.asked": {
|
case "permission.asked": {
|
||||||
|
|||||||
Reference in New Issue
Block a user