summaryrefslogtreecommitdiffhomepage
path: root/packages/app/src/context/global-sync
diff options
context:
space:
mode:
authorBrendan Allan <[email protected]>2026-04-20 13:17:37 +0800
committerGitHub <[email protected]>2026-04-20 05:17:37 +0000
commit687b7588820df02dfe7397a399f213f394aa6b09 (patch)
tree0497e08000939606f41b9a7577924d9376ecba7c /packages/app/src/context/global-sync
parent84e322b0fdb178ad420f3f6507a22c0da590f524 (diff)
downloadopencode-687b7588820df02dfe7397a399f213f394aa6b09.tar.gz
opencode-687b7588820df02dfe7397a399f213f394aa6b09.zip
app: better loading (#23489)
Diffstat (limited to 'packages/app/src/context/global-sync')
-rw-r--r--packages/app/src/context/global-sync/bootstrap.ts144
-rw-r--r--packages/app/src/context/global-sync/child-store.ts10
2 files changed, 88 insertions, 66 deletions
diff --git a/packages/app/src/context/global-sync/bootstrap.ts b/packages/app/src/context/global-sync/bootstrap.ts
index 17fe726f9..be789a5e5 100644
--- a/packages/app/src/context/global-sync/bootstrap.ts
+++ b/packages/app/src/context/global-sync/bootstrap.ts
@@ -19,7 +19,6 @@ import type { State, VcsCache } from "./types"
import { cmp, normalizeAgentList, normalizeProviderList } from "./utils"
import { formatServerError } from "@/utils/server-errors"
import { QueryClient, queryOptions, skipToken } from "@tanstack/solid-query"
-import { loadSessionsQuery } from "../global-sync"
type GlobalStore = {
ready: boolean
@@ -82,6 +81,9 @@ export async function bootstrapGlobal(input: {
input.setGlobalStore("config", x.data!)
}),
),
+ ]
+
+ const slow = [
() =>
input.queryClient.fetchQuery({
...loadProvidersQuery(null),
@@ -93,9 +95,6 @@ export async function bootstrapGlobal(input: {
}),
),
}),
- ]
-
- const slow = [
() =>
retry(() =>
input.globalSDK.path.get().then((x) => {
@@ -183,8 +182,43 @@ function warmSessions(input: {
export const loadProvidersQuery = (directory: string | null) =>
queryOptions<null>({ queryKey: [directory, "providers"], queryFn: skipToken })
-export const loadAgentsQuery = (directory: string | null) =>
- queryOptions<null>({ queryKey: [directory, "agents"], queryFn: skipToken })
+export const loadAgentsQuery = (
+ directory: string | null,
+ sdk?: OpencodeClient,
+ transform?: (x: Awaited<ReturnType<OpencodeClient["app"]["agents"]>>) => void,
+) =>
+ queryOptions<null>({
+ queryKey: [directory, "agents"],
+ queryFn:
+ sdk && transform
+ ? () =>
+ retry(() =>
+ sdk.app
+ .agents()
+ .then(transform)
+ .then(() => null),
+ )
+ : skipToken,
+ })
+
+export const loadPathQuery = (
+ directory: string | null,
+ sdk?: OpencodeClient,
+ transform?: (x: Awaited<ReturnType<OpencodeClient["path"]["get"]>>) => void,
+) =>
+ queryOptions<Path>({
+ queryKey: [directory, "path"],
+ queryFn:
+ sdk && transform
+ ? () =>
+ retry(() =>
+ sdk.path.get().then(async (x) => {
+ transform(x)
+ return x.data!
+ }),
+ )
+ : skipToken,
+ })
export async function bootstrapDirectory(input: {
directory: string
@@ -222,45 +256,27 @@ export async function bootstrapDirectory(input: {
input.setStore("lsp", [])
if (loading) input.setStore("status", "partial")
- const fast = [() => Promise.resolve(input.loadSessions(input.directory))]
-
- const errs = errors(await runAll(fast))
- if (errs.length > 0) {
- console.error("Failed to bootstrap instance", errs[0])
- const project = getFilename(input.directory)
- showToast({
- variant: "error",
- title: input.translate("toast.project.reloadFailed.title", { project }),
- description: formatServerError(errs[0], input.translate),
- })
- }
-
+ const rev = (providerRev.get(input.directory) ?? 0) + 1
+ providerRev.set(input.directory, rev)
;(async () => {
const slow = [
+ () => Promise.resolve(input.loadSessions(input.directory)),
() =>
- input.queryClient.ensureQueryData({
- ...loadAgentsQuery(input.directory),
- queryFn: () =>
- retry(() => input.sdk.app.agents().then((x) => input.setStore("agent", normalizeAgentList(x.data)))).then(
- () => null,
- ),
- }),
+ input.queryClient.ensureQueryData(
+ loadAgentsQuery(input.directory, input.sdk, (x) => input.setStore("agent", normalizeAgentList(x.data))),
+ ),
() => retry(() => input.sdk.config.get().then((x) => input.setStore("config", x.data!))),
() => retry(() => input.sdk.session.status().then((x) => input.setStore("session_status", x.data!))),
- () =>
- seededProject
- ? Promise.resolve()
- : retry(() => input.sdk.project.current()).then((x) => input.setStore("project", x.data!.id)),
- () =>
- seededPath
- ? Promise.resolve()
- : retry(() =>
- input.sdk.path.get().then((x) => {
- input.setStore("path", x.data!)
- const next = projectID(x.data?.directory ?? input.directory, input.global.project)
- if (next) input.setStore("project", next)
- }),
- ),
+ !seededProject &&
+ (() => retry(() => input.sdk.project.current()).then((x) => input.setStore("project", x.data!.id))),
+ !seededPath &&
+ (() =>
+ input.queryClient.ensureQueryData(
+ loadPathQuery(input.directory, input.sdk, (x) => {
+ const next = projectID(x.data?.directory ?? input.directory, input.global.project)
+ if (next) input.setStore("project", next)
+ }),
+ )),
() =>
retry(() =>
input.sdk.vcs.get().then((x) => {
@@ -330,7 +346,28 @@ export async function bootstrapDirectory(input: {
input.setStore("mcp_ready", true)
}),
),
- ]
+ () =>
+ input.queryClient.ensureQueryData({
+ ...loadProvidersQuery(input.directory),
+ queryFn: () =>
+ retry(() => input.sdk.provider.list())
+ .then((x) => {
+ if (providerRev.get(input.directory) !== rev) return
+ input.setStore("provider", normalizeProviderList(x.data!))
+ input.setStore("provider_ready", true)
+ })
+ .catch((err) => {
+ if (providerRev.get(input.directory) !== rev) console.error("Failed to refresh provider list", err)
+ const project = getFilename(input.directory)
+ showToast({
+ variant: "error",
+ title: input.translate("toast.project.reloadFailed.title", { project }),
+ description: formatServerError(err, input.translate),
+ })
+ })
+ .then(() => null),
+ }),
+ ].filter(Boolean) as (() => Promise<any>)[]
await waitForPaint()
const slowErrs = errors(await runAll(slow))
@@ -344,29 +381,6 @@ export async function bootstrapDirectory(input: {
})
}
- if (loading && errs.length === 0 && slowErrs.length === 0) input.setStore("status", "complete")
-
- const rev = (providerRev.get(input.directory) ?? 0) + 1
- providerRev.set(input.directory, rev)
- void input.queryClient.ensureQueryData({
- ...loadSessionsQuery(input.directory),
- queryFn: () =>
- retry(() => input.sdk.provider.list())
- .then((x) => {
- if (providerRev.get(input.directory) !== rev) return
- input.setStore("provider", normalizeProviderList(x.data!))
- input.setStore("provider_ready", true)
- })
- .catch((err) => {
- if (providerRev.get(input.directory) !== rev) console.error("Failed to refresh provider list", err)
- const project = getFilename(input.directory)
- showToast({
- variant: "error",
- title: input.translate("toast.project.reloadFailed.title", { project }),
- description: formatServerError(err, input.translate),
- })
- })
- .then(() => null),
- })
+ if (loading && slowErrs.length === 0) input.setStore("status", "complete")
})()
}
diff --git a/packages/app/src/context/global-sync/child-store.ts b/packages/app/src/context/global-sync/child-store.ts
index 3fe67e4fb..c92d2ae57 100644
--- a/packages/app/src/context/global-sync/child-store.ts
+++ b/packages/app/src/context/global-sync/child-store.ts
@@ -14,6 +14,8 @@ import {
type VcsCache,
} from "./types"
import { canDisposeDirectory, pickDirectoriesToEvict } from "./eviction"
+import { useQuery } from "@tanstack/solid-query"
+import { loadPathQuery } from "./bootstrap"
export function createChildStoreManager(input: {
owner: Owner
@@ -156,6 +158,8 @@ export function createChildStoreManager(input: {
createRoot((dispose) => {
const initialMeta = meta[0].value
const initialIcon = icon[0].value
+
+ const pathQuery = useQuery(() => loadPathQuery(directory))
const child = createStore<State>({
project: "",
projectMeta: initialMeta,
@@ -163,7 +167,11 @@ export function createChildStoreManager(input: {
provider_ready: false,
provider: { all: [], connected: [], default: {} },
config: {},
- path: { state: "", config: "", worktree: "", directory: "", home: "" },
+ get path() {
+ if (pathQuery.isLoading || !pathQuery.data)
+ return { state: "", config: "", worktree: "", directory: "", home: "" }
+ return pathQuery.data
+ },
status: "loading" as const,
agent: [],
command: [],