소스 검색

refactor(app): rename global context files to server context files (#28790)

Brendan Allan 2 달 전
부모
커밋
eab34b46d0
56개의 변경된 파일338개의 추가작업 그리고 338개의 파일을 삭제
  1. 6 6
      packages/app/src/app.tsx
  2. 15 15
      packages/app/src/components/dialog-connect-provider.tsx
  3. 9 9
      packages/app/src/components/dialog-custom-provider.tsx
  4. 7 7
      packages/app/src/components/dialog-edit-project.tsx
  5. 5 5
      packages/app/src/components/dialog-select-directory.tsx
  6. 9 9
      packages/app/src/components/dialog-select-file.tsx
  7. 1 1
      packages/app/src/components/dialog-select-mcp.tsx
  8. 1 1
      packages/app/src/components/prompt-input.tsx
  9. 2 2
      packages/app/src/components/prompt-input/submit.test.ts
  10. 9 9
      packages/app/src/components/prompt-input/submit.ts
  11. 3 3
      packages/app/src/components/session/session-new-design-view.tsx
  12. 7 7
      packages/app/src/components/settings-general.tsx
  13. 12 12
      packages/app/src/components/settings-providers.tsx
  14. 1 1
      packages/app/src/components/status-popover-body.tsx
  15. 3 3
      packages/app/src/components/titlebar.tsx
  16. 20 20
      packages/app/src/context/directory-sync.ts
  17. 6 6
      packages/app/src/context/global-sync/bootstrap.ts
  18. 1 1
      packages/app/src/context/global-sync/child-store.test.ts
  19. 1 1
      packages/app/src/context/global-sync/child-store.ts
  20. 13 13
      packages/app/src/context/layout.tsx
  21. 7 7
      packages/app/src/context/notification.tsx
  22. 13 13
      packages/app/src/context/permission.tsx
  23. 3 3
      packages/app/src/context/sdk.tsx
  24. 9 9
      packages/app/src/context/server-sdk.tsx
  25. 0 0
      packages/app/src/context/server-sync.test.ts
  26. 26 26
      packages/app/src/context/server-sync.tsx
  27. 3 3
      packages/app/src/context/sync.tsx
  28. 4 4
      packages/app/src/hooks/use-providers.ts
  29. 3 3
      packages/app/src/i18n/ar.ts
  30. 3 3
      packages/app/src/i18n/br.ts
  31. 3 3
      packages/app/src/i18n/bs.ts
  32. 3 3
      packages/app/src/i18n/da.ts
  33. 3 3
      packages/app/src/i18n/de.ts
  34. 3 3
      packages/app/src/i18n/en.ts
  35. 3 3
      packages/app/src/i18n/es.ts
  36. 3 3
      packages/app/src/i18n/fr.ts
  37. 3 3
      packages/app/src/i18n/ja.ts
  38. 3 3
      packages/app/src/i18n/ko.ts
  39. 3 3
      packages/app/src/i18n/no.ts
  40. 3 3
      packages/app/src/i18n/pl.ts
  41. 3 3
      packages/app/src/i18n/ru.ts
  42. 3 3
      packages/app/src/i18n/th.ts
  43. 3 3
      packages/app/src/i18n/tr.ts
  44. 3 3
      packages/app/src/i18n/uk.ts
  45. 3 3
      packages/app/src/i18n/zh.ts
  46. 3 3
      packages/app/src/i18n/zht.ts
  47. 5 5
      packages/app/src/pages/home.tsx
  48. 43 43
      packages/app/src/pages/layout.tsx
  49. 5 5
      packages/app/src/pages/layout/sidebar-items.tsx
  50. 6 6
      packages/app/src/pages/layout/sidebar-project.tsx
  51. 10 10
      packages/app/src/pages/layout/sidebar-workspace.tsx
  52. 8 8
      packages/app/src/pages/session.tsx
  53. 4 4
      packages/app/src/pages/session/composer/session-composer-state.ts
  54. 4 4
      packages/app/src/pages/session/message-timeline.tsx
  55. 1 1
      packages/storybook/.storybook/mocks/app/context/global-sync.ts
  56. 2 2
      packages/ui/src/components/todo-panel-motion.stories.tsx

+ 6 - 6
packages/app/src/app.tsx

@@ -30,8 +30,8 @@ import { Dynamic } from "solid-js/web"
 import { CommandProvider } from "@/context/command"
 import { CommentsProvider } from "@/context/comments"
 import { FileProvider } from "@/context/file"
-import { GlobalSDKProvider } from "@/context/global-sdk"
-import { GlobalSyncProvider } from "@/context/global-sync"
+import { ServerSDKProvider } from "@/context/server-sdk"
+import { ServerSyncProvider } from "@/context/server-sync"
 import { HighlightsProvider } from "@/context/highlights"
 import { LanguageProvider, type Locale, useLanguage } from "@/context/language"
 import { LayoutProvider } from "@/context/layout"
@@ -304,8 +304,8 @@ export function AppInterface(props: {
       <ConnectionGate disableHealthCheck={props.disableHealthCheck}>
         <ServerKey>
           <QueryProvider>
-            <GlobalSDKProvider>
-              <GlobalSyncProvider>
+            <ServerSDKProvider>
+              <ServerSyncProvider>
                 <Dynamic
                   component={props.router ?? Router}
                   root={(routerProps) => <RouterRoot appChildren={props.children}>{routerProps.children}</RouterRoot>}
@@ -316,8 +316,8 @@ export function AppInterface(props: {
                     <Route path="/session/:id?" component={SessionRoute} />
                   </Route>
                 </Dynamic>
-              </GlobalSyncProvider>
-            </GlobalSDKProvider>
+              </ServerSyncProvider>
+            </ServerSDKProvider>
           </QueryProvider>
         </ServerKey>
       </ConnectionGate>

+ 15 - 15
packages/app/src/components/dialog-connect-provider.tsx

@@ -12,15 +12,15 @@ import { showToast } from "@opencode-ai/ui/toast"
 import { createEffect, createMemo, createResource, Match, onCleanup, onMount, Switch } from "solid-js"
 import { createStore, produce } from "solid-js/store"
 import { Link } from "@/components/link"
-import { useGlobalSDK } from "@/context/global-sdk"
-import { useGlobalSync } from "@/context/global-sync"
+import { useServerSDK } from "@/context/server-sdk"
+import { useServerSync } from "@/context/server-sync"
 import { useLanguage } from "@/context/language"
 import { useProviders } from "@/hooks/use-providers"
 
 export function DialogConnectProvider(props: { provider: string }) {
   const dialog = useDialog()
-  const globalSync = useGlobalSync()
-  const globalSDK = useGlobalSDK()
+  const serverSync = useServerSync()
+  const serverSDK = useServerSDK()
   const language = useLanguage()
   const providers = useProviders()
 
@@ -41,7 +41,7 @@ export function DialogConnectProvider(props: { provider: string }) {
   })
 
   const provider = createMemo(
-    () => providers.all().get(props.provider) ?? globalSync.data.provider.all.get(props.provider)!,
+    () => providers.all().get(props.provider) ?? serverSync.data.provider.all.get(props.provider)!,
   )
   const fallback = createMemo<ProviderAuthMethod[]>(() => [
     {
@@ -52,16 +52,16 @@ export function DialogConnectProvider(props: { provider: string }) {
   const [auth] = createResource(
     () => props.provider,
     async () => {
-      const cached = globalSync.data.provider_auth[props.provider]
+      const cached = serverSync.data.provider_auth[props.provider]
       if (cached) return cached
-      const res = await globalSDK.client.provider.auth()
+      const res = await serverSDK.client.provider.auth()
       if (!alive.value) return fallback()
-      globalSync.set("provider_auth", res.data ?? {})
+      serverSync.set("provider_auth", res.data ?? {})
       return res.data?.[props.provider] ?? fallback()
     },
   )
-  const loading = createMemo(() => auth.loading && !globalSync.data.provider_auth[props.provider])
-  const methods = createMemo(() => auth.latest ?? globalSync.data.provider_auth[props.provider] ?? fallback())
+  const loading = createMemo(() => auth.loading && !serverSync.data.provider_auth[props.provider])
+  const methods = createMemo(() => auth.latest ?? serverSync.data.provider_auth[props.provider] ?? fallback())
   const [store, setStore] = createStore({
     methodIndex: undefined as undefined | number,
     authorization: undefined as undefined | ProviderAuthAuthorization,
@@ -158,7 +158,7 @@ export function DialogConnectProvider(props: { provider: string }) {
       }
       dispatch({ type: "auth.pending" })
       const start = Date.now()
-      await globalSDK.client.provider.oauth
+      await serverSDK.client.provider.oauth
         .authorize(
           {
             providerID: props.provider,
@@ -330,7 +330,7 @@ export function DialogConnectProvider(props: { provider: string }) {
   })
 
   async function complete() {
-    await globalSDK.client.global.dispose()
+    await serverSDK.client.global.dispose()
     dialog.close()
     showToast({
       variant: "success",
@@ -407,7 +407,7 @@ export function DialogConnectProvider(props: { provider: string }) {
       }
 
       setFormStore("error", undefined)
-      await globalSDK.client.auth.set({
+      await serverSDK.client.auth.set({
         providerID: props.provider,
         auth: {
           type: "api",
@@ -478,7 +478,7 @@ export function DialogConnectProvider(props: { provider: string }) {
       }
 
       setFormStore("error", undefined)
-      const result = await globalSDK.client.provider.oauth
+      const result = await serverSDK.client.provider.oauth
         .callback({
           providerID: props.provider,
           method: store.methodIndex,
@@ -531,7 +531,7 @@ export function DialogConnectProvider(props: { provider: string }) {
 
     onMount(() => {
       void (async () => {
-        const result = await globalSDK.client.provider.oauth
+        const result = await serverSDK.client.provider.oauth
           .callback({
             providerID: props.provider,
             method: store.methodIndex,

+ 9 - 9
packages/app/src/components/dialog-custom-provider.tsx

@@ -9,8 +9,8 @@ import { showToast } from "@opencode-ai/ui/toast"
 import { batch, For } from "solid-js"
 import { createStore, produce } from "solid-js/store"
 import { Link } from "@/components/link"
-import { useGlobalSDK } from "@/context/global-sdk"
-import { useGlobalSync } from "@/context/global-sync"
+import { useServerSDK } from "@/context/server-sdk"
+import { useServerSync } from "@/context/server-sync"
 import { useLanguage } from "@/context/language"
 import { type FormState, headerRow, modelRow, validateCustomProvider } from "./dialog-custom-provider-form"
 import { DialogSelectProvider } from "./dialog-select-provider"
@@ -21,8 +21,8 @@ type Props = {
 
 export function DialogCustomProvider(props: Props) {
   const dialog = useDialog()
-  const globalSync = useGlobalSync()
-  const globalSDK = useGlobalSDK()
+  const serverSync = useServerSync()
+  const serverSDK = useServerSDK()
   const language = useLanguage()
 
   const [form, setForm] = createStore<FormState>({
@@ -105,8 +105,8 @@ export function DialogCustomProvider(props: Props) {
     const output = validateCustomProvider({
       form,
       t: language.t,
-      disabledProviders: globalSync.data.config.disabled_providers ?? [],
-      existingProviderIDs: new Set(globalSync.data.provider.all.keys()),
+      disabledProviders: serverSync.data.config.disabled_providers ?? [],
+      existingProviderIDs: new Set(serverSync.data.provider.all.keys()),
     })
     batch(() => {
       setForm("err", output.err)
@@ -118,11 +118,11 @@ export function DialogCustomProvider(props: Props) {
 
   const saveMutation = useMutation(() => ({
     mutationFn: async (result: NonNullable<ReturnType<typeof validate>>) => {
-      const disabledProviders = globalSync.data.config.disabled_providers ?? []
+      const disabledProviders = serverSync.data.config.disabled_providers ?? []
       const nextDisabled = disabledProviders.filter((id) => id !== result.providerID)
 
       if (result.key) {
-        await globalSDK.client.auth.set({
+        await serverSDK.client.auth.set({
           providerID: result.providerID,
           auth: {
             type: "api",
@@ -131,7 +131,7 @@ export function DialogCustomProvider(props: Props) {
         })
       }
 
-      await globalSync.updateConfig({
+      await serverSync.updateConfig({
         provider: { [result.providerID]: result.config },
         disabled_providers: nextDisabled,
       })

+ 7 - 7
packages/app/src/components/dialog-edit-project.tsx

@@ -6,8 +6,8 @@ import { useMutation } from "@tanstack/solid-query"
 import { Icon } from "@opencode-ai/ui/icon"
 import { createMemo, For, Show } from "solid-js"
 import { createStore } from "solid-js/store"
-import { useGlobalSDK } from "@/context/global-sdk"
-import { useGlobalSync } from "@/context/global-sync"
+import { useServerSDK } from "@/context/server-sdk"
+import { useServerSync } from "@/context/server-sync"
 import { type LocalProject, getAvatarColors } from "@/context/layout"
 import { getFilename } from "@opencode-ai/core/util/path"
 import { Avatar } from "@opencode-ai/ui/avatar"
@@ -18,8 +18,8 @@ const AVATAR_COLOR_KEYS = ["pink", "mint", "orange", "purple", "cyan", "lime"] a
 
 export function DialogEditProject(props: { project: LocalProject }) {
   const dialog = useDialog()
-  const globalSDK = useGlobalSDK()
-  const globalSync = useGlobalSync()
+  const serverSDK = useServerSDK()
+  const serverSync = useServerSync()
   const language = useLanguage()
 
   const folderName = createMemo(() => getFilename(props.project.worktree))
@@ -78,19 +78,19 @@ export function DialogEditProject(props: { project: LocalProject }) {
       const start = store.startup.trim()
 
       if (props.project.id && props.project.id !== "global") {
-        await globalSDK.client.project.update({
+        await serverSDK.client.project.update({
           projectID: props.project.id,
           directory: props.project.worktree,
           name,
           icon: { color: store.color || "", override: store.iconOverride || "" },
           commands: { start },
         })
-        globalSync.project.icon(props.project.worktree, store.iconOverride || undefined)
+        serverSync.project.icon(props.project.worktree, store.iconOverride || undefined)
         dialog.close()
         return
       }
 
-      globalSync.project.meta(props.project.worktree, {
+      serverSync.project.meta(props.project.worktree, {
         name,
         icon: { color: store.color || undefined, override: store.iconOverride || undefined },
         commands: { start: start || undefined },

+ 5 - 5
packages/app/src/components/dialog-select-directory.tsx

@@ -6,8 +6,8 @@ import type { ListRef } from "@opencode-ai/ui/list"
 import { getDirectory, getFilename } from "@opencode-ai/core/util/path"
 import fuzzysort from "fuzzysort"
 import { createMemo, createResource, createSignal } from "solid-js"
-import { useGlobalSDK } from "@/context/global-sdk"
-import { useGlobalSync } from "@/context/global-sync"
+import { useServerSDK } from "@/context/server-sdk"
+import { useServerSync } from "@/context/server-sync"
 import { useLayout } from "@/context/layout"
 import { useLanguage } from "@/context/language"
 
@@ -128,7 +128,7 @@ function uniqueRows(rows: Row[]) {
 }
 
 function useDirectorySearch(args: {
-  sdk: ReturnType<typeof useGlobalSDK>
+  sdk: ReturnType<typeof useServerSDK>
   start: () => string | undefined
   home: () => string
 }) {
@@ -246,8 +246,8 @@ function useDirectorySearch(args: {
 }
 
 export function DialogSelectDirectory(props: DialogSelectDirectoryProps) {
-  const sync = useGlobalSync()
-  const sdk = useGlobalSDK()
+  const sync = useServerSync()
+  const sdk = useServerSDK()
   const layout = useLayout()
   const dialog = useDialog()
   const language = useLanguage()

+ 9 - 9
packages/app/src/components/dialog-select-file.tsx

@@ -9,8 +9,8 @@ import { getDirectory, getFilename } from "@opencode-ai/core/util/path"
 import { useNavigate } from "@solidjs/router"
 import { createMemo, createSignal, Match, onCleanup, Show, Switch } from "solid-js"
 import { formatKeybind, useCommand, type CommandOption } from "@/context/command"
-import { useGlobalSDK } from "@/context/global-sdk"
-import { useGlobalSync } from "@/context/global-sync"
+import { useServerSDK } from "@/context/server-sdk"
+import { useServerSync } from "@/context/server-sync"
 import { useLayout } from "@/context/layout"
 import { useFile } from "@/context/file"
 import { useLanguage } from "@/context/language"
@@ -175,7 +175,7 @@ function createFileEntries(props: {
 function createSessionEntries(props: {
   workspaces: () => string[]
   label: (directory: string) => string
-  globalSDK: ReturnType<typeof useGlobalSDK>
+  serverSDK: ReturnType<typeof useServerSDK>
   language: ReturnType<typeof useLanguage>
 }) {
   const state: {
@@ -207,7 +207,7 @@ function createSessionEntries(props: {
     state.inflight = Promise.all(
       dirs.map((directory) => {
         const description = props.label(directory)
-        return props.globalSDK.client.session
+        return props.serverSDK.client.session
           .list({ directory, roots: true })
           .then((x) =>
             (x.data ?? [])
@@ -268,8 +268,8 @@ export function DialogSelectFile(props: { mode?: DialogSelectFileMode; onOpenFil
   const file = useFile()
   const dialog = useDialog()
   const navigate = useNavigate()
-  const globalSDK = useGlobalSDK()
-  const globalSync = useGlobalSync()
+  const serverSDK = useServerSDK()
+  const serverSync = useServerSync()
   const { params, tabs, view } = useSessionLayout()
   const filesOnly = () => props.mode === "files"
   const state = { cleanup: undefined as (() => void) | void, committed: false }
@@ -292,21 +292,21 @@ export function DialogSelectFile(props: { mode?: DialogSelectFileMode; onOpenFil
     if (directory && !dirs.includes(directory)) return [...dirs, directory]
     return dirs
   })
-  const homedir = createMemo(() => globalSync.data.path.home)
+  const homedir = createMemo(() => serverSync.data.path.home)
   const label = (directory: string) => {
     const current = project()
     const kind =
       current && directory === current.worktree
         ? language.t("workspace.type.local")
         : language.t("workspace.type.sandbox")
-    const [store] = globalSync.child(directory, { bootstrap: false })
+    const [store] = serverSync.child(directory, { bootstrap: false })
     const home = homedir()
     const path = home ? directory.replace(home, "~") : directory
     const name = store.vcs?.branch ?? getFilename(directory)
     return `${kind} : ${name || path}`
   }
 
-  const { sessions } = createSessionEntries({ workspaces, label, globalSDK, language })
+  const { sessions } = createSessionEntries({ workspaces, label, serverSDK, language })
 
   const items = async (text: string) => {
     const query = text.trim()

+ 1 - 1
packages/app/src/components/dialog-select-mcp.tsx

@@ -6,7 +6,7 @@ import { Dialog } from "@opencode-ai/ui/dialog"
 import { List } from "@opencode-ai/ui/list"
 import { Switch } from "@opencode-ai/ui/switch"
 import { useLanguage } from "@/context/language"
-import { useQueryOptions } from "@/context/global-sync"
+import { useQueryOptions } from "@/context/server-sync"
 import { pathKey } from "@/utils/path-key"
 
 const statusLabels = {

+ 1 - 1
packages/app/src/components/prompt-input.tsx

@@ -66,7 +66,7 @@ import { PromptDragOverlay } from "./prompt-input/drag-overlay"
 import { promptPlaceholder } from "./prompt-input/placeholder"
 import { ImagePreview } from "@opencode-ai/ui/image-preview"
 import { useQueries } from "@tanstack/solid-query"
-import { useQueryOptions } from "@/context/global-sync"
+import { useQueryOptions } from "@/context/server-sync"
 import { pathKey } from "@/utils/path-key"
 import { getFilename } from "@opencode-ai/core/util/path"
 

+ 2 - 2
packages/app/src/components/prompt-input/submit.test.ts

@@ -162,8 +162,8 @@ beforeAll(async () => {
     }),
   }))
 
-  mock.module("@/context/global-sync", () => ({
-    useGlobalSync: () => ({
+  mock.module("@/context/server-sync", () => ({
+    useServerSync: () => ({
       child: (directory: string) => {
         syncedDirectories.push(directory)
         storedSessions[directory] ??= []

+ 9 - 9
packages/app/src/components/prompt-input/submit.ts

@@ -5,7 +5,7 @@ import { Binary } from "@opencode-ai/core/util/binary"
 import { useNavigate, useParams } from "@solidjs/router"
 import { batch, type Accessor } from "solid-js"
 import type { FileSelection } from "@/context/file"
-import { useGlobalSync } from "@/context/global-sync"
+import { useServerSync } from "@/context/server-sync"
 import { useLanguage } from "@/context/language"
 import { useLayout } from "@/context/layout"
 import { useLocal } from "@/context/local"
@@ -38,7 +38,7 @@ export type FollowupDraft = {
 
 type FollowupSendInput = {
   client: ReturnType<typeof useSDK>["client"]
-  globalSync: ReturnType<typeof useGlobalSync>
+  serverSync: ReturnType<typeof useServerSync>
   sync: ReturnType<typeof useSync>
   draft: FollowupDraft
   messageID?: string
@@ -53,7 +53,7 @@ const draftImages = (prompt: Prompt) => prompt.filter((part): part is ImageAttac
 export async function sendFollowupDraft(input: FollowupSendInput) {
   const text = draftText(input.draft.prompt)
   const images = draftImages(input.draft.prompt)
-  const [, setStore] = input.globalSync.child(input.draft.sessionDirectory)
+  const [, setStore] = input.serverSync.child(input.draft.sessionDirectory)
 
   const setBusy = () => {
     if (!input.optimisticBusy) return
@@ -205,7 +205,7 @@ export function createPromptSubmit(input: PromptSubmitInput) {
   const navigate = useNavigate()
   const sdk = useSDK()
   const sync = useSync()
-  const globalSync = useGlobalSync()
+  const serverSync = useServerSync()
   const local = useLocal()
   const permission = usePermission()
   const prompt = usePrompt()
@@ -226,8 +226,8 @@ export function createPromptSubmit(input: PromptSubmitInput) {
     const sessionID = params.id
     if (!sessionID) return Promise.resolve()
 
-    globalSync.todo.set(sessionID, [])
-    const [, setStore] = globalSync.child(sdk.directory)
+    serverSync.todo.set(sessionID, [])
+    const [, setStore] = serverSync.child(sdk.directory)
     setStore("todo", sessionID, [])
 
     input.onAbort?.()
@@ -273,7 +273,7 @@ export function createPromptSubmit(input: PromptSubmitInput) {
   }
 
   const seed = (dir: string, info: Session) => {
-    const [, setStore] = globalSync.child(dir)
+    const [, setStore] = serverSync.child(dir)
     setStore("session", (list: Session[]) => {
       const result = Binary.search(list, info.id, (item) => item.id)
       const next = [...list]
@@ -354,7 +354,7 @@ export function createPromptSubmit(input: PromptSubmitInput) {
           directory: sessionDirectory,
           throwOnError: true,
         })
-        globalSync.child(sessionDirectory)
+        serverSync.child(sessionDirectory)
       }
 
       input.onNewSessionWorktreeReset?.()
@@ -557,7 +557,7 @@ export function createPromptSubmit(input: PromptSubmitInput) {
     void sendFollowupDraft({
       client,
       sync,
-      globalSync,
+      serverSync,
       draft,
       messageID,
       optimisticBusy: sessionDirectory === projectDirectory,

+ 3 - 3
packages/app/src/components/session/session-new-design-view.tsx

@@ -1,7 +1,7 @@
 import type { JSX } from "solid-js"
 import { createMemo } from "solid-js"
 import { useNavigate } from "@solidjs/router"
-import { useGlobalSync } from "@/context/global-sync"
+import { useServerSync } from "@/context/server-sync"
 import { useLayout } from "@/context/layout"
 import { useSDK } from "@/context/sdk"
 import { useServer } from "@/context/server"
@@ -15,7 +15,7 @@ import { WordmarkV2 } from "@opencode-ai/ui/v2/components/wordmark-v2.jsx"
 const MAIN_WORKTREE = "main"
 
 export function NewSessionDesignView(props: { worktree: string; children: JSX.Element }) {
-  const globalSync = useGlobalSync()
+  const serverSync = useServerSync()
   const layout = useLayout()
   const navigate = useNavigate()
   const sdk = useSDK()
@@ -24,7 +24,7 @@ export function NewSessionDesignView(props: { worktree: string; children: JSX.El
 
   const projectRoot = createMemo(() => sync.project?.worktree ?? sdk.directory)
   const projects = createMemo(() => {
-    const roots = globalSync.data.project.map((project) => project.worktree)
+    const roots = serverSync.data.project.map((project) => project.worktree)
     if (roots.includes(projectRoot())) return roots
     return [projectRoot(), ...roots]
   })

+ 7 - 7
packages/app/src/components/settings-general.tsx

@@ -12,8 +12,8 @@ import { useParams } from "@solidjs/router"
 import { useLanguage } from "@/context/language"
 import { usePermission } from "@/context/permission"
 import { usePlatform, type DisplayBackend } from "@/context/platform"
-import { useGlobalSync } from "@/context/global-sync"
-import { useGlobalSDK } from "@/context/global-sdk"
+import { useServerSync } from "@/context/server-sync"
+import { useServerSDK } from "@/context/server-sdk"
 import {
   monoDefault,
   monoFontFamily,
@@ -175,8 +175,8 @@ export const SettingsGeneral: Component = () => {
 
   const themeOptions = createMemo<ThemeOption[]>(() => theme.ids().map((id) => ({ id, name: theme.name(id) })))
 
-  const globalSync = useGlobalSync()
-  const globalSdk = useGlobalSDK()
+  const serverSync = useServerSync()
+  const globalSdk = useServerSDK()
 
   const [shells] = createResource(
     () =>
@@ -204,11 +204,11 @@ export const SettingsGeneral: Component = () => {
   })
 
   const autoOption = { id: "auto", value: "", label: language.t("settings.general.row.shell.autoDefault") }
-  const currentShell = createMemo(() => globalSync.data.config.shell ?? "")
+  const currentShell = createMemo(() => serverSync.data.config.shell ?? "")
 
   const shellOptions = createMemo<ShellSelectOption[]>(() => {
     const list = shells.latest
-    const current = globalSync.data.config.shell
+    const current = serverSync.data.config.shell
 
     const nameCounts = new Map<string, number>()
     for (const s of list) {
@@ -343,7 +343,7 @@ export const SettingsGeneral: Component = () => {
             onSelect={(option) => {
               if (!option) return
               if (option.value === currentShell()) return
-              globalSync.updateConfig({ shell: option.value })
+              serverSync.updateConfig({ shell: option.value })
             }}
             variant="secondary"
             size="small"

+ 12 - 12
packages/app/src/components/settings-providers.tsx

@@ -6,8 +6,8 @@ import { showToast } from "@opencode-ai/ui/toast"
 import { popularProviders, useProviders } from "@/hooks/use-providers"
 import { createMemo, type Component, For, Show } from "solid-js"
 import { useLanguage } from "@/context/language"
-import { useGlobalSDK } from "@/context/global-sdk"
-import { useGlobalSync } from "@/context/global-sync"
+import { useServerSDK } from "@/context/server-sdk"
+import { useServerSync } from "@/context/server-sync"
 import { DialogConnectProvider } from "./dialog-connect-provider"
 import { DialogSelectProvider } from "./dialog-select-provider"
 import { DialogCustomProvider } from "./dialog-custom-provider"
@@ -30,8 +30,8 @@ const PROVIDER_NOTES = [
 export const SettingsProviders: Component = () => {
   const dialog = useDialog()
   const language = useLanguage()
-  const globalSDK = useGlobalSDK()
-  const globalSync = useGlobalSync()
+  const serverSDK = useServerSDK()
+  const serverSync = useServerSync()
   const providers = useProviders()
 
   const connected = createMemo(() => {
@@ -74,7 +74,7 @@ export const SettingsProviders: Component = () => {
   const note = (id: string) => PROVIDER_NOTES.find((item) => item.match(id))?.key
 
   const isConfigCustom = (providerID: string) => {
-    const provider = globalSync.data.config.provider?.[providerID]
+    const provider = serverSync.data.config.provider?.[providerID]
     if (!provider) return false
     if (provider.npm !== "@ai-sdk/openai-compatible") return false
     if (!provider.models || Object.keys(provider.models).length === 0) return false
@@ -82,11 +82,11 @@ export const SettingsProviders: Component = () => {
   }
 
   const disableProvider = async (providerID: string, name: string) => {
-    const before = globalSync.data.config.disabled_providers ?? []
+    const before = serverSync.data.config.disabled_providers ?? []
     const next = before.includes(providerID) ? before : [...before, providerID]
-    globalSync.set("config", "disabled_providers", next)
+    serverSync.set("config", "disabled_providers", next)
 
-    await globalSync
+    await serverSync
       .updateConfig({ disabled_providers: next })
       .then(() => {
         showToast({
@@ -97,7 +97,7 @@ export const SettingsProviders: Component = () => {
         })
       })
       .catch((err: unknown) => {
-        globalSync.set("config", "disabled_providers", before)
+        serverSync.set("config", "disabled_providers", before)
         const message = err instanceof Error ? err.message : String(err)
         showToast({ title: language.t("common.requestFailed"), description: message })
       })
@@ -105,14 +105,14 @@ export const SettingsProviders: Component = () => {
 
   const disconnect = async (providerID: string, name: string) => {
     if (isConfigCustom(providerID)) {
-      await globalSDK.client.auth.remove({ providerID }).catch(() => undefined)
+      await serverSDK.client.auth.remove({ providerID }).catch(() => undefined)
       await disableProvider(providerID, name)
       return
     }
-    await globalSDK.client.auth
+    await serverSDK.client.auth
       .remove({ providerID })
       .then(async () => {
-        await globalSDK.client.global.dispose()
+        await serverSDK.client.global.dispose()
         showToast({
           variant: "success",
           icon: "circle-check",

+ 1 - 1
packages/app/src/components/status-popover-body.tsx

@@ -15,7 +15,7 @@ import { useSDK } from "@/context/sdk"
 import { normalizeServerUrl, ServerConnection, useServer } from "@/context/server"
 import { useSync } from "@/context/sync"
 import { useCheckServerHealth, type ServerHealth } from "@/utils/server-health"
-import { useQueryOptions } from "@/context/global-sync"
+import { useQueryOptions } from "@/context/server-sync"
 import { pathKey } from "@/utils/path-key"
 
 const pollMs = 10_000

+ 3 - 3
packages/app/src/components/titlebar.tsx

@@ -16,7 +16,7 @@ import { useLanguage } from "@/context/language"
 import { useSettings } from "@/context/settings"
 import { WindowsAppMenu } from "./windows-app-menu"
 import { applyPath, backPath, forwardPath } from "./titlebar-history"
-import { useGlobalSync } from "@/context/global-sync"
+import { useServerSync } from "@/context/server-sync"
 import { decodeDirectory } from "@/pages/directory-layout"
 import { iife } from "@opencode-ai/core/util/iife"
 import { base64Encode } from "@opencode-ai/core/util/encode"
@@ -221,7 +221,7 @@ export function Titlebar(props: { update?: TitlebarUpdate }) {
       <Switch>
         <Match when={USE_V2_TITLEBAR}>
           {(_) => {
-            const globalSync = useGlobalSync()
+            const serverSync = useServerSync()
             const navigate = useNavigate()
             const homeMatch = useMatch(() => "/")
 
@@ -391,7 +391,7 @@ export function Titlebar(props: { update?: TitlebarUpdate }) {
               const base = mapArray(
                 () => tabsStore,
                 (tab) => {
-                  const sync = globalSync.createDirSyncContext(tab.dir)
+                  const sync = serverSync.createDirSyncContext(tab.dir)
                   const session = sync.session.get(tab.sessionId)
                   return session ? { ...tab, info: session } : null
                 },

+ 20 - 20
packages/app/src/context/directory-sync.ts

@@ -8,7 +8,7 @@ import {
   getSessionPrefetchPromise,
   setSessionPrefetch,
 } from "./global-sync/session-prefetch"
-import { useGlobalSync } from "./global-sync"
+import { useServerSync } from "./server-sync"
 import type { Message, OpencodeClient, Part } from "@opencode-ai/sdk/v2/client"
 import { SESSION_CACHE_LIMIT, dropSessionCaches, pickSessionCacheEvictions } from "./global-sync/session-cache"
 import { diffs as list, message as clean } from "@/utils/diffs"
@@ -165,15 +165,15 @@ function setOptimisticRemove(setStore: (...args: unknown[]) => void, input: Opti
 }
 
 export const createDirSyncContext = (client: OpencodeClient, directory: string) => {
-  const globalSync = useGlobalSync()
+  const serverSync = useServerSync()
 
-  type Child = ReturnType<(typeof globalSync)["child"]>
+  type Child = ReturnType<(typeof serverSync)["child"]>
   type Setter = Child[1]
 
-  const current = createMemo(() => globalSync.child(directory))
+  const current = createMemo(() => serverSync.child(directory))
   const target = (directory?: string) => {
     if (!directory || directory === directory) return current()
-    return globalSync.child(directory)
+    return serverSync.child(directory)
   }
   const absolute = (path: string) => (current()[0].path.directory + "/" + path).replace("//", "/")
   const initialMessagePageSize = 80
@@ -239,7 +239,7 @@ export const createDirSyncContext = (client: OpencodeClient, directory: string)
       if (!first) break
       const stale = [...(seen.get(first) ?? [])]
       seen.delete(first)
-      const [, setStore] = globalSync.child(first, { bootstrap: false })
+      const [, setStore] = serverSync.child(first, { bootstrap: false })
       evict(first, setStore, stale)
     }
     return created
@@ -267,7 +267,7 @@ export const createDirSyncContext = (client: OpencodeClient, directory: string)
     if (sessionIDs.length === 0) return
     clearSessionPrefetch(directory, sessionIDs)
     for (const sessionID of sessionIDs) {
-      globalSync.todo.set(sessionID, undefined)
+      serverSync.todo.set(sessionID, undefined)
     }
     setStore(
       produce((draft) => {
@@ -324,7 +324,7 @@ export const createDirSyncContext = (client: OpencodeClient, directory: string)
         for (const messageID of next.confirmed) {
           clearOptimistic(input.directory, input.sessionID, messageID)
         }
-        const [store] = globalSync.child(input.directory, { bootstrap: false })
+        const [store] = serverSync.child(input.directory, { bootstrap: false })
         const cached = input.mode === "prepend" ? (store.message[input.sessionID] ?? []) : []
         const message = input.mode === "prepend" ? merge(cached, next.session) : next.session
         batch(() => {
@@ -373,8 +373,8 @@ export const createDirSyncContext = (client: OpencodeClient, directory: string)
     },
     get project() {
       const store = current()[0]
-      const match = Binary.search(globalSync.data.project, store.project, (p) => p.id)
-      if (match.found) return globalSync.data.project[match.index]
+      const match = Binary.search(serverSync.data.project, store.project, (p) => p.id)
+      if (match.found) return serverSync.data.project[match.index]
       return undefined
     },
     session: {
@@ -418,7 +418,7 @@ export const createDirSyncContext = (client: OpencodeClient, directory: string)
         })
       },
       async sync(sessionID: string, opts?: { force?: boolean }) {
-        const [store, setStore] = globalSync.child(directory)
+        const [store, setStore] = serverSync.child(directory)
         const key = keyFor(directory, sessionID)
 
         touch(directory, setStore, sessionID)
@@ -488,7 +488,7 @@ export const createDirSyncContext = (client: OpencodeClient, directory: string)
         })
       },
       async diff(sessionID: string, opts?: { force?: boolean }) {
-        const [store, setStore] = globalSync.child(directory)
+        const [store, setStore] = serverSync.child(directory)
         touch(directory, setStore, sessionID)
         if (store.session_diff[sessionID] !== undefined && !opts?.force) return
 
@@ -501,13 +501,13 @@ export const createDirSyncContext = (client: OpencodeClient, directory: string)
         )
       },
       async todo(sessionID: string, opts?: { force?: boolean }) {
-        const [store, setStore] = globalSync.child(directory)
+        const [store, setStore] = serverSync.child(directory)
         touch(directory, setStore, sessionID)
         const existing = store.todo[sessionID]
-        const cached = globalSync.data.session_todo[sessionID]
+        const cached = serverSync.data.session_todo[sessionID]
         if (existing !== undefined) {
           if (cached === undefined) {
-            globalSync.todo.set(sessionID, existing)
+            serverSync.todo.set(sessionID, existing)
           }
           if (!opts?.force) return
         }
@@ -522,7 +522,7 @@ export const createDirSyncContext = (client: OpencodeClient, directory: string)
             if (!tracked(directory, sessionID)) return
             const list = todo.data ?? []
             setStore("todo", sessionID, reconcile(list, { key: "id" }))
-            globalSync.todo.set(sessionID, list)
+            serverSync.todo.set(sessionID, list)
           }),
         )
       },
@@ -540,7 +540,7 @@ export const createDirSyncContext = (client: OpencodeClient, directory: string)
           return meta.loading[key] ?? false
         },
         async loadMore(sessionID: string, count?: number) {
-          const [, setStore] = globalSync.child(directory)
+          const [, setStore] = serverSync.child(directory)
           touch(directory, setStore, sessionID)
           const key = keyFor(directory, sessionID)
           const step = count ?? historyMessagePageSize
@@ -561,12 +561,12 @@ export const createDirSyncContext = (client: OpencodeClient, directory: string)
         },
       },
       evict(sessionID: string, _directory = directory) {
-        const [, setStore] = globalSync.child(_directory)
+        const [, setStore] = serverSync.child(_directory)
         seenFor(_directory).delete(sessionID)
         evict(_directory, setStore, [sessionID])
       },
       fetch: async (count = 10) => {
-        const [store, setStore] = globalSync.child(directory)
+        const [store, setStore] = serverSync.child(directory)
         setStore("limit", (x) => x + count)
         await client.session.list().then((x) => {
           const sessions = (x.data ?? [])
@@ -578,7 +578,7 @@ export const createDirSyncContext = (client: OpencodeClient, directory: string)
       },
       more: createMemo(() => current()[0].session.length >= current()[0].limit),
       archive: async (sessionID: string) => {
-        const [, setStore] = globalSync.child(directory)
+        const [, setStore] = serverSync.child(directory)
         await client.session.update({ sessionID, time: { archived: Date.now() } })
         setStore(
           produce((draft) => {

+ 6 - 6
packages/app/src/context/global-sync/bootstrap.ts

@@ -18,7 +18,7 @@ import type { State, VcsCache } from "./types"
 import { cmp, normalizeAgentList, normalizeProviderList } from "./utils"
 import { formatServerError } from "@/utils/server-errors"
 import { QueryClient, queryOptions } from "@tanstack/solid-query"
-import { loadMcpQuery } from "../global-sync"
+import { loadMcpQuery } from "../server-sync"
 import { NormalizedProviderListResponse } from "@opencode-ai/ui/context"
 
 type GlobalStore = {
@@ -105,7 +105,7 @@ export const loadProjectsQuery = (sdk: OpencodeClient) =>
   })
 
 export async function bootstrapGlobal(input: {
-  globalSDK: OpencodeClient
+  serverSDK: OpencodeClient
   requestFailedTitle: string
   translate: (key: string, vars?: Record<string, string | number>) => string
   formatMoreCount: (count: number) => string
@@ -113,12 +113,12 @@ export async function bootstrapGlobal(input: {
   queryClient: QueryClient
 }) {
   const slow = [
-    () => input.queryClient.fetchQuery(loadGlobalConfigQuery(input.globalSDK)),
-    () => input.queryClient.fetchQuery(loadProvidersQuery(null, input.globalSDK)),
-    () => input.queryClient.fetchQuery(loadPathQuery(null, input.globalSDK)),
+    () => input.queryClient.fetchQuery(loadGlobalConfigQuery(input.serverSDK)),
+    () => input.queryClient.fetchQuery(loadProvidersQuery(null, input.serverSDK)),
+    () => input.queryClient.fetchQuery(loadPathQuery(null, input.serverSDK)),
     () =>
       input.queryClient
-        .fetchQuery(loadProjectsQuery(input.globalSDK))
+        .fetchQuery(loadProjectsQuery(input.serverSDK))
         .then((data) => input.setGlobalStore("project", data)),
   ]
   await runAll(slow)

+ 1 - 1
packages/app/src/context/global-sync/child-store.test.ts

@@ -3,7 +3,7 @@ import { createRoot, getOwner, type Owner } from "solid-js"
 import { createStore } from "solid-js/store"
 import type { NormalizedProviderListResponse } from "@opencode-ai/ui/context"
 import type { State } from "./types"
-import type { QueryOptionsApi } from "../global-sync"
+import type { QueryOptionsApi } from "../server-sync"
 
 let createChildStoreManager: typeof import("./child-store").createChildStoreManager
 

+ 1 - 1
packages/app/src/context/global-sync/child-store.ts

@@ -15,7 +15,7 @@ import {
 } from "./types"
 import { canDisposeDirectory, pickDirectoriesToEvict } from "./eviction"
 import { useQueries } from "@tanstack/solid-query"
-import { QueryOptionsApi } from "../global-sync"
+import { QueryOptionsApi } from "../server-sync"
 import { directoryKey, type DirectoryKey } from "./utils"
 import { NormalizedProviderListResponse } from "@opencode-ai/ui/context"
 

+ 13 - 13
packages/app/src/context/layout.tsx

@@ -2,8 +2,8 @@ import { createStore, produce } from "solid-js/store"
 import { batch, createEffect, createMemo, onCleanup, onMount, type Accessor } from "solid-js"
 import { createSimpleContext } from "@opencode-ai/ui/context"
 import { makeEventListener } from "@solid-primitives/event-listener"
-import { useGlobalSync } from "./global-sync"
-import { useGlobalSDK } from "./global-sdk"
+import { useServerSync } from "./server-sync"
+import { useServerSDK } from "./server-sdk"
 import { useServer } from "./server"
 import { usePlatform } from "./platform"
 import { Project } from "@opencode-ai/sdk/v2"
@@ -136,8 +136,8 @@ const normalizeStoredSessionTabs = (key: string, tabs: SessionTabs) => {
 export const { use: useLayout, provider: LayoutProvider } = createSimpleContext({
   name: "Layout",
   init: () => {
-    const globalSdk = useGlobalSDK()
-    const globalSync = useGlobalSync()
+    const globalSdk = useServerSDK()
+    const serverSync = useServerSync()
     const server = useServer()
     const platform = usePlatform()
 
@@ -386,11 +386,11 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
     }
 
     function enrich(project: { worktree: string; expanded: boolean }) {
-      const [childStore] = globalSync.child(project.worktree, { bootstrap: false })
+      const [childStore] = serverSync.child(project.worktree, { bootstrap: false })
       const projectID = childStore.project
       const metadata = projectID
-        ? globalSync.data.project.find((x) => x.id === projectID)
-        : globalSync.data.project.find((x) => x.worktree === project.worktree)
+        ? serverSync.data.project.find((x) => x.id === projectID)
+        : serverSync.data.project.find((x) => x.worktree === project.worktree)
 
       // Preserve local icon override from per-workspace localStorage cache (childStore.icon).
       // Without this, different subdirectories of the same git repo would share the same
@@ -404,7 +404,7 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
 
     const roots = createMemo(() => {
       const map = new Map<string, string>()
-      for (const project of globalSync.data.project) {
+      for (const project of serverSync.data.project) {
         const sandboxes = project.sandboxes ?? []
         for (const sandbox of sandboxes) {
           map.set(sandbox, project.worktree)
@@ -470,12 +470,12 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
     createEffect(() => {
       const projects = enriched()
       if (projects.length === 0) return
-      if (!globalSync.ready) return
+      if (!serverSync.ready) return
 
       for (const project of projects) {
         if (!project.id) continue
         if (project.id === "global") continue
-        globalSync.project.icon(project.worktree, project.icon?.override)
+        serverSync.project.icon(project.worktree, project.icon?.override)
       }
     })
 
@@ -509,7 +509,7 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
         colorRequested.set(worktree, color)
 
         if (project.id === "global") {
-          globalSync.project.meta(worktree, { icon: { color } })
+          serverSync.project.meta(worktree, { icon: { color } })
           continue
         }
 
@@ -531,7 +531,7 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
           sessionTimer = undefined
           void Promise.all(
             server.projects.list().map((project) => {
-              return globalSync.project.loadSessions(project.worktree)
+              return serverSync.project.loadSessions(project.worktree)
             }),
           )
         }, 0)
@@ -560,7 +560,7 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
         open(directory: string) {
           const root = rootFor(directory)
           if (server.projects.list().find((x) => x.worktree === root)) return
-          void globalSync.project.loadSessions(root)
+          void serverSync.project.loadSessions(root)
           server.projects.open(root)
         },
         close(directory: string) {

+ 7 - 7
packages/app/src/context/notification.tsx

@@ -2,8 +2,8 @@ import { createStore, reconcile } from "solid-js/store"
 import { batch, createEffect, createMemo, onCleanup } from "solid-js"
 import { useParams } from "@solidjs/router"
 import { createSimpleContext } from "@opencode-ai/ui/context"
-import { useGlobalSDK } from "./global-sdk"
-import { useGlobalSync } from "./global-sync"
+import { useServerSDK } from "./server-sdk"
+import { useServerSync } from "./server-sync"
 import { usePlatform } from "@/context/platform"
 import { useLanguage } from "@/context/language"
 import { useSettings } from "@/context/settings"
@@ -109,8 +109,8 @@ export const { use: useNotification, provider: NotificationProvider } = createSi
   name: "Notification",
   init: () => {
     const params = useParams()
-    const globalSDK = useGlobalSDK()
-    const globalSync = useGlobalSync()
+    const serverSDK = useServerSDK()
+    const serverSync = useServerSync()
     const platform = usePlatform()
     const settings = useSettings()
     const language = useLanguage()
@@ -207,10 +207,10 @@ export const { use: useNotification, provider: NotificationProvider } = createSi
 
     const lookup = async (directory: string, sessionID?: string) => {
       if (!sessionID) return undefined
-      const [syncStore] = globalSync.child(directory, { bootstrap: false })
+      const [syncStore] = serverSync.child(directory, { bootstrap: false })
       const match = Binary.search(syncStore.session, sessionID, (s) => s.id)
       if (match.found) return syncStore.session[match.index]
-      return globalSDK.client.session
+      return serverSDK.client.session
         .get({ directory, sessionID })
         .then((x) => x.data)
         .catch(() => undefined)
@@ -285,7 +285,7 @@ export const { use: useNotification, provider: NotificationProvider } = createSi
       })
     }
 
-    const unsub = globalSDK.event.listen((e) => {
+    const unsub = serverSDK.event.listen((e) => {
       const event = e.details
       if (event.type !== "session.idle" && event.type !== "session.error") return
 

+ 13 - 13
packages/app/src/context/permission.tsx

@@ -3,8 +3,8 @@ import { createStore, produce } from "solid-js/store"
 import { createSimpleContext } from "@opencode-ai/ui/context"
 import type { PermissionRequest } from "@opencode-ai/sdk/v2/client"
 import { Persist, persisted } from "@/utils/persist"
-import { useGlobalSDK } from "@/context/global-sdk"
-import { useGlobalSync } from "./global-sync"
+import { useServerSDK } from "@/context/server-sdk"
+import { useServerSync } from "./server-sync"
 import { useParams } from "@solidjs/router"
 import { decode64 } from "@/utils/base64"
 import {
@@ -48,13 +48,13 @@ export const { use: usePermission, provider: PermissionProvider } = createSimple
   name: "Permission",
   init: () => {
     const params = useParams()
-    const globalSDK = useGlobalSDK()
-    const globalSync = useGlobalSync()
+    const serverSDK = useServerSDK()
+    const serverSync = useServerSync()
 
     const permissionsEnabled = createMemo(() => {
       const directory = decode64(params.dir)
       if (!directory) return false
-      const [store] = globalSync.child(directory)
+      const [store] = serverSync.child(directory)
       return hasPermissionPromptRules(store.config.permission)
     })
 
@@ -86,7 +86,7 @@ export const { use: usePermission, provider: PermissionProvider } = createSimple
       if (!ready()) return
       const directory = decode64(params.dir)
       if (!directory) return
-      const [childStore] = globalSync.child(directory)
+      const [childStore] = serverSync.child(directory)
       const perm = childStore.config.permission
       if (typeof perm === "string" && perm === "allow") {
         const key = directoryAcceptKey(directory)
@@ -118,7 +118,7 @@ export const { use: usePermission, provider: PermissionProvider } = createSimple
     }
 
     const respond: PermissionRespondFn = (input) => {
-      globalSDK.client.permission.respond(input).catch(() => {
+      serverSDK.client.permission.respond(input).catch(() => {
         responded.delete(input.permissionID)
       })
     }
@@ -139,7 +139,7 @@ export const { use: usePermission, provider: PermissionProvider } = createSimple
     }
 
     function isAutoAccepting(sessionID: string, directory?: string) {
-      const session = directory ? globalSync.child(directory, { bootstrap: false })[0].session : []
+      const session = directory ? serverSync.child(directory, { bootstrap: false })[0].session : []
       return autoRespondsPermission(store.autoAccept, session, { sessionID }, directory)
     }
 
@@ -148,7 +148,7 @@ export const { use: usePermission, provider: PermissionProvider } = createSimple
     }
 
     function shouldAutoRespond(permission: PermissionRequest, directory?: string) {
-      const session = directory ? globalSync.child(directory, { bootstrap: false })[0].session : []
+      const session = directory ? serverSync.child(directory, { bootstrap: false })[0].session : []
       return autoRespondsPermission(store.autoAccept, session, permission, directory)
     }
 
@@ -159,7 +159,7 @@ export const { use: usePermission, provider: PermissionProvider } = createSimple
       return next
     }
 
-    const unsubscribe = globalSDK.event.listen((e) => {
+    const unsubscribe = serverSDK.event.listen((e) => {
       const event = e.details
       if (event?.type !== "permission.asked") return
 
@@ -178,7 +178,7 @@ export const { use: usePermission, provider: PermissionProvider } = createSimple
         }),
       )
 
-      globalSDK.client.permission
+      serverSDK.client.permission
         .list({ directory })
         .then((x) => {
           if (!isAutoAcceptingDirectory(directory)) return
@@ -210,7 +210,7 @@ export const { use: usePermission, provider: PermissionProvider } = createSimple
         }),
       )
 
-      globalSDK.client.permission
+      serverSDK.client.permission
         .list({ directory })
         .then((x) => {
           if (enableVersion.get(key) !== version) return
@@ -268,7 +268,7 @@ export const { use: usePermission, provider: PermissionProvider } = createSimple
       },
       permissionsEnabled,
       isPermissionAllowAll(directory: string) {
-        const [childStore] = globalSync.child(directory)
+        const [childStore] = serverSync.child(directory)
         const perm = childStore.config.permission
         return typeof perm === "string" && perm === "allow"
       },

+ 3 - 3
packages/app/src/context/sdk.tsx

@@ -1,11 +1,11 @@
 import { createSimpleContext } from "@opencode-ai/ui/context"
-import { useGlobalSDK } from "./global-sdk"
+import { useServerSDK } from "./server-sdk"
 
 export const { use: useSDK, provider: SDKProvider } = createSimpleContext({
   name: "SDK",
   init: (props: { directory: string }) => {
-    const globalSDK = useGlobalSDK()
+    const serverSDK = useServerSDK()
 
-    return globalSDK.createDirSyncContext(props.directory)
+    return serverSDK.createDirSyncContext(props.directory)
   },
 })

+ 9 - 9
packages/app/src/context/global-sdk.tsx → packages/app/src/context/server-sdk.tsx

@@ -11,7 +11,7 @@ import { useServer } from "./server"
 const isAbortError = (error: unknown) =>
   error !== null && typeof error === "object" && "name" in error && error.name === "AbortError"
 
-export const { use: useGlobalSDK, provider: GlobalSDKProvider } = createSimpleContext({
+export const { use: useServerSDK, provider: ServerSDKProvider } = createSimpleContext({
   name: "GlobalSDK",
   init: () => {
     const language = useLanguage()
@@ -31,7 +31,7 @@ export const { use: useGlobalSDK, provider: GlobalSDKProvider } = createSimpleCo
     })()
 
     const currentServer = server.current
-    if (!currentServer) throw new Error(language.t("error.globalSDK.noServerAvailable"))
+    if (!currentServer) throw new Error(language.t("error.serverSDK.noServerAvailable"))
 
     const eventSdk = createSdkForServer({
       signal: abort.signal,
@@ -245,7 +245,7 @@ export const { use: useGlobalSDK, provider: GlobalSDKProvider } = createSimpleCo
       },
       createClient(opts: Omit<Parameters<typeof createSdkForServer>[0], "server" | "fetch">) {
         const s = server.current
-        if (!s) throw new Error(language.t("error.globalSDK.serverNotAvailable"))
+        if (!s) throw new Error(language.t("error.serverSDK.serverNotAvailable"))
         return createSdkForServer({
           server: s.http,
           fetch: platform.fetch,
@@ -281,16 +281,16 @@ type SDKEventMap = {
 }
 
 function createDirSdkContext(directory: string) {
-  const globalSDK = useGlobalSDK()
+  const serverSDK = useServerSDK()
 
-  const client = globalSDK.createClient({
+  const client = serverSDK.createClient({
     directory,
     throwOnError: true,
   })
 
   const emitter = createGlobalEmitter<SDKEventMap>()
 
-  const unsub = globalSDK.event.on(directory, (event) => {
+  const unsub = serverSDK.event.on(directory, (event) => {
     emitter.emit(event.type, event)
   })
   onCleanup(unsub)
@@ -300,10 +300,10 @@ function createDirSdkContext(directory: string) {
     client,
     event: emitter,
     get url() {
-      return globalSDK.url
+      return serverSDK.url
     },
-    createClient(opts: Parameters<typeof globalSDK.createClient>[0]) {
-      return globalSDK.createClient(opts)
+    createClient(opts: Parameters<typeof serverSDK.createClient>[0]) {
+      return serverSDK.createClient(opts)
     },
   }
 }

+ 0 - 0
packages/app/src/context/global-sync.test.ts → packages/app/src/context/server-sync.test.ts


+ 26 - 26
packages/app/src/context/global-sync.tsx → packages/app/src/context/server-sync.tsx

@@ -5,7 +5,7 @@ import { batch, createContext, getOwner, onCleanup, onMount, type ParentProps, u
 import { createStore, produce, reconcile } from "solid-js/store"
 import { useLanguage } from "@/context/language"
 import type { InitError } from "../pages/error"
-import { useGlobalSDK } from "./global-sdk"
+import { useServerSDK } from "./server-sdk"
 import {
   bootstrapDirectory,
   bootstrapGlobal,
@@ -57,13 +57,13 @@ export const loadLspQuery = (directory: string, sdk: OpencodeClient) =>
     queryFn: () => sdk.lsp.status().then((r) => r.data ?? []),
   })
 
-function makeQueryOptionsApi(globalSDK: () => OpencodeClient, sdkFor: (dir: PathKey) => OpencodeClient) {
+function makeQueryOptionsApi(serverSDK: () => OpencodeClient, sdkFor: (dir: PathKey) => OpencodeClient) {
   return {
-    globalConfig: () => loadGlobalConfigQuery(globalSDK()),
-    projects: () => loadProjectsQuery(globalSDK()),
+    globalConfig: () => loadGlobalConfigQuery(serverSDK()),
+    projects: () => loadProjectsQuery(serverSDK()),
     providers: (directory: PathKey | null) =>
-      loadProvidersQuery(directory, directory === null ? globalSDK() : sdkFor(directory)),
-    path: (directory: PathKey | null) => loadPathQuery(directory, directory === null ? globalSDK() : sdkFor(directory)),
+      loadProvidersQuery(directory, directory === null ? serverSDK() : sdkFor(directory)),
+    path: (directory: PathKey | null) => loadPathQuery(directory, directory === null ? serverSDK() : sdkFor(directory)),
     agents: (directory: PathKey) => loadAgentsQuery(directory, sdkFor(directory)),
     mcp: (directory: PathKey) => loadMcpQuery(directory, sdkFor(directory)),
     lsp: (directory: PathKey) => loadLspQuery(directory, sdkFor(directory)),
@@ -72,11 +72,11 @@ function makeQueryOptionsApi(globalSDK: () => OpencodeClient, sdkFor: (dir: Path
 }
 export type QueryOptionsApi = ReturnType<typeof makeQueryOptionsApi>
 
-function createGlobalSync() {
-  const globalSDK = useGlobalSDK()
+function createServerSyncContext() {
+  const serverSDK = useServerSDK()
   const language = useLanguage()
   const owner = getOwner()
-  if (!owner) throw new Error("GlobalSync must be created within owner")
+  if (!owner) throw new Error("ServerSync must be created within owner")
 
   const sdkCache = new Map<string, OpencodeClient>()
   const booting = new Map<string, Promise<void>>()
@@ -87,7 +87,7 @@ function createGlobalSync() {
     const key = directoryKey(directory)
     const cached = sdkCache.get(key)
     if (cached) return cached
-    const sdk = globalSDK.createClient({
+    const sdk = serverSDK.createClient({
       directory,
       throwOnError: true,
     })
@@ -95,7 +95,7 @@ function createGlobalSync() {
     return sdk
   }
 
-  const queryOptionsApi = makeQueryOptionsApi(() => globalSDK.client, sdkFor)
+  const queryOptionsApi = makeQueryOptionsApi(() => serverSDK.client, sdkFor)
 
   const [configQuery, providerQuery, pathQuery] = useQueries(() => ({
     queries: [queryOptionsApi.globalConfig(), queryOptionsApi.providers(null), queryOptionsApi.path(null)],
@@ -154,7 +154,7 @@ function createGlobalSync() {
     queryKey: ["bootstrap"],
     queryFn: async () => {
       await bootstrapGlobal({
-        globalSDK: globalSDK.client,
+        serverSDK: serverSDK.client,
         requestFailedTitle: language.t("common.requestFailed"),
         translate: language.t,
         formatMoreCount: (count) => language.t("common.moreCountSuffix", { count }),
@@ -248,7 +248,7 @@ function createGlobalSync() {
           loadRootSessionsWithFallback({
             directory,
             limit,
-            list: (query) => globalSDK.client.session.list(query),
+            list: (query) => serverSDK.client.session.list(query),
           })
             .then((x) => {
               const nonArchived = (x.data ?? [])
@@ -334,7 +334,7 @@ function createGlobalSync() {
     return promise
   }
 
-  const unsub = globalSDK.event.listen((e) => {
+  const unsub = serverSDK.event.listen((e) => {
     const directory = e.name
     const key = directoryKey(directory)
     const event = e.details
@@ -393,13 +393,13 @@ function createGlobalSync() {
         eventFrame = undefined
         eventTimer = setTimeout(() => {
           eventTimer = undefined
-          void globalSDK.event.start()
+          void serverSDK.event.start()
         }, 0)
       })
     } else {
       eventTimer = setTimeout(() => {
         eventTimer = undefined
-        void globalSDK.event.start()
+        void serverSDK.event.start()
       }, 0)
     }
   })
@@ -415,7 +415,7 @@ function createGlobalSync() {
   }
 
   const updateConfigMutation = useMutation(() => ({
-    mutationFn: (config: Config) => globalSDK.client.global.config.update({ config }),
+    mutationFn: (config: Config) => serverSDK.client.global.config.update({ config }),
     onSuccess: () => {
       bootstrap.refetch()
       // Invalidate all provider queries so newly configured custom providers
@@ -460,7 +460,7 @@ function createGlobalSync() {
         dirSyncContextRefCounts.set(directory, (dirSyncContextRefCounts.get(directory) ?? 0) + 1)
         return cached
       }
-      const ctx = createDirSyncContext(globalSDK.createClient({ directory, throwOnError: true }), directory)
+      const ctx = createDirSyncContext(serverSDK.createClient({ directory, throwOnError: true }), directory)
       dirSyncContexts.set(directory, ctx)
       dirSyncContextRefCounts.set(directory, 1)
 
@@ -469,19 +469,19 @@ function createGlobalSync() {
   }
 }
 
-const GlobalSyncContext = createContext<ReturnType<typeof createGlobalSync>>()
+const ServerSyncContext = createContext<ReturnType<typeof createServerSyncContext>>()
 
-export function GlobalSyncProvider(props: ParentProps) {
-  const value = createGlobalSync()
-  return <GlobalSyncContext.Provider value={value}>{props.children}</GlobalSyncContext.Provider>
+export function ServerSyncProvider(props: ParentProps) {
+  const value = createServerSyncContext()
+  return <ServerSyncContext.Provider value={value}>{props.children}</ServerSyncContext.Provider>
 }
 
-export function useGlobalSync() {
-  const context = useContext(GlobalSyncContext)
-  if (!context) throw new Error("useGlobalSync must be used within GlobalSyncProvider")
+export function useServerSync() {
+  const context = useContext(ServerSyncContext)
+  if (!context) throw new Error("useServerSync must be used within ServerSyncProvider")
   return context
 }
 
 export function useQueryOptions() {
-  return useGlobalSync().queryOptions
+  return useServerSync().queryOptions
 }

+ 3 - 3
packages/app/src/context/sync.tsx

@@ -1,5 +1,5 @@
 import { Binary } from "@opencode-ai/core/util/binary"
-import { useGlobalSync } from "./global-sync"
+import { useServerSync } from "./server-sync"
 import { useSDK } from "./sdk"
 import type { Message, Part } from "@opencode-ai/sdk/v2/client"
 
@@ -109,8 +109,8 @@ export function applyOptimisticRemove(draft: OptimisticStore, input: OptimisticR
 }
 
 export const useSync = () => {
-  const globalSync = useGlobalSync()
+  const serverSync = useServerSync()
   const sdk = useSDK()
 
-  return globalSync.createDirSyncContext(sdk.directory)
+  return serverSync.createDirSyncContext(sdk.directory)
 }

+ 4 - 4
packages/app/src/hooks/use-providers.ts

@@ -1,4 +1,4 @@
-import { useGlobalSync } from "@/context/global-sync"
+import { useServerSync } from "@/context/server-sync"
 import { decode64 } from "@/utils/base64"
 import { useParams } from "@solidjs/router"
 import { Iterable, pipe } from "effect"
@@ -17,15 +17,15 @@ export const popularProviders = [
 const popularProviderSet = new Set(popularProviders)
 
 export function useProviders() {
-  const globalSync = useGlobalSync()
+  const serverSync = useServerSync()
   const params = useParams()
   const dir = createMemo(() => decode64(params.dir) ?? "")
   const providers = () => {
     if (dir()) {
-      const [projectStore] = globalSync.child(dir())
+      const [projectStore] = serverSync.child(dir())
       if (projectStore.provider_ready) return projectStore.provider
     }
-    return globalSync.data.provider
+    return serverSync.data.provider
   }
   return {
     all: () => providers().all,

+ 3 - 3
packages/app/src/i18n/ar.ts

@@ -413,7 +413,7 @@ export const dict = {
   "error.page.version": "الإصدار: {{version}}",
   "error.dev.rootNotFound":
     "لم يتم العثور على العنصر الجذري. هل نسيت إضافته إلى index.html؟ أو ربما تمت كتابة سمة id بشكل خاطئ؟",
-  "error.globalSync.connectFailed": "تعذر الاتصال بالخادم. هل هناك خادم يعمل في `{{url}}`؟",
+  "error.serverSync.connectFailed": "تعذر الاتصال بالخادم. هل هناك خادم يعمل في `{{url}}`؟",
   "directory.error.invalidUrl": "دليل غير صالح في عنوان URL.",
   "error.chain.unknown": "خطأ غير معروف",
   "error.chain.causedBy": "بسبب:",
@@ -837,8 +837,8 @@ export const dict = {
   "common.key.insert": "Insert",
   "common.unknown": "غير معروف",
   "error.page.circular": "[دائري]",
-  "error.globalSDK.noServerAvailable": "لا يوجد خادم متاح",
-  "error.globalSDK.serverNotAvailable": "الخادم غير متاح",
+  "error.serverSDK.noServerAvailable": "لا يوجد خادم متاح",
+  "error.serverSDK.serverNotAvailable": "الخادم غير متاح",
   "error.childStore.persistedCacheCreateFailed": "فشل إنشاء ذاكرة التخزين المؤقت الدائمة",
   "error.childStore.persistedProjectMetadataCreateFailed": "فشل إنشاء بيانات تعريف المشروع الدائمة",
   "error.childStore.persistedProjectIconCreateFailed": "فشل إنشاء أيقونة المشروع الدائمة",

+ 3 - 3
packages/app/src/i18n/br.ts

@@ -414,7 +414,7 @@ export const dict = {
   "error.page.version": "Versão: {{version}}",
   "error.dev.rootNotFound":
     "Elemento raiz não encontrado. Você esqueceu de adicioná-lo ao seu index.html? Ou talvez o atributo id foi escrito incorretamente?",
-  "error.globalSync.connectFailed": "Não foi possível conectar ao servidor. Há um servidor executando em `{{url}}`?",
+  "error.serverSync.connectFailed": "Não foi possível conectar ao servidor. Há um servidor executando em `{{url}}`?",
   "directory.error.invalidUrl": "Diretório inválido na URL.",
   "error.chain.unknown": "Erro desconhecido",
   "error.chain.causedBy": "Causado por:",
@@ -850,8 +850,8 @@ export const dict = {
   "common.key.insert": "Insert",
   "common.unknown": "desconhecido",
   "error.page.circular": "[Circular]",
-  "error.globalSDK.noServerAvailable": "Nenhum servidor disponível",
-  "error.globalSDK.serverNotAvailable": "Servidor indisponível",
+  "error.serverSDK.noServerAvailable": "Nenhum servidor disponível",
+  "error.serverSDK.serverNotAvailable": "Servidor indisponível",
   "error.childStore.persistedCacheCreateFailed": "Falha ao criar cache persistente",
   "error.childStore.persistedProjectMetadataCreateFailed": "Falha ao criar metadados de projeto persistentes",
   "error.childStore.persistedProjectIconCreateFailed": "Falha ao criar ícone de projeto persistente",

+ 3 - 3
packages/app/src/i18n/bs.ts

@@ -462,7 +462,7 @@ export const dict = {
   "error.dev.rootNotFound":
     "Korijenski element nije pronađen. Da li si zaboravio da ga dodaš u index.html? Ili je možda id atribut pogrešno napisan?",
 
-  "error.globalSync.connectFailed": "Nije moguće povezati se na server. Da li server radi na `{{url}}`?",
+  "error.serverSync.connectFailed": "Nije moguće povezati se na server. Da li server radi na `{{url}}`?",
   "directory.error.invalidUrl": "Nevažeći direktorij u URL-u.",
 
   "error.chain.unknown": "Nepoznata greška",
@@ -926,8 +926,8 @@ export const dict = {
   "common.key.insert": "Insert",
   "common.unknown": "nepoznato",
   "error.page.circular": "[Kružno]",
-  "error.globalSDK.noServerAvailable": "Nema dostupnog servera",
-  "error.globalSDK.serverNotAvailable": "Server nije dostupan",
+  "error.serverSDK.noServerAvailable": "Nema dostupnog servera",
+  "error.serverSDK.serverNotAvailable": "Server nije dostupan",
   "error.childStore.persistedCacheCreateFailed": "Nije uspjelo kreiranje trajnog keša",
   "error.childStore.persistedProjectMetadataCreateFailed": "Nije uspjelo kreiranje trajnih metapodataka projekta",
   "error.childStore.persistedProjectIconCreateFailed": "Nije uspjelo kreiranje trajne ikone projekta",

+ 3 - 3
packages/app/src/i18n/da.ts

@@ -459,7 +459,7 @@ export const dict = {
   "error.dev.rootNotFound":
     "Rodelement ikke fundet. Har du glemt at tilføje det til din index.html? Eller måske er id-attributten stavet forkert?",
 
-  "error.globalSync.connectFailed": "Kunne ikke forbinde til server. Kører der en server på `{{url}}`?",
+  "error.serverSync.connectFailed": "Kunne ikke forbinde til server. Kører der en server på `{{url}}`?",
   "directory.error.invalidUrl": "Ugyldig mappe i URL.",
 
   "error.chain.unknown": "Ukendt fejl",
@@ -920,8 +920,8 @@ export const dict = {
   "common.key.insert": "Insert",
   "common.unknown": "ukendt",
   "error.page.circular": "[Cirkulær]",
-  "error.globalSDK.noServerAvailable": "Ingen server tilgængelig",
-  "error.globalSDK.serverNotAvailable": "Server ikke tilgængelig",
+  "error.serverSDK.noServerAvailable": "Ingen server tilgængelig",
+  "error.serverSDK.serverNotAvailable": "Server ikke tilgængelig",
   "error.childStore.persistedCacheCreateFailed": "Kunne ikke oprette vedvarende cache",
   "error.childStore.persistedProjectMetadataCreateFailed": "Kunne ikke oprette vedvarende projektmetadata",
   "error.childStore.persistedProjectIconCreateFailed": "Kunne ikke oprette vedvarende projektikon",

+ 3 - 3
packages/app/src/i18n/de.ts

@@ -421,7 +421,7 @@ export const dict = {
   "error.page.version": "Version: {{version}}",
   "error.dev.rootNotFound":
     "Wurzelelement nicht gefunden. Haben Sie vergessen, es in Ihre index.html aufzunehmen? Oder wurde das id-Attribut falsch geschrieben?",
-  "error.globalSync.connectFailed": "Verbindung zum Server fehlgeschlagen. Läuft ein Server unter `{{url}}`?",
+  "error.serverSync.connectFailed": "Verbindung zum Server fehlgeschlagen. Läuft ein Server unter `{{url}}`?",
   "directory.error.invalidUrl": "Ungültiges Verzeichnis in der URL.",
   "error.chain.unknown": "Unbekannter Fehler",
   "error.chain.causedBy": "Verursacht durch:",
@@ -862,8 +862,8 @@ export const dict = {
   "common.key.insert": "Einfg",
   "common.unknown": "unbekannt",
   "error.page.circular": "[Zirkulär]",
-  "error.globalSDK.noServerAvailable": "Kein Server verfügbar",
-  "error.globalSDK.serverNotAvailable": "Server nicht verfügbar",
+  "error.serverSDK.noServerAvailable": "Kein Server verfügbar",
+  "error.serverSDK.serverNotAvailable": "Server nicht verfügbar",
   "error.childStore.persistedCacheCreateFailed": "Dauerhafter Cache konnte nicht erstellt werden",
   "error.childStore.persistedProjectMetadataCreateFailed": "Dauerhafte Projektmetadaten konnten nicht erstellt werden",
   "error.childStore.persistedProjectIconCreateFailed": "Dauerhaftes Projekticon konnte nicht erstellt werden",

+ 3 - 3
packages/app/src/i18n/en.ts

@@ -482,9 +482,9 @@ export const dict = {
   "error.dev.rootNotFound":
     "Root element not found. Did you forget to add it to your index.html? Or maybe the id attribute got misspelled?",
 
-  "error.globalSync.connectFailed": "Could not connect to server. Is there a server running at `{{url}}`?",
-  "error.globalSDK.noServerAvailable": "No server available",
-  "error.globalSDK.serverNotAvailable": "Server not available",
+  "error.serverSync.connectFailed": "Could not connect to server. Is there a server running at `{{url}}`?",
+  "error.serverSDK.noServerAvailable": "No server available",
+  "error.serverSDK.serverNotAvailable": "Server not available",
   "error.childStore.persistedCacheCreateFailed": "Failed to create persisted cache",
   "error.childStore.persistedProjectMetadataCreateFailed": "Failed to create persisted project metadata",
   "error.childStore.persistedProjectIconCreateFailed": "Failed to create persisted project icon",

+ 3 - 3
packages/app/src/i18n/es.ts

@@ -462,7 +462,7 @@ export const dict = {
   "error.dev.rootNotFound":
     "Elemento raíz no encontrado. ¿Olvidaste añadirlo a tu index.html? ¿O tal vez el atributo id está mal escrito?",
 
-  "error.globalSync.connectFailed": "No se pudo conectar al servidor. ¿Hay un servidor ejecutándose en `{{url}}`?",
+  "error.serverSync.connectFailed": "No se pudo conectar al servidor. ¿Hay un servidor ejecutándose en `{{url}}`?",
   "directory.error.invalidUrl": "URL de directorio inválida.",
 
   "error.chain.unknown": "Error desconocido",
@@ -933,8 +933,8 @@ export const dict = {
   "common.key.insert": "Insert",
   "common.unknown": "desconocido",
   "error.page.circular": "[Circular]",
-  "error.globalSDK.noServerAvailable": "Ningún servidor disponible",
-  "error.globalSDK.serverNotAvailable": "Servidor no disponible",
+  "error.serverSDK.noServerAvailable": "Ningún servidor disponible",
+  "error.serverSDK.serverNotAvailable": "Servidor no disponible",
   "error.childStore.persistedCacheCreateFailed": "Error al crear caché persistente",
   "error.childStore.persistedProjectMetadataCreateFailed": "Error al crear metadatos de proyecto persistentes",
   "error.childStore.persistedProjectIconCreateFailed": "Error al crear icono de proyecto persistente",

+ 3 - 3
packages/app/src/i18n/fr.ts

@@ -417,7 +417,7 @@ export const dict = {
   "error.page.version": "Version : {{version}}",
   "error.dev.rootNotFound":
     "Élément racine introuvable. Avez-vous oublié de l'ajouter à votre index.html ? Ou peut-être que l'attribut id est mal orthographié ?",
-  "error.globalSync.connectFailed":
+  "error.serverSync.connectFailed":
     "Impossible de se connecter au serveur. Y a-t-il un serveur en cours d'exécution à `{{url}}` ?",
   "directory.error.invalidUrl": "Répertoire invalide dans l'URL.",
   "error.chain.unknown": "Erreur inconnue",
@@ -860,8 +860,8 @@ export const dict = {
   "common.key.insert": "Inser",
   "common.unknown": "inconnu",
   "error.page.circular": "[Circulaire]",
-  "error.globalSDK.noServerAvailable": "Aucun serveur disponible",
-  "error.globalSDK.serverNotAvailable": "Serveur non disponible",
+  "error.serverSDK.noServerAvailable": "Aucun serveur disponible",
+  "error.serverSDK.serverNotAvailable": "Serveur non disponible",
   "error.childStore.persistedCacheCreateFailed": "Échec de la création du cache persistant",
   "error.childStore.persistedProjectMetadataCreateFailed":
     "Échec de la création des métadonnées de projet persistantes",

+ 3 - 3
packages/app/src/i18n/ja.ts

@@ -413,7 +413,7 @@ export const dict = {
   "error.page.version": "バージョン: {{version}}",
   "error.dev.rootNotFound":
     "ルート要素が見つかりません。index.htmlに追加するのを忘れていませんか?またはid属性のスペルが間違っていませんか?",
-  "error.globalSync.connectFailed": "サーバーに接続できませんでした。`{{url}}`でサーバーが実行されていますか?",
+  "error.serverSync.connectFailed": "サーバーに接続できませんでした。`{{url}}`でサーバーが実行されていますか?",
   "directory.error.invalidUrl": "URL内のディレクトリが無効です。",
   "error.chain.unknown": "不明なエラー",
   "error.chain.causedBy": "原因:",
@@ -844,8 +844,8 @@ export const dict = {
   "common.key.insert": "Insert",
   "common.unknown": "不明",
   "error.page.circular": "[循環]",
-  "error.globalSDK.noServerAvailable": "利用可能なサーバーがありません",
-  "error.globalSDK.serverNotAvailable": "サーバーが利用できません",
+  "error.serverSDK.noServerAvailable": "利用可能なサーバーがありません",
+  "error.serverSDK.serverNotAvailable": "サーバーが利用できません",
   "error.childStore.persistedCacheCreateFailed": "永続キャッシュの作成に失敗しました",
   "error.childStore.persistedProjectMetadataCreateFailed": "永続プロジェクトメタデータの作成に失敗しました",
   "error.childStore.persistedProjectIconCreateFailed": "永続プロジェクトアイコンの作成に失敗しました",

+ 3 - 3
packages/app/src/i18n/ko.ts

@@ -412,7 +412,7 @@ export const dict = {
   "error.page.version": "버전: {{version}}",
   "error.dev.rootNotFound":
     "루트 요소를 찾을 수 없습니다. index.html에 추가하는 것을 잊으셨나요? 또는 id 속성의 철자가 틀렸을 수 있습니다.",
-  "error.globalSync.connectFailed": "서버에 연결할 수 없습니다. `{{url}}`에서 서버가 실행 중인가요?",
+  "error.serverSync.connectFailed": "서버에 연결할 수 없습니다. `{{url}}`에서 서버가 실행 중인가요?",
   "directory.error.invalidUrl": "URL에 유효하지 않은 디렉터리가 있습니다.",
   "error.chain.unknown": "알 수 없는 오류",
   "error.chain.causedBy": "원인:",
@@ -839,8 +839,8 @@ export const dict = {
   "common.key.insert": "Insert",
   "common.unknown": "알 수 없음",
   "error.page.circular": "[순환]",
-  "error.globalSDK.noServerAvailable": "사용 가능한 서버 없음",
-  "error.globalSDK.serverNotAvailable": "서버를 사용할 수 없음",
+  "error.serverSDK.noServerAvailable": "사용 가능한 서버 없음",
+  "error.serverSDK.serverNotAvailable": "서버를 사용할 수 없음",
   "error.childStore.persistedCacheCreateFailed": "영구 캐시 생성 실패",
   "error.childStore.persistedProjectMetadataCreateFailed": "영구 프로젝트 메타데이터 생성 실패",
   "error.childStore.persistedProjectIconCreateFailed": "영구 프로젝트 아이콘 생성 실패",

+ 3 - 3
packages/app/src/i18n/no.ts

@@ -463,7 +463,7 @@ export const dict = {
   "error.dev.rootNotFound":
     "Rotelement ikke funnet. Glemte du å legge det til i index.html? Eller kanskje id-attributten er feilstavet?",
 
-  "error.globalSync.connectFailed": "Kunne ikke koble til server. Kjører det en server på `{{url}}`?",
+  "error.serverSync.connectFailed": "Kunne ikke koble til server. Kjører det en server på `{{url}}`?",
   "directory.error.invalidUrl": "Invalid directory in URL.",
 
   "error.chain.unknown": "Ukjent feil",
@@ -927,8 +927,8 @@ export const dict = {
   "common.key.insert": "Insert",
   "common.unknown": "ukjent",
   "error.page.circular": "[Sirkulær]",
-  "error.globalSDK.noServerAvailable": "Ingen server tilgjengelig",
-  "error.globalSDK.serverNotAvailable": "Server ikke tilgjengelig",
+  "error.serverSDK.noServerAvailable": "Ingen server tilgjengelig",
+  "error.serverSDK.serverNotAvailable": "Server ikke tilgjengelig",
   "error.childStore.persistedCacheCreateFailed": "Kunne ikke opprette vedvarende hurtigbuffer",
   "error.childStore.persistedProjectMetadataCreateFailed": "Kunne ikke opprette vedvarende prosjektmetadata",
   "error.childStore.persistedProjectIconCreateFailed": "Kunne ikke opprette vedvarende prosjektikon",

+ 3 - 3
packages/app/src/i18n/pl.ts

@@ -414,7 +414,7 @@ export const dict = {
   "error.page.version": "Wersja: {{version}}",
   "error.dev.rootNotFound":
     "Nie znaleziono elementu głównego. Czy zapomniałeś dodać go do swojego index.html? A może atrybut id został błędnie wpisany?",
-  "error.globalSync.connectFailed": "Nie można połączyć się z serwerem. Czy serwer działa pod adresem `{{url}}`?",
+  "error.serverSync.connectFailed": "Nie można połączyć się z serwerem. Czy serwer działa pod adresem `{{url}}`?",
   "directory.error.invalidUrl": "Nieprawidłowy katalog w URL.",
   "error.chain.unknown": "Nieznany błąd",
   "error.chain.causedBy": "Spowodowany przez:",
@@ -848,8 +848,8 @@ export const dict = {
   "common.key.insert": "Insert",
   "common.unknown": "nieznany",
   "error.page.circular": "[Cykliczne]",
-  "error.globalSDK.noServerAvailable": "Brak dostępnego serwera",
-  "error.globalSDK.serverNotAvailable": "Serwer niedostępny",
+  "error.serverSDK.noServerAvailable": "Brak dostępnego serwera",
+  "error.serverSDK.serverNotAvailable": "Serwer niedostępny",
   "error.childStore.persistedCacheCreateFailed": "Nie udało się utworzyć trwałej pamięci podręcznej",
   "error.childStore.persistedProjectMetadataCreateFailed": "Nie udało się utworzyć trwałych metadanych projektu",
   "error.childStore.persistedProjectIconCreateFailed": "Nie udało się utworzyć trwałej ikony projektu",

+ 3 - 3
packages/app/src/i18n/ru.ts

@@ -461,7 +461,7 @@ export const dict = {
   "error.dev.rootNotFound":
     "Корневой элемент не найден. Вы забыли добавить его в index.html? Или, может быть, атрибут id был написан неправильно?",
 
-  "error.globalSync.connectFailed": "Не удалось подключиться к серверу. Запущен ли сервер по адресу `{{url}}`?",
+  "error.serverSync.connectFailed": "Не удалось подключиться к серверу. Запущен ли сервер по адресу `{{url}}`?",
   "directory.error.invalidUrl": "Недопустимая директория в URL.",
 
   "error.chain.unknown": "Неизвестная ошибка",
@@ -929,8 +929,8 @@ export const dict = {
   "common.key.insert": "Insert",
   "common.unknown": "неизвестно",
   "error.page.circular": "[Циклично]",
-  "error.globalSDK.noServerAvailable": "Нет доступного сервера",
-  "error.globalSDK.serverNotAvailable": "Сервер недоступен",
+  "error.serverSDK.noServerAvailable": "Нет доступного сервера",
+  "error.serverSDK.serverNotAvailable": "Сервер недоступен",
   "error.childStore.persistedCacheCreateFailed": "Не удалось создать постоянный кэш",
   "error.childStore.persistedProjectMetadataCreateFailed": "Не удалось создать постоянные метаданные проекта",
   "error.childStore.persistedProjectIconCreateFailed": "Не удалось создать постоянный значок проекта",

+ 3 - 3
packages/app/src/i18n/th.ts

@@ -459,7 +459,7 @@ export const dict = {
 
   "error.dev.rootNotFound": "ไม่พบองค์ประกอบรูท คุณลืมเพิ่มใน index.html หรือบางทีแอตทริบิวต์ id อาจสะกดผิด?",
 
-  "error.globalSync.connectFailed": "ไม่สามารถเชื่อมต่อกับเซิร์ฟเวอร์ มีเซิร์ฟเวอร์ทำงานอยู่ที่ `{{url}}` หรือไม่?",
+  "error.serverSync.connectFailed": "ไม่สามารถเชื่อมต่อกับเซิร์ฟเวอร์ มีเซิร์ฟเวอร์ทำงานอยู่ที่ `{{url}}` หรือไม่?",
   "directory.error.invalidUrl": "ไดเรกทอรีใน URL ไม่ถูกต้อง",
 
   "error.chain.unknown": "ข้อผิดพลาดที่ไม่รู้จัก",
@@ -916,8 +916,8 @@ export const dict = {
   "common.key.insert": "Insert",
   "common.unknown": "ไม่ทราบ",
   "error.page.circular": "[วงกลม]",
-  "error.globalSDK.noServerAvailable": "ไม่มีเซิร์ฟเวอร์",
-  "error.globalSDK.serverNotAvailable": "เซิร์ฟเวอร์ไม่พร้อมใช้งาน",
+  "error.serverSDK.noServerAvailable": "ไม่มีเซิร์ฟเวอร์",
+  "error.serverSDK.serverNotAvailable": "เซิร์ฟเวอร์ไม่พร้อมใช้งาน",
   "error.childStore.persistedCacheCreateFailed": "ไม่สามารถสร้างแคชถาวร",
   "error.childStore.persistedProjectMetadataCreateFailed": "ไม่สามารถสร้างเมตาดาต้าโปรเจกต์ถาวร",
   "error.childStore.persistedProjectIconCreateFailed": "ไม่สามารถสร้างไอคอนโปรเจกต์ถาวร",

+ 3 - 3
packages/app/src/i18n/tr.ts

@@ -465,7 +465,7 @@ export const dict = {
   "error.dev.rootNotFound":
     "Kök eleman bulunamadı. index.html dosyanıza eklemeyi unuttunuz mu? Ya da id özelliği yanlış mı yazıldı?",
 
-  "error.globalSync.connectFailed": "Sunucuya bağlanılamadı. `{{url}}` adresinde çalışan bir sunucu var mı?",
+  "error.serverSync.connectFailed": "Sunucuya bağlanılamadı. `{{url}}` adresinde çalışan bir sunucu var mı?",
   "directory.error.invalidUrl": "URL'de geçersiz dizin.",
 
   "error.chain.unknown": "Bilinmeyen hata",
@@ -935,8 +935,8 @@ export const dict = {
   "common.key.insert": "Insert",
   "common.unknown": "bilinmiyor",
   "error.page.circular": "[Döngüsel]",
-  "error.globalSDK.noServerAvailable": "Sunucu yok",
-  "error.globalSDK.serverNotAvailable": "Sunucu mevcut değil",
+  "error.serverSDK.noServerAvailable": "Sunucu yok",
+  "error.serverSDK.serverNotAvailable": "Sunucu mevcut değil",
   "error.childStore.persistedCacheCreateFailed": "Kalıcı önbellek oluşturulamadı",
   "error.childStore.persistedProjectMetadataCreateFailed": "Kalıcı proje meta verileri oluşturulamadı",
   "error.childStore.persistedProjectIconCreateFailed": "Kalıcı proje simgesi oluşturulamadı",

+ 3 - 3
packages/app/src/i18n/uk.ts

@@ -483,9 +483,9 @@ export const dict = {
   "error.dev.rootNotFound":
     "Кореневий елемент не знайдено. Ви забули додати його до index.html? Або, можливо, атрибут id було написано з помилкою?",
 
-  "error.globalSync.connectFailed": "Не вдалося підключитися до сервера. Чи працює сервер за адресою `{{url}}`?",
-  "error.globalSDK.noServerAvailable": "Сервер недоступний",
-  "error.globalSDK.serverNotAvailable": "Сервер недоступний",
+  "error.serverSync.connectFailed": "Не вдалося підключитися до сервера. Чи працює сервер за адресою `{{url}}`?",
+  "error.serverSDK.noServerAvailable": "Сервер недоступний",
+  "error.serverSDK.serverNotAvailable": "Сервер недоступний",
   "error.childStore.persistedCacheCreateFailed": "Не вдалося створити постійний кеш",
   "error.childStore.persistedProjectMetadataCreateFailed": "Не вдалося створити постійні метадані проєкту",
   "error.childStore.persistedProjectIconCreateFailed": "Не вдалося створити постійну іконку проєкту",

+ 3 - 3
packages/app/src/i18n/zh.ts

@@ -462,7 +462,7 @@ export const dict = {
   "error.page.report.discord": "在 Discord 上",
   "error.page.version": "版本:{{version}}",
   "error.dev.rootNotFound": "未找到根元素。你是不是忘了把它添加到 index.html?或者 id 属性拼写错了?",
-  "error.globalSync.connectFailed": "无法连接到服务器。是否有服务器正在 `{{url}}` 运行?",
+  "error.serverSync.connectFailed": "无法连接到服务器。是否有服务器正在 `{{url}}` 运行?",
 
   "directory.error.invalidUrl": "URL 中的目录无效。",
 
@@ -919,8 +919,8 @@ export const dict = {
   "common.key.insert": "Insert",
   "common.unknown": "未知",
   "error.page.circular": "[循环]",
-  "error.globalSDK.noServerAvailable": "无可用服务器",
-  "error.globalSDK.serverNotAvailable": "服务器不可用",
+  "error.serverSDK.noServerAvailable": "无可用服务器",
+  "error.serverSDK.serverNotAvailable": "服务器不可用",
   "error.childStore.persistedCacheCreateFailed": "创建持久化缓存失败",
   "error.childStore.persistedProjectMetadataCreateFailed": "创建持久化项目元数据失败",
   "error.childStore.persistedProjectIconCreateFailed": "创建持久化项目图标失败",

+ 3 - 3
packages/app/src/i18n/zht.ts

@@ -457,7 +457,7 @@ export const dict = {
 
   "error.dev.rootNotFound": "找不到根元素。你是不是忘了把它新增到 index.html? 或者 id 屬性拼錯了?",
 
-  "error.globalSync.connectFailed": "無法連線到伺服器。是否有伺服器正在 `{{url}}` 執行?",
+  "error.serverSync.connectFailed": "無法連線到伺服器。是否有伺服器正在 `{{url}}` 執行?",
   "directory.error.invalidUrl": "URL 中的目錄無效。",
 
   "error.chain.unknown": "未知錯誤",
@@ -907,8 +907,8 @@ export const dict = {
   "common.key.insert": "Insert",
   "common.unknown": "未知",
   "error.page.circular": "[循環]",
-  "error.globalSDK.noServerAvailable": "無可用的伺服器",
-  "error.globalSDK.serverNotAvailable": "伺服器無法使用",
+  "error.serverSDK.noServerAvailable": "無可用的伺服器",
+  "error.serverSDK.serverNotAvailable": "伺服器無法使用",
   "error.childStore.persistedCacheCreateFailed": "建立持續性快取失敗",
   "error.childStore.persistedProjectMetadataCreateFailed": "建立持續性專案中繼資料失敗",
   "error.childStore.persistedProjectIconCreateFailed": "建立持續性專案圖示失敗",

+ 5 - 5
packages/app/src/pages/home.tsx

@@ -19,7 +19,7 @@ import { useDialog } from "@opencode-ai/ui/context/dialog"
 import { DialogSelectDirectory } from "@/components/dialog-select-directory"
 import { DialogSelectServer } from "@/components/dialog-select-server"
 import { useServer } from "@/context/server"
-import { useGlobalSync } from "@/context/global-sync"
+import { useServerSync } from "@/context/server-sync"
 import { useLanguage } from "@/context/language"
 import { useNotification } from "@/context/notification"
 import { usePermission } from "@/context/permission"
@@ -55,7 +55,7 @@ export default function Home() {
 }
 
 function HomeDesign() {
-  const sync = useGlobalSync()
+  const sync = useServerSync()
   const layout = useLayout()
   const platform = usePlatform()
   const dialog = useDialog()
@@ -358,10 +358,10 @@ function HomeSessionGroupHeader(props: { title: string; onNewSession?: () => voi
 }
 
 function HomeSessionRow(props: { record: HomeSessionRecord; openSession: (session: Session) => void }) {
-  const globalSync = useGlobalSync()
+  const serverSync = useServerSync()
   const notification = useNotification()
   const permission = usePermission()
-  const [sessionStore] = globalSync.child(props.record.session.directory, { bootstrap: false })
+  const [sessionStore] = serverSync.child(props.record.session.directory, { bootstrap: false })
   const title = createMemo(() => sessionTitle(props.record.session.title) || props.record.session.id)
   const unseenCount = createMemo(() => notification.session.unseenCount(props.record.session.id))
   const hasError = createMemo(() => notification.session.unseenHasError(props.record.session.id))
@@ -459,7 +459,7 @@ function groupSessions(records: HomeSessionRecord[], language: ReturnType<typeof
 }
 
 function LegacyHome() {
-  const sync = useGlobalSync()
+  const sync = useServerSync()
   const layout = useLayout()
   const platform = usePlatform()
   const dialog = useDialog()

+ 43 - 43
packages/app/src/pages/layout.tsx

@@ -16,7 +16,7 @@ import { makeEventListener } from "@solid-primitives/event-listener"
 import { useLocation, useNavigate, useParams } from "@solidjs/router"
 import { useQuery } from "@tanstack/solid-query"
 import { useLayout, LocalProject } from "@/context/layout"
-import { useGlobalSync } from "@/context/global-sync"
+import { useServerSync } from "@/context/server-sync"
 import { Persist, persisted } from "@/utils/persist"
 import { base64Encode } from "@opencode-ai/core/util/encode"
 import { decode64 } from "@/utils/base64"
@@ -35,7 +35,7 @@ import { DragDropProvider, DragDropSensors, DragOverlay, SortableProvider, close
 import type { DragEvent } from "@thisbeyond/solid-dnd"
 import { useProviders } from "@/hooks/use-providers"
 import { showToast, Toast, toaster } from "@opencode-ai/ui/toast"
-import { useGlobalSDK } from "@/context/global-sdk"
+import { useServerSDK } from "@/context/server-sdk"
 import { clearWorkspaceTerminals, getTerminalServerScope } from "@/context/terminal"
 import { dropSessionCaches, pickSessionCacheEvictions } from "@/context/global-sync/session-cache"
 import {
@@ -113,8 +113,8 @@ export default function Layout(props: ParentProps) {
   let dialogDead = false
 
   const params = useParams()
-  const globalSDK = useGlobalSDK()
-  const globalSync = useGlobalSync()
+  const serverSDK = useServerSDK()
+  const serverSync = useServerSync()
   const layout = useLayout()
   const layoutReady = createMemo(() => layout.ready())
   const platform = usePlatform()
@@ -136,7 +136,7 @@ export default function Layout(props: ParentProps) {
     if (!slug) return { slug, dir: "" }
     const dir = decode64(slug)
     if (!dir) return { slug, dir: "" }
-    const store = globalSync.peek(dir, { bootstrap: false })
+    const store = serverSync.peek(dir, { bootstrap: false })
     return {
       slug,
       store,
@@ -226,7 +226,7 @@ export default function Layout(props: ParentProps) {
     active: () => state.hoverProject,
     el: () => state.nav?.querySelector<HTMLElement>("[data-component='sidebar-rail']") ?? state.nav,
     onActivate: (directory) => {
-      globalSync.child(directory)
+      serverSync.child(directory)
       setState("hoverProject", directory)
     },
   })
@@ -410,7 +410,7 @@ export default function Layout(props: ParentProps) {
         alertedAtBySession.delete(sessionKey)
       }
 
-      const unsub = globalSDK.event.listen((e) => {
+      const unsub = serverSDK.event.listen((e) => {
         if (e.details?.type === "worktree.ready") {
           setBusy(e.name, false)
           WorktreeState.ready(e.name)
@@ -444,7 +444,7 @@ export default function Layout(props: ParentProps) {
         const props = e.details.properties
         if (e.details.type === "permission.asked" && permission.autoResponds(e.details.properties, directory)) return
 
-        const [store] = globalSync.child(directory, { bootstrap: false })
+        const [store] = serverSync.child(directory, { bootstrap: false })
         const session = store.session.find((s) => s.id === props.sessionID)
         const sessionKey = `${directory}:${props.sessionID}`
 
@@ -507,7 +507,7 @@ export default function Layout(props: ParentProps) {
         if (!currentDir() || !currentSession) return
         const sessionKey = `${currentDir()}:${currentSession}`
         dismissSessionAlert(sessionKey)
-        const [store] = globalSync.child(currentDir(), { bootstrap: false })
+        const [store] = serverSync.child(currentDir(), { bootstrap: false })
         const childSessions = store.session.filter((s) => s.parentID === currentSession)
         for (const child of childSessions) {
           dismissSessionAlert(`${currentDir()}:${child.id}`)
@@ -545,11 +545,11 @@ export default function Layout(props: ParentProps) {
     const direct = projects.find((p) => pathKey(p.worktree) === key)
     if (direct) return direct
 
-    const [child] = globalSync.child(directory, { bootstrap: false })
+    const [child] = serverSync.child(directory, { bootstrap: false })
     const id = child.project
     if (!id) return
 
-    const meta = globalSync.data.project.find((p) => p.id === id)
+    const meta = serverSync.data.project.find((p) => p.id === id)
     const root = meta?.worktree
     if (!root) return
 
@@ -640,7 +640,7 @@ export default function Layout(props: ParentProps) {
 
     const result: Session[] = []
     for (const dir of dirs) {
-      const [dirStore] = globalSync.child(dir, { bootstrap: true })
+      const [dirStore] = serverSync.child(dir, { bootstrap: true })
       const dirSessions = sortedRootSessions(dirStore, now)
       result.push(...dirSessions)
     }
@@ -692,7 +692,7 @@ export default function Layout(props: ParentProps) {
 
   createEffect(() => {
     route()
-    globalSDK.url
+    serverSDK.url
 
     prefetchToken.value += 1
     clearSessionPrefetchInflight()
@@ -739,13 +739,13 @@ export default function Layout(props: ParentProps) {
   }
 
   async function prefetchMessages(directory: string, sessionID: string, token: number) {
-    const [store, setStore] = globalSync.child(directory, { bootstrap: false })
+    const [store, setStore] = serverSync.child(directory, { bootstrap: false })
 
     return runSessionPrefetch({
       directory,
       sessionID,
       task: (rev) =>
-        retry(() => globalSDK.client.session.messages({ directory, sessionID, limit: prefetchChunk }))
+        retry(() => serverSDK.client.session.messages({ directory, sessionID, limit: prefetchChunk }))
           .then((messages) => {
             if (prefetchToken.value !== token) return
             if (!isSessionPrefetchCurrent(directory, sessionID, rev)) return
@@ -765,7 +765,7 @@ export default function Layout(props: ParentProps) {
             if (stale.length > 0) {
               clearSessionPrefetch(directory, stale)
               for (const id of stale) {
-                globalSync.todo.set(id, undefined)
+                serverSync.todo.set(id, undefined)
               }
             }
 
@@ -830,7 +830,7 @@ export default function Layout(props: ParentProps) {
     const directory = session.directory
     if (!directory) return
 
-    const [store] = globalSync.child(directory, { bootstrap: false })
+    const [store] = serverSync.child(directory, { bootstrap: false })
     const cached = untrack(() => {
       const info = getSessionPrefetch(directory, session.id)
       return shouldSkipSessionPrefetch({
@@ -935,7 +935,7 @@ export default function Layout(props: ParentProps) {
     if (!target) return
 
     // warm up child store to prevent flicker
-    globalSync.child(target.worktree)
+    serverSync.child(target.worktree)
     void openProject(target.worktree)
   }
 
@@ -944,7 +944,7 @@ export default function Layout(props: ParentProps) {
     const target = projects[index]
     if (!target) return
 
-    globalSync.child(target.worktree)
+    serverSync.child(target.worktree)
     void openProject(target.worktree)
   }
 
@@ -973,12 +973,12 @@ export default function Layout(props: ParentProps) {
   }
 
   async function archiveSession(session: Session) {
-    const [store, setStore] = globalSync.child(session.directory)
+    const [store, setStore] = serverSync.child(session.directory)
     const sessions = store.session ?? []
     const index = sessions.findIndex((s) => s.id === session.id)
     const nextSession = sessions[index + 1] ?? sessions[index - 1]
 
-    await globalSDK.client.session.update({
+    await serverSDK.client.session.update({
       directory: session.directory,
       sessionID: session.id,
       time: { archived: Date.now() },
@@ -1246,11 +1246,11 @@ export default function Layout(props: ParentProps) {
     )
     if (known) return known[0]
 
-    const [child] = globalSync.child(directory, { bootstrap: false })
+    const [child] = serverSync.child(directory, { bootstrap: false })
     const id = child.project
     if (!id) return directory
 
-    const meta = globalSync.data.project.find((item) => item.id === id)
+    const meta = serverSync.data.project.find((item) => item.id === id)
     return meta?.worktree ?? directory
   }
 
@@ -1298,7 +1298,7 @@ export default function Layout(props: ParentProps) {
     }
     const refreshDirs = async (target?: string) => {
       if (!target || target === root || canOpen(target)) return canOpen(target)
-      const listed = await globalSDK.client.worktree
+      const listed = await serverSDK.client.worktree
         .list({ directory: root })
         .then((x) => x.data ?? [])
         .catch(() => [] as string[])
@@ -1307,13 +1307,13 @@ export default function Layout(props: ParentProps) {
     }
     const openSession = async (target: { directory: string; id: string }) => {
       if (!canOpen(target.directory)) return false
-      const [data] = globalSync.child(target.directory, { bootstrap: false })
+      const [data] = serverSync.child(target.directory, { bootstrap: false })
       if (data.session.some((item) => item.id === target.id)) {
         setStore("lastProjectSession", root, { directory: target.directory, id: target.id, at: Date.now() })
         navigateWithSidebarReset(`/${base64Encode(target.directory)}/session/${target.id}`)
         return true
       }
-      const resolved = await globalSDK.client.session
+      const resolved = await serverSDK.client.session
         .get({ sessionID: target.id })
         .then((x) => x.data)
         .catch(() => undefined)
@@ -1333,7 +1333,7 @@ export default function Layout(props: ParentProps) {
     }
 
     const latest = latestRootSession(
-      dirs.map((item) => globalSync.child(item, { bootstrap: false })[0]),
+      dirs.map((item) => serverSync.child(item, { bootstrap: false })[0]),
       Date.now(),
     )
     if (latest && (await openSession(latest))) {
@@ -1344,7 +1344,7 @@ export default function Layout(props: ParentProps) {
       await Promise.all(
         dirs.map(async (item) => ({
           path: { directory: item },
-          session: await globalSDK.client.session
+          session: await serverSDK.client.session
             .list({ directory: item })
             .then((x) => x.data ?? [])
             .catch(() => []),
@@ -1405,11 +1405,11 @@ export default function Layout(props: ParentProps) {
     const name = next === getFilename(project.worktree) ? "" : next
 
     if (project.id && project.id !== "global") {
-      await globalSDK.client.project.update({ projectID: project.id, directory: project.worktree, name })
+      await serverSDK.client.project.update({ projectID: project.id, directory: project.worktree, name })
       return
     }
 
-    globalSync.project.meta(project.worktree, { name })
+    serverSync.project.meta(project.worktree, { name })
   }
 
   const renameWorkspace = (directory: string, next: string, projectId?: string, branch?: string) => {
@@ -1506,7 +1506,7 @@ export default function Layout(props: ParentProps) {
 
     setBusy(directory, true)
 
-    const result = await globalSDK.client.worktree
+    const result = await serverSDK.client.worktree
       .remove({ directory: root, worktreeRemoveInput: { directory } })
       .then((x) => x.data)
       .catch((err) => {
@@ -1525,7 +1525,7 @@ export default function Layout(props: ParentProps) {
       clearLastProjectSession(root)
     }
 
-    globalSync.set(
+    serverSync.set(
       "project",
       produce((draft) => {
         const project = draft.find((item) => item.worktree === root)
@@ -1564,7 +1564,7 @@ export default function Layout(props: ParentProps) {
     })
     const dismiss = () => toaster.dismiss(progress)
 
-    const sessions: Session[] = await globalSDK.client.session
+    const sessions: Session[] = await serverSDK.client.session
       .list({ directory })
       .then((x) => x.data ?? [])
       .catch(() => [])
@@ -1575,9 +1575,9 @@ export default function Layout(props: ParentProps) {
       platform,
       getTerminalServerScope(server.current, server.key),
     )
-    await globalSDK.client.instance.dispose({ directory }).catch(() => undefined)
+    await serverSDK.client.instance.dispose({ directory }).catch(() => undefined)
 
-    const result = await globalSDK.client.worktree
+    const result = await serverSDK.client.worktree
       .reset({ directory: root, worktreeResetInput: { directory } })
       .then((x) => x.data)
       .catch((err) => {
@@ -1599,7 +1599,7 @@ export default function Layout(props: ParentProps) {
       sessions
         .filter((session) => session.time.archived === undefined)
         .map((session) =>
-          globalSDK.client.session
+          serverSDK.client.session
             .update({
               sessionID: session.id,
               directory: session.directory,
@@ -1640,7 +1640,7 @@ export default function Layout(props: ParentProps) {
     })
 
     onMount(() => {
-      globalSDK.client.file
+      serverSDK.client.file
         .status({ directory: props.directory })
         .then((x) => {
           const files = x.data ?? []
@@ -1699,7 +1699,7 @@ export default function Layout(props: ParentProps) {
     })
 
     const refresh = async () => {
-      const sessions = await globalSDK.client.session
+      const sessions = await serverSDK.client.session
         .list({ directory: props.directory })
         .then((x) => x.data ?? [])
         .catch(() => [])
@@ -1708,7 +1708,7 @@ export default function Layout(props: ParentProps) {
     }
 
     onMount(() => {
-      globalSDK.client.file
+      serverSDK.client.file
         .status({ directory: props.directory })
         .then((x) => {
           const files = x.data ?? []
@@ -1842,7 +1842,7 @@ export default function Layout(props: ParentProps) {
         const next = new Set(dirs)
         for (const directory of next) {
           if (loadedSessionDirs.has(directory)) continue
-          void globalSync.project.loadSessions(directory)
+          void serverSync.project.loadSessions(directory)
         }
 
         loadedSessionDirs.clear()
@@ -1939,7 +1939,7 @@ export default function Layout(props: ParentProps) {
 
   const createWorkspace = async (project: LocalProject) => {
     clearSidebarHoverState()
-    const created = await globalSDK.client.worktree
+    const created = await serverSDK.client.worktree
       .create({ directory: project.worktree })
       .then((x) => x.data)
       .catch((err) => {
@@ -1973,7 +1973,7 @@ export default function Layout(props: ParentProps) {
       return [created.directory, ...next]
     })
 
-    globalSync.child(created.directory)
+    serverSync.child(created.directory)
     navigateWithSidebarReset(`/${base64Encode(created.directory)}/session`)
   }
 
@@ -2078,7 +2078,7 @@ export default function Layout(props: ParentProps) {
       if (!item) return false
       return item.vcs === "git" || layout.sidebar.workspaces(item.worktree)()
     })
-    const homedir = createMemo(() => globalSync.data.path.home)
+    const homedir = createMemo(() => serverSync.data.path.home)
 
     return (
       <div

+ 5 - 5
packages/app/src/pages/layout/sidebar-items.tsx

@@ -7,7 +7,7 @@ import { Tooltip } from "@opencode-ai/ui/tooltip"
 import { getFilename } from "@opencode-ai/core/util/path"
 import { A, useParams } from "@solidjs/router"
 import { type Accessor, createMemo, For, type JSX, Match, Show, Switch } from "solid-js"
-import { useGlobalSync } from "@/context/global-sync"
+import { useServerSync } from "@/context/server-sync"
 import { useLanguage } from "@/context/language"
 import { getAvatarColors, type LocalProject, useLayout } from "@/context/layout"
 import { useNotification } from "@/context/notification"
@@ -23,7 +23,7 @@ export const ProjectIcon = (props: {
   notify?: boolean
   working?: boolean
 }): JSX.Element => {
-  const globalSync = useGlobalSync()
+  const serverSync = useServerSync()
   const notification = useNotification()
   const permission = usePermission()
   const dirs = createMemo(() => [props.project.worktree, ...(props.project.sandboxes ?? [])])
@@ -33,7 +33,7 @@ export const ProjectIcon = (props: {
   const hasError = createMemo(() => dirs().some((directory) => notification.project.unseenHasError(directory)))
   const hasPermissions = createMemo(() =>
     dirs().some((directory) => {
-      const [store] = globalSync.child(directory, { bootstrap: false })
+      const [store] = serverSync.child(directory, { bootstrap: false })
       return hasProjectPermissions(store.permission, (item) => !permission.autoResponds(item, directory))
     }),
   )
@@ -146,10 +146,10 @@ export const SessionItem = (props: SessionItemProps): JSX.Element => {
   const language = useLanguage()
   const notification = useNotification()
   const permission = usePermission()
-  const globalSync = useGlobalSync()
+  const serverSync = useServerSync()
   const unseenCount = createMemo(() => notification.session.unseenCount(props.session.id))
   const hasError = createMemo(() => notification.session.unseenHasError(props.session.id))
-  const [sessionStore] = globalSync.child(props.session.directory)
+  const [sessionStore] = serverSync.child(props.session.directory)
   const hasPermissions = createMemo(() => {
     return !!sessionPermissionRequest(sessionStore.session, sessionStore.permission, props.session.id, (item) => {
       return !permission.autoResponds(item, props.session.directory)

+ 6 - 6
packages/app/src/pages/layout/sidebar-project.tsx

@@ -7,7 +7,7 @@ import { HoverCard } from "@opencode-ai/ui/hover-card"
 import { Icon } from "@opencode-ai/ui/icon"
 import { createSortable } from "@thisbeyond/solid-dnd"
 import { useLayout, type LocalProject } from "@/context/layout"
-import { useGlobalSync } from "@/context/global-sync"
+import { useServerSync } from "@/context/server-sync"
 import { useLanguage } from "@/context/language"
 import { useNotification } from "@/context/notification"
 import { ProjectIcon, SessionItem, type SessionItemProps } from "./sidebar-items"
@@ -274,7 +274,7 @@ export const SortableProject = (props: {
   ctx: ProjectSidebarContext
   sortNow: Accessor<number>
 }): JSX.Element => {
-  const globalSync = useGlobalSync()
+  const serverSync = useServerSync()
   const language = useLanguage()
   const sortable = createSortable(props.project.worktree)
   const selected = createMemo(() => props.ctx.currentProject()?.worktree === props.project.worktree)
@@ -294,23 +294,23 @@ export const SortableProject = (props: {
   const hoverOpen = () => isHoverProject() && preview() && !selected() && !state.menu
 
   const label = (directory: string) => {
-    const [data] = globalSync.child(directory, { bootstrap: false })
+    const [data] = serverSync.child(directory, { bootstrap: false })
     const kind =
       directory === props.project.worktree ? language.t("workspace.type.local") : language.t("workspace.type.sandbox")
     const name = props.ctx.workspaceLabel(directory, data.vcs?.branch, props.project.id)
     return `${kind} : ${name}`
   }
 
-  const projectStore = createMemo(() => globalSync.child(props.project.worktree, { bootstrap: false })[0])
+  const projectStore = createMemo(() => serverSync.child(props.project.worktree, { bootstrap: false })[0])
   const isWorking = createMemo(() =>
     dirs().some((directory) => {
-      const [store] = globalSync.child(directory, { bootstrap: false })
+      const [store] = serverSync.child(directory, { bootstrap: false })
       return Object.keys(store.session_status).some((id) => store.session_working(id))
     }),
   )
   const projectSessions = createMemo(() => sortedRootSessions(projectStore(), props.sortNow()))
   const workspaceSessions = (directory: string) => {
-    const [data] = globalSync.child(directory, { bootstrap: false })
+    const [data] = serverSync.child(directory, { bootstrap: false })
     return sortedRootSessions(data, props.sortNow())
   }
   const tile = () => (

+ 10 - 10
packages/app/src/pages/layout/sidebar-workspace.tsx

@@ -14,7 +14,7 @@ import { Spinner } from "@opencode-ai/ui/spinner"
 import { Tooltip } from "@opencode-ai/ui/tooltip"
 import { type Session } from "@opencode-ai/sdk/v2/client"
 import { type LocalProject } from "@/context/layout"
-import { useGlobalSync, useQueryOptions } from "@/context/global-sync"
+import { useServerSync, useQueryOptions } from "@/context/server-sync"
 import { useLanguage } from "@/context/language"
 import { pathKey } from "@/utils/path-key"
 import { NewSessionItem, SessionItem, SessionSkeleton } from "./sidebar-items"
@@ -60,7 +60,7 @@ export const WorkspaceDragOverlay = (props: {
   activeWorkspace: Accessor<string | undefined>
   workspaceLabel: (directory: string, branch?: string, projectId?: string) => string
 }): JSX.Element => {
-  const globalSync = useGlobalSync()
+  const serverSync = useServerSync()
   const language = useLanguage()
   const label = createMemo(() => {
     const project = props.sidebarProject()
@@ -68,7 +68,7 @@ export const WorkspaceDragOverlay = (props: {
     const directory = props.activeWorkspace()
     if (!directory) return
 
-    const [workspaceStore] = globalSync.child(directory, { bootstrap: false })
+    const [workspaceStore] = serverSync.child(directory, { bootstrap: false })
     const kind =
       directory === project.worktree ? language.t("workspace.type.local") : language.t("workspace.type.sandbox")
     const name = props.workspaceLabel(directory, workspaceStore.vcs?.branch, project.id)
@@ -299,11 +299,11 @@ export const SortableWorkspace = (props: {
 }): JSX.Element => {
   const navigate = useNavigate()
   const params = useParams()
-  const globalSync = useGlobalSync()
+  const serverSync = useServerSync()
   const queryOptions = useQueryOptions()
   const language = useLanguage()
   const sortable = createSortable(props.directory)
-  const [workspaceStore, setWorkspaceStore] = globalSync.child(props.directory, { bootstrap: false })
+  const [workspaceStore, setWorkspaceStore] = serverSync.child(props.directory, { bootstrap: false })
   const [menu, setMenu] = createStore({
     open: false,
     pendingRename: false,
@@ -328,7 +328,7 @@ export const SortableWorkspace = (props: {
   const showNew = createMemo(() => !loading() && (touch() || count() === 0 || (active() && !params.id)))
   const loadMore = async () => {
     setWorkspaceStore("limit", (limit) => (limit ?? 0) + 5)
-    await globalSync.project.loadSessions(props.directory)
+    await serverSync.project.loadSessions(props.directory)
   }
 
   const workspaceEditActive = createMemo(() => props.ctx.editorOpen(`workspace:${props.directory}`))
@@ -357,7 +357,7 @@ export const SortableWorkspace = (props: {
 
   createEffect(() => {
     if (!boot()) return
-    globalSync.child(props.directory, { bootstrap: true })
+    serverSync.child(props.directory, { bootstrap: true })
   })
 
   return (
@@ -446,11 +446,11 @@ export const LocalWorkspace = (props: {
   sortNow: Accessor<number>
   mobile?: boolean
 }): JSX.Element => {
-  const globalSync = useGlobalSync()
+  const serverSync = useServerSync()
   const queryOptions = useQueryOptions()
   const language = useLanguage()
   const workspace = createMemo(() => {
-    const [store, setStore] = globalSync.child(props.project.worktree)
+    const [store, setStore] = serverSync.child(props.project.worktree)
     return { store, setStore }
   })
   const slug = createMemo(() => base64Encode(props.project.worktree))
@@ -461,7 +461,7 @@ export const LocalWorkspace = (props: {
   const loading = () => fetching() > 0 && count() === 0
   const loadMore = async () => {
     workspace().setStore("limit", (limit) => (limit ?? 0) + 5)
-    await globalSync.project.loadSessions(props.project.worktree)
+    await serverSync.project.loadSessions(props.project.worktree)
   }
 
   return (

+ 8 - 8
packages/app/src/pages/session.tsx

@@ -34,7 +34,7 @@ import { useLocation, useSearchParams } from "@solidjs/router"
 import { NewSessionDesignView, NewSessionView, SessionHeader } from "@/components/session"
 import { useComments } from "@/context/comments"
 import { getSessionPrefetch, SESSION_PREFETCH_TTL } from "@/context/global-sync/session-prefetch"
-import { useGlobalSync } from "@/context/global-sync"
+import { useServerSync } from "@/context/server-sync"
 import { useLanguage } from "@/context/language"
 import { useLayout } from "@/context/layout"
 import { usePrompt } from "@/context/prompt"
@@ -182,7 +182,7 @@ function createSessionHistoryLoader(input: SessionHistoryWindowInput) {
 }
 
 export default function Page() {
-  const globalSync = useGlobalSync()
+  const serverSync = useServerSync()
   const layout = useLayout()
   const local = useLocal()
   const file = useFile()
@@ -560,11 +560,11 @@ export default function Page() {
   }
 
   function upsert(next: Project) {
-    const list = globalSync.data.project
+    const list = serverSync.data.project
     sync.set("project", next.id)
     const idx = list.findIndex((item) => item.id === next.id)
     if (idx >= 0) {
-      globalSync.set(
+      serverSync.set(
         "project",
         list.map((item, i) => (i === idx ? { ...item, ...next } : item)),
       )
@@ -572,10 +572,10 @@ export default function Page() {
     }
     const at = list.findIndex((item) => item.id > next.id)
     if (at >= 0) {
-      globalSync.set("project", [...list.slice(0, at), next, ...list.slice(at)])
+      serverSync.set("project", [...list.slice(0, at), next, ...list.slice(at)])
       return
     }
-    globalSync.set("project", [...list, next])
+    serverSync.set("project", [...list, next])
   }
 
   const gitMutation = useMutation(() => ({
@@ -673,7 +673,7 @@ export default function Page() {
         todoTimer = undefined
         if (!id) return
         if (status === "idle" && !blocked) return
-        const cached = untrack(() => sync.data.todo[id] !== undefined || globalSync.data.session_todo[id] !== undefined)
+        const cached = untrack(() => sync.data.todo[id] !== undefined || serverSync.data.session_todo[id] !== undefined)
 
         todoFrame = requestAnimationFrame(() => {
           todoFrame = undefined
@@ -1386,7 +1386,7 @@ export default function Page() {
       const ok = await sendFollowupDraft({
         client: sdk.client,
         sync,
-        globalSync,
+        serverSync,
         draft: item,
         optimisticBusy: item.sessionDirectory === sdk.directory,
       }).catch((err) => {

+ 4 - 4
packages/app/src/pages/session/composer/session-composer-state.ts

@@ -3,7 +3,7 @@ import { createStore } from "solid-js/store"
 import type { PermissionRequest, QuestionRequest, Todo } from "@opencode-ai/sdk/v2"
 import { useParams } from "@solidjs/router"
 import { showToast } from "@opencode-ai/ui/toast"
-import { useGlobalSync } from "@/context/global-sync"
+import { useServerSync } from "@/context/server-sync"
 import { useLanguage } from "@/context/language"
 import { usePermission } from "@/context/permission"
 import { useSDK } from "@/context/sdk"
@@ -27,7 +27,7 @@ export function createSessionComposerState(options?: { closeMs?: number | (() =>
   const params = useParams()
   const sdk = useSDK()
   const sync = useSync()
-  const globalSync = useGlobalSync()
+  const serverSync = useServerSync()
   const language = useLanguage()
   const permission = usePermission()
 
@@ -50,7 +50,7 @@ export function createSessionComposerState(options?: { closeMs?: number | (() =>
   const todos = createMemo((): Todo[] => {
     const id = params.id
     if (!id) return []
-    return globalSync.data.session_todo[id] ?? []
+    return serverSync.data.session_todo[id] ?? []
   })
 
   const done = createMemo(
@@ -111,7 +111,7 @@ export function createSessionComposerState(options?: { closeMs?: number | (() =>
   const clear = () => {
     const id = params.id
     if (!id) return
-    globalSync.todo.set(id, [])
+    serverSync.todo.set(id, [])
     sync.set("todo", id, [])
   }
 

+ 4 - 4
packages/app/src/pages/session/message-timeline.tsx

@@ -48,7 +48,7 @@ import { useDialog } from "@opencode-ai/ui/context/dialog"
 import { createResizeObserver } from "@solid-primitives/resize-observer"
 import { useLanguage } from "@/context/language"
 import { useSessionKey } from "@/pages/session/session-layout"
-import { useGlobalSDK } from "@/context/global-sdk"
+import { useServerSDK } from "@/context/server-sdk"
 import { usePlatform } from "@/context/platform"
 import { useSettings } from "@/context/settings"
 import { useSDK } from "@/context/sdk"
@@ -273,7 +273,7 @@ export function MessageTimeline(props: {
   let touchGesture: number | undefined
 
   const navigate = useNavigate()
-  const globalSDK = useGlobalSDK()
+  const serverSDK = useServerSDK()
   const sdk = useSDK()
   const sync = useSync()
   const settings = useSettings()
@@ -704,14 +704,14 @@ export function MessageTimeline(props: {
   }
 
   const shareMutation = useMutation(() => ({
-    mutationFn: (id: string) => globalSDK.client.session.share({ sessionID: id, directory: sdk.directory }),
+    mutationFn: (id: string) => serverSDK.client.session.share({ sessionID: id, directory: sdk.directory }),
     onError: (err) => {
       console.error("Failed to share session", err)
     },
   }))
 
   const unshareMutation = useMutation(() => ({
-    mutationFn: (id: string) => globalSDK.client.session.unshare({ sessionID: id, directory: sdk.directory }),
+    mutationFn: (id: string) => serverSDK.client.session.unshare({ sessionID: id, directory: sdk.directory }),
     onError: (err) => {
       console.error("Failed to unshare session", err)
     },

+ 1 - 1
packages/storybook/.storybook/mocks/app/context/global-sync.ts

@@ -24,7 +24,7 @@ const [store, setStore] = createStore({
   config: { permission: {} },
 })
 
-export function useGlobalSync() {
+export function useServerSync() {
   return {
     data: {
       provider,

+ 2 - 2
packages/ui/src/components/todo-panel-motion.stories.tsx

@@ -2,7 +2,7 @@
 import { createEffect, createMemo, onCleanup } from "solid-js"
 import { createStore } from "solid-js/store"
 import type { Todo } from "@opencode-ai/sdk/v2"
-import { useGlobalSync } from "@/context/global-sync"
+import { useServerSync } from "@/context/global-sync"
 import { SessionComposerRegion, createSessionComposerState } from "@/pages/session/composer"
 
 export default {
@@ -129,7 +129,7 @@ const css = `
 
 export const Playground = {
   render: () => {
-    const global = useGlobalSync()
+    const global = useServerSync()
     const [cfg, setCfg] = createStore({
       open: true,
       step: 1,