Browse Source

feat(app): persist workspace branch

Adam 1 month ago
parent
commit
47d43aaf2d
1 changed files with 50 additions and 7 deletions
  1. 50 7
      packages/app/src/context/global-sync.tsx

+ 50 - 7
packages/app/src/context/global-sync.tsx

@@ -19,15 +19,27 @@ import {
   type QuestionRequest,
   createOpencodeClient,
 } 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 { retry } from "@opencode-ai/util/retry"
 import { useGlobalSDK } from "./global-sdk"
 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 { getFilename } from "@opencode-ai/util/path"
 import { usePlatform } from "./platform"
+import { Persist, persisted } from "@/utils/persist"
 
 type State = {
   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() {
   const globalSDK = useGlobalSDK()
   const platform = usePlatform()
+  const vcsCache = new Map<string, VcsCache>()
   const [globalStore, setGlobalStore] = createStore<{
     ready: boolean
     error?: InitError
@@ -86,10 +105,16 @@ function createGlobalSync() {
     provider_auth: {},
   })
 
-  const children: Record<string, ReturnType<typeof createStore<State>>> = {}
+  const children: Record<string, [Store<State>, SetStoreFunction<State>]> = {}
   function child(directory: string) {
     if (!directory) console.error("No directory provided")
     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>({
         project: "",
         provider: { all: [], connected: [], default: {} },
@@ -107,14 +132,16 @@ function createGlobalSync() {
         question: {},
         mcp: {},
         lsp: [],
-        vcs: undefined,
+        vcs: cache[0].value,
         limit: 5,
         message: {},
         part: {},
       })
       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) {
@@ -157,6 +184,8 @@ function createGlobalSync() {
   async function bootstrapInstance(directory: string) {
     if (!directory) return
     const [store, setStore] = child(directory)
+    const cache = vcsCache.get(directory)
+    if (!cache) return
     const sdk = createOpencodeClient({
       baseUrl: globalSDK.url,
       fetch: platform.fetch,
@@ -164,6 +193,13 @@ function createGlobalSync() {
       throwOnError: true,
     })
 
+    createEffect(() => {
+      if (!cache.ready()) return
+      const cached = cache.store.value
+      if (!cached?.branch) return
+      setStore("vcs", (value) => value ?? cached)
+    })
+
     const blockingRequests = {
       project: () => sdk.project.current().then((x) => setStore("project", x.data!.id)),
       provider: () =>
@@ -193,7 +229,11 @@ function createGlobalSync() {
           loadSessions(directory),
           sdk.mcp.status().then((x) => setStore("mcp", 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) => {
             const grouped: Record<string, PermissionRequest[]> = {}
             for (const perm of x.data ?? []) {
@@ -406,7 +446,10 @@ function createGlobalSync() {
         break
       }
       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
       }
       case "permission.asked": {