mirror of
https://github.com/anomalyco/opencode.git
synced 2026-05-06 00:12:11 +00:00
feat(app): configure TanStack Query client with default options
Add defaultOptions to QueryClient to disable automatic refetching: - refetchOnReconnect: false - refetchOnMount: false - refetchOnWindowFocus: false
This commit is contained in:
parent
a4bd88ab97
commit
acf3b00790
6 changed files with 251 additions and 231 deletions
|
|
@ -82,7 +82,15 @@ declare global {
|
|||
}
|
||||
|
||||
function QueryProvider(props: ParentProps) {
|
||||
const client = new QueryClient()
|
||||
const client = new QueryClient({
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
refetchOnReconnect: false,
|
||||
refetchOnMount: false,
|
||||
refetchOnWindowFocus: false,
|
||||
},
|
||||
},
|
||||
})
|
||||
return <QueryClientProvider client={client}>{props.children}</QueryClientProvider>
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ export const DialogSelectMcp: Component = () => {
|
|||
.status()
|
||||
.then((result) => {
|
||||
sync.set("mcp", result.data ?? {})
|
||||
sync.set("mcp_ready", true)
|
||||
// sync.set("mcp_ready", true)
|
||||
setState("done", true)
|
||||
})
|
||||
.catch((err) => {
|
||||
|
|
|
|||
|
|
@ -162,14 +162,6 @@ export function StatusPopoverBody(props: { shown: Accessor<boolean> }) {
|
|||
const dialog = useDialog()
|
||||
const language = useLanguage()
|
||||
const navigate = useNavigate()
|
||||
const sdk = useSDK()
|
||||
|
||||
const [load, setLoad] = createStore({
|
||||
lspDone: false,
|
||||
lspLoading: false,
|
||||
mcpDone: false,
|
||||
mcpLoading: false,
|
||||
})
|
||||
|
||||
const fail = (err: unknown) => {
|
||||
showToast({
|
||||
|
|
@ -181,40 +173,6 @@ export function StatusPopoverBody(props: { shown: Accessor<boolean> }) {
|
|||
|
||||
createEffect(() => {
|
||||
if (!props.shown()) return
|
||||
|
||||
if (!sync.data.mcp_ready && !load.mcpDone && !load.mcpLoading) {
|
||||
setLoad("mcpLoading", true)
|
||||
void sdk.client.mcp
|
||||
.status()
|
||||
.then((result) => {
|
||||
sync.set("mcp", result.data ?? {})
|
||||
sync.set("mcp_ready", true)
|
||||
})
|
||||
.catch((err) => {
|
||||
setLoad("mcpDone", true)
|
||||
fail(err)
|
||||
})
|
||||
.finally(() => {
|
||||
setLoad("mcpLoading", false)
|
||||
})
|
||||
}
|
||||
|
||||
if (!sync.data.lsp_ready && !load.lspDone && !load.lspLoading) {
|
||||
setLoad("lspLoading", true)
|
||||
void sdk.client.lsp
|
||||
.status()
|
||||
.then((result) => {
|
||||
sync.set("lsp", result.data ?? [])
|
||||
sync.set("lsp_ready", true)
|
||||
})
|
||||
.catch((err) => {
|
||||
setLoad("lspDone", true)
|
||||
fail(err)
|
||||
})
|
||||
.finally(() => {
|
||||
setLoad("lspLoading", false)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
let dialogRun = 0
|
||||
|
|
|
|||
|
|
@ -10,21 +10,30 @@ import type {
|
|||
import { showToast } from "@opencode-ai/ui/toast"
|
||||
import { getFilename } from "@opencode-ai/shared/util/path"
|
||||
import { batch, createContext, getOwner, onCleanup, onMount, type ParentProps, untrack, useContext } from "solid-js"
|
||||
import { createStore, produce, reconcile } from "solid-js/store"
|
||||
import { createStore, produce, reconcile, unwrap } from "solid-js/store"
|
||||
import { useLanguage } from "@/context/language"
|
||||
import { Persist, persisted } from "@/utils/persist"
|
||||
import type { InitError } from "../pages/error"
|
||||
import { useGlobalSDK } from "./global-sdk"
|
||||
import { bootstrapDirectory, bootstrapGlobal, clearProviderRev } from "./global-sync/bootstrap"
|
||||
import {
|
||||
bootstrapDirectory,
|
||||
bootstrapGlobal,
|
||||
clearProviderRev,
|
||||
loadGlobalConfigQuery,
|
||||
loadPathQuery,
|
||||
loadProjectsQuery,
|
||||
loadProvidersQuery,
|
||||
} from "./global-sync/bootstrap"
|
||||
import { createChildStoreManager } from "./global-sync/child-store"
|
||||
import { applyDirectoryEvent, applyGlobalEvent, cleanupDroppedSessionCaches } from "./global-sync/event-reducer"
|
||||
import { createRefreshQueue } from "./global-sync/queue"
|
||||
import { clearSessionPrefetchDirectory } from "./global-sync/session-prefetch"
|
||||
import { estimateRootSessionTotal, loadRootSessionsWithFallback } from "./global-sync/session-load"
|
||||
import { trimSessions } from "./global-sync/session-trim"
|
||||
import type { ProjectMeta } from "./global-sync/types"
|
||||
import { SESSION_RECENT_LIMIT } from "./global-sync/types"
|
||||
import { sanitizeProject } from "./global-sync/utils"
|
||||
import { formatServerError } from "@/utils/server-errors"
|
||||
import { queryOptions, skipToken, useQueryClient } from "@tanstack/solid-query"
|
||||
import { queryOptions, skipToken, useMutation, useQueries, useQuery, useQueryClient } from "@tanstack/solid-query"
|
||||
|
||||
type GlobalStore = {
|
||||
ready: boolean
|
||||
|
|
@ -43,6 +52,18 @@ type GlobalStore = {
|
|||
export const loadSessionsQuery = (directory: string) =>
|
||||
queryOptions<null>({ queryKey: [directory, "loadSessions"], queryFn: skipToken })
|
||||
|
||||
export const loadMcpQuery = (directory: string, sdk?: OpencodeClient) =>
|
||||
queryOptions({
|
||||
queryKey: [directory, "mcp"],
|
||||
queryFn: sdk ? () => sdk.mcp.status().then((r) => r.data ?? {}) : skipToken,
|
||||
})
|
||||
|
||||
export const loadLspQuery = (directory: string, sdk?: OpencodeClient) =>
|
||||
queryOptions({
|
||||
queryKey: [directory, "lsp"],
|
||||
queryFn: sdk ? () => sdk.lsp.status().then((r) => r.data ?? {}) : skipToken,
|
||||
})
|
||||
|
||||
function createGlobalSync() {
|
||||
const globalSDK = useGlobalSDK()
|
||||
const language = useLanguage()
|
||||
|
|
@ -54,30 +75,68 @@ function createGlobalSync() {
|
|||
const sessionLoads = new Map<string, Promise<void>>()
|
||||
const sessionMeta = new Map<string, { limit: number }>()
|
||||
|
||||
const [projectCache, setProjectCache, projectInit] = persisted(
|
||||
Persist.global("globalSync.project", ["globalSync.project.v1"]),
|
||||
createStore({ value: [] as Project[] }),
|
||||
)
|
||||
|
||||
const [configQuery, providerQuery, pathQuery] = useQueries(() => ({
|
||||
queries: [loadGlobalConfigQuery(), loadProvidersQuery(null), loadPathQuery(null), loadProjectsQuery()],
|
||||
}))
|
||||
|
||||
const [globalStore, setGlobalStore] = createStore<GlobalStore>({
|
||||
ready: false,
|
||||
path: { state: "", config: "", worktree: "", directory: "", home: "" },
|
||||
project: [],
|
||||
get ready() {
|
||||
return bootstrap.isPending
|
||||
},
|
||||
project: projectCache.value,
|
||||
session_todo: {},
|
||||
provider: { all: [], connected: [], default: {} },
|
||||
provider_auth: {},
|
||||
config: {},
|
||||
reload: undefined,
|
||||
get path() {
|
||||
const EMPTY = { state: "", config: "", worktree: "", directory: "", home: "" }
|
||||
if (pathQuery.isLoading) return EMPTY
|
||||
return pathQuery.data ?? EMPTY
|
||||
},
|
||||
get provider() {
|
||||
const EMPTY = { all: [], connected: [], default: {} }
|
||||
if (providerQuery.isLoading) return EMPTY
|
||||
return providerQuery.data ?? EMPTY
|
||||
},
|
||||
get config() {
|
||||
if (configQuery.isLoading) return {}
|
||||
return configQuery.data ?? {}
|
||||
},
|
||||
get reload() {
|
||||
return updateConfigMutation.isPending ? "pending" : undefined
|
||||
},
|
||||
})
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
let active = true
|
||||
let projectWritten = false
|
||||
let bootedAt = 0
|
||||
let bootingRoot = false
|
||||
let eventFrame: number | undefined
|
||||
let eventTimer: ReturnType<typeof setTimeout> | undefined
|
||||
|
||||
onCleanup(() => {
|
||||
active = false
|
||||
})
|
||||
onCleanup(() => {
|
||||
if (eventFrame !== undefined) cancelAnimationFrame(eventFrame)
|
||||
if (eventTimer !== undefined) clearTimeout(eventTimer)
|
||||
})
|
||||
|
||||
const cacheProjects = () => {
|
||||
setProjectCache(
|
||||
"value",
|
||||
untrack(() => globalStore.project.map(sanitizeProject)),
|
||||
)
|
||||
}
|
||||
|
||||
const setProjects = (next: Project[] | ((draft: Project[]) => Project[])) => {
|
||||
projectWritten = true
|
||||
setGlobalStore("project", next)
|
||||
cacheProjects()
|
||||
}
|
||||
|
||||
const setBootStore = ((...input: unknown[]) => {
|
||||
|
|
@ -88,6 +147,22 @@ function createGlobalSync() {
|
|||
return (setGlobalStore as (...args: unknown[]) => unknown)(...input)
|
||||
}) as typeof setGlobalStore
|
||||
|
||||
const bootstrap = useQuery(() => ({
|
||||
queryKey: ["bootstrap"],
|
||||
queryFn: async () => {
|
||||
await bootstrapGlobal({
|
||||
globalSDK: globalSDK.client,
|
||||
requestFailedTitle: language.t("common.requestFailed"),
|
||||
translate: language.t,
|
||||
formatMoreCount: (count) => language.t("common.moreCountSuffix", { count }),
|
||||
setGlobalStore: setBootStore,
|
||||
queryClient,
|
||||
})
|
||||
bootedAt = Date.now()
|
||||
return bootedAt
|
||||
},
|
||||
}))
|
||||
|
||||
const set = ((...input: unknown[]) => {
|
||||
if (input[0] === "project" && (Array.isArray(input[1]) || typeof input[1] === "function")) {
|
||||
setProjects(input[1] as Project[] | ((draft: Project[]) => Project[]))
|
||||
|
|
@ -96,6 +171,16 @@ function createGlobalSync() {
|
|||
return (setGlobalStore as (...args: unknown[]) => unknown)(...input)
|
||||
}) as typeof setGlobalStore
|
||||
|
||||
if (projectInit instanceof Promise) {
|
||||
void projectInit.then(() => {
|
||||
if (!active) return
|
||||
if (projectWritten) return
|
||||
const cached = projectCache.value
|
||||
if (cached.length === 0) return
|
||||
setGlobalStore("project", cached)
|
||||
})
|
||||
}
|
||||
|
||||
const setSessionTodo = (sessionID: string, todos: Todo[] | undefined) => {
|
||||
if (!sessionID) return
|
||||
if (!todos) {
|
||||
|
|
@ -112,11 +197,11 @@ function createGlobalSync() {
|
|||
|
||||
const paused = () => untrack(() => globalStore.reload) !== undefined
|
||||
|
||||
const queue = createRefreshQueue({
|
||||
paused,
|
||||
bootstrap,
|
||||
bootstrapInstance,
|
||||
})
|
||||
// const queue = createRefreshQueue({
|
||||
// paused,
|
||||
// bootstrap: () => queryClient.fetchQuery({ queryKey: ["bootstrap"] }),
|
||||
// bootstrapInstance,
|
||||
// })
|
||||
|
||||
const children = createChildStoreManager({
|
||||
owner,
|
||||
|
|
@ -126,7 +211,7 @@ function createGlobalSync() {
|
|||
void bootstrapInstance(directory)
|
||||
},
|
||||
onDispose: (directory) => {
|
||||
queue.clear(directory)
|
||||
// queue.clear(directory)
|
||||
sessionMeta.delete(directory)
|
||||
sdkCache.delete(directory)
|
||||
clearProviderRev(directory)
|
||||
|
|
@ -264,33 +349,20 @@ function createGlobalSync() {
|
|||
const event = e.details
|
||||
const recent = bootingRoot || Date.now() - bootedAt < 1500
|
||||
|
||||
if (event.type === "session.error") {
|
||||
const error = event.properties.error
|
||||
if (error?.name !== "MessageAbortedError") {
|
||||
console.error("[global-sync] session error", {
|
||||
scope: directory === "global" ? "global" : "workspace",
|
||||
directory: directory === "global" ? undefined : directory,
|
||||
project: directory === "global" ? undefined : getFilename(directory),
|
||||
sessionID: event.properties.sessionID,
|
||||
error,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (directory === "global") {
|
||||
applyGlobalEvent({
|
||||
event,
|
||||
project: globalStore.project,
|
||||
refresh: () => {
|
||||
if (recent) return
|
||||
queue.refresh()
|
||||
bootstrap.refetch()
|
||||
},
|
||||
setGlobalProject: setProjects,
|
||||
})
|
||||
if (event.type === "server.connected" || event.type === "global.disposed") {
|
||||
if (recent) return
|
||||
for (const directory of Object.keys(children.children)) {
|
||||
queue.push(directory)
|
||||
// queue.push(directory)
|
||||
}
|
||||
}
|
||||
return
|
||||
|
|
@ -305,47 +377,27 @@ function createGlobalSync() {
|
|||
directory,
|
||||
store,
|
||||
setStore,
|
||||
push: queue.push,
|
||||
push: () => {}, // queue.push,
|
||||
setSessionTodo,
|
||||
vcsCache: children.vcsCache.get(directory),
|
||||
loadLsp: () => {
|
||||
void sdkFor(directory)
|
||||
.lsp.status()
|
||||
.then((x) => {
|
||||
setStore("lsp", x.data ?? [])
|
||||
setStore("lsp_ready", true)
|
||||
})
|
||||
void queryClient.fetchQuery(loadLspQuery(directory, sdkFor(directory))).then((data) => {
|
||||
setStore("lsp", data ?? [])
|
||||
})
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
onCleanup(unsub)
|
||||
onCleanup(() => {
|
||||
queue.dispose()
|
||||
})
|
||||
// onCleanup(() => {
|
||||
// queue.dispose()
|
||||
// })
|
||||
onCleanup(() => {
|
||||
for (const directory of Object.keys(children.children)) {
|
||||
children.disposeDirectory(directory)
|
||||
}
|
||||
})
|
||||
|
||||
async function bootstrap() {
|
||||
bootingRoot = true
|
||||
try {
|
||||
await bootstrapGlobal({
|
||||
globalSDK: globalSDK.client,
|
||||
requestFailedTitle: language.t("common.requestFailed"),
|
||||
translate: language.t,
|
||||
formatMoreCount: (count) => language.t("common.moreCountSuffix", { count }),
|
||||
setGlobalStore: setBootStore,
|
||||
queryClient,
|
||||
})
|
||||
bootedAt = Date.now()
|
||||
} finally {
|
||||
bootingRoot = false
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
if (typeof requestAnimationFrame === "function") {
|
||||
eventFrame = requestAnimationFrame(() => {
|
||||
|
|
@ -361,7 +413,6 @@ function createGlobalSync() {
|
|||
void globalSDK.event.start()
|
||||
}, 0)
|
||||
}
|
||||
void bootstrap()
|
||||
})
|
||||
|
||||
const projectApi = {
|
||||
|
|
@ -374,21 +425,10 @@ function createGlobalSync() {
|
|||
},
|
||||
}
|
||||
|
||||
const updateConfig = async (config: Config) => {
|
||||
setGlobalStore("reload", "pending")
|
||||
return globalSDK.client.global.config
|
||||
.update({ config })
|
||||
.then(bootstrap)
|
||||
.then(() => {
|
||||
queue.refresh()
|
||||
setGlobalStore("reload", undefined)
|
||||
queue.refresh()
|
||||
})
|
||||
.catch((error) => {
|
||||
setGlobalStore("reload", undefined)
|
||||
throw error
|
||||
})
|
||||
}
|
||||
const updateConfigMutation = useMutation(() => ({
|
||||
mutationFn: (config: Config) => globalSDK.client.global.config.update({ config }),
|
||||
// onSuccess: () => bootstrap.refetch(),
|
||||
}))
|
||||
|
||||
return {
|
||||
data: globalStore,
|
||||
|
|
@ -401,8 +441,8 @@ function createGlobalSync() {
|
|||
},
|
||||
child: children.child,
|
||||
peek: children.peek,
|
||||
bootstrap,
|
||||
updateConfig,
|
||||
// bootstrap,
|
||||
updateConfig: updateConfigMutation.mutateAsync,
|
||||
project: projectApi,
|
||||
todo: {
|
||||
set: setSessionTodo,
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ 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 { loadMcpQuery } from "../global-sync"
|
||||
|
||||
type GlobalStore = {
|
||||
ready: boolean
|
||||
|
|
@ -66,6 +67,62 @@ function runAll(list: Array<() => Promise<unknown>>) {
|
|||
return Promise.allSettled(list.map((item) => item()))
|
||||
}
|
||||
|
||||
function showErrors(input: {
|
||||
errors: unknown[]
|
||||
title: string
|
||||
translate: (key: string, vars?: Record<string, string | number>) => string
|
||||
formatMoreCount: (count: number) => string
|
||||
}) {
|
||||
if (input.errors.length === 0) return
|
||||
const message = formatServerError(input.errors[0], input.translate)
|
||||
const more = input.errors.length > 1 ? input.formatMoreCount(input.errors.length - 1) : ""
|
||||
showToast({
|
||||
variant: "error",
|
||||
title: input.title,
|
||||
description: message + more,
|
||||
})
|
||||
}
|
||||
|
||||
export const loadGlobalConfigQuery = (
|
||||
sdk?: OpencodeClient,
|
||||
transform?: (x: Awaited<ReturnType<OpencodeClient["global"]["config"]["get"]>>) => void,
|
||||
) =>
|
||||
queryOptions({
|
||||
queryKey: ["config"],
|
||||
queryFn: sdk
|
||||
? () =>
|
||||
retry(() =>
|
||||
sdk.global.config.get().then((x) => {
|
||||
transform?.(x)
|
||||
return x.data!
|
||||
}),
|
||||
)
|
||||
: skipToken,
|
||||
})
|
||||
|
||||
export const loadProjectsQuery = (
|
||||
sdk?: OpencodeClient,
|
||||
transform?: (x: Awaited<ReturnType<OpencodeClient["project"]["list"]>>["data"]) => void,
|
||||
) =>
|
||||
queryOptions({
|
||||
queryKey: ["project"],
|
||||
queryFn: sdk
|
||||
? () =>
|
||||
retry(() =>
|
||||
sdk.project
|
||||
.list()
|
||||
.then((x) => {
|
||||
return (x.data ?? [])
|
||||
.filter((p) => !!p?.id)
|
||||
.filter((p) => !!p.worktree && !p.worktree.includes("opencode-test"))
|
||||
.slice()
|
||||
.sort((a, b) => cmp(a.id, b.id))
|
||||
})
|
||||
.then(transform),
|
||||
)
|
||||
: skipToken,
|
||||
})
|
||||
|
||||
export async function bootstrapGlobal(input: {
|
||||
globalSDK: OpencodeClient
|
||||
requestFailedTitle: string
|
||||
|
|
@ -74,61 +131,21 @@ export async function bootstrapGlobal(input: {
|
|||
setGlobalStore: SetStoreFunction<GlobalStore>
|
||||
queryClient: QueryClient
|
||||
}) {
|
||||
const fast = [
|
||||
() =>
|
||||
retry(() =>
|
||||
input.globalSDK.global.config.get().then((x) => {
|
||||
input.setGlobalStore("config", x.data!)
|
||||
}),
|
||||
),
|
||||
]
|
||||
|
||||
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({
|
||||
...loadProvidersQuery(null),
|
||||
queryFn: () =>
|
||||
retry(() =>
|
||||
input.globalSDK.provider.list().then((x) => {
|
||||
input.setGlobalStore("provider", normalizeProviderList(x.data!))
|
||||
return null
|
||||
}),
|
||||
),
|
||||
}),
|
||||
() =>
|
||||
retry(() =>
|
||||
input.globalSDK.path.get().then((x) => {
|
||||
input.setGlobalStore("path", x.data!)
|
||||
}),
|
||||
),
|
||||
() =>
|
||||
retry(() =>
|
||||
input.globalSDK.project.list().then((x) => {
|
||||
const projects = (x.data ?? [])
|
||||
.filter((p) => !!p?.id)
|
||||
.filter((p) => !!p.worktree && !p.worktree.includes("opencode-test"))
|
||||
.slice()
|
||||
.sort((a, b) => cmp(a.id, b.id))
|
||||
input.setGlobalStore("project", projects)
|
||||
}),
|
||||
input.queryClient.fetchQuery(
|
||||
loadProjectsQuery(input.globalSDK, (data) => input.setGlobalStore("project", data ?? [])),
|
||||
),
|
||||
]
|
||||
await runAll(fast)
|
||||
// showErrors({
|
||||
// errors: errors(await runAll(fast)),
|
||||
// title: input.requestFailedTitle,
|
||||
// translate: input.translate,
|
||||
// formatMoreCount: input.formatMoreCount,
|
||||
// })
|
||||
await waitForPaint()
|
||||
await runAll(slow)
|
||||
// showErrors({
|
||||
// errors: errors(),
|
||||
// title: input.requestFailedTitle,
|
||||
// translate: input.translate,
|
||||
// formatMoreCount: input.formatMoreCount,
|
||||
// })
|
||||
input.setGlobalStore("ready", true)
|
||||
showErrors({
|
||||
errors: errors(await runAll(slow)),
|
||||
title: input.requestFailedTitle,
|
||||
translate: input.translate,
|
||||
formatMoreCount: input.formatMoreCount,
|
||||
})
|
||||
}
|
||||
|
||||
function groupBySession<T extends { id: string; sessionID: string }>(input: T[]) {
|
||||
|
|
@ -179,26 +196,28 @@ function warmSessions(input: {
|
|||
).then(() => undefined)
|
||||
}
|
||||
|
||||
export const loadProvidersQuery = (directory: string | null) =>
|
||||
queryOptions<null>({ queryKey: [directory, "providers"], queryFn: skipToken })
|
||||
export const loadProvidersQuery = (directory: string | null, sdk?: OpencodeClient) =>
|
||||
queryOptions({
|
||||
queryKey: [directory, "providers"],
|
||||
queryFn: sdk ? () => retry(() => sdk.provider.list().then((x) => normalizeProviderList(x.data!))) : skipToken,
|
||||
})
|
||||
|
||||
export const loadAgentsQuery = (
|
||||
directory: string | null,
|
||||
sdk?: OpencodeClient,
|
||||
transform?: (x: Awaited<ReturnType<OpencodeClient["app"]["agents"]>>) => void,
|
||||
) =>
|
||||
queryOptions<null>({
|
||||
queryOptions({
|
||||
queryKey: [directory, "agents"],
|
||||
queryFn:
|
||||
sdk && transform
|
||||
? () =>
|
||||
retry(() =>
|
||||
sdk.app
|
||||
.agents()
|
||||
.then(transform)
|
||||
.then(() => null),
|
||||
)
|
||||
: skipToken,
|
||||
queryFn: sdk
|
||||
? () =>
|
||||
retry(() =>
|
||||
sdk.app.agents().then((x) => {
|
||||
transform?.(x)
|
||||
return x.data!
|
||||
}),
|
||||
)
|
||||
: skipToken,
|
||||
})
|
||||
|
||||
export const loadPathQuery = (
|
||||
|
|
@ -208,16 +227,15 @@ export const loadPathQuery = (
|
|||
) =>
|
||||
queryOptions<Path>({
|
||||
queryKey: [directory, "path"],
|
||||
queryFn:
|
||||
sdk && transform
|
||||
? () =>
|
||||
retry(() =>
|
||||
sdk.path.get().then(async (x) => {
|
||||
transform(x)
|
||||
return x.data!
|
||||
}),
|
||||
)
|
||||
: skipToken,
|
||||
queryFn: sdk
|
||||
? () =>
|
||||
retry(() =>
|
||||
sdk.path.get().then(async (x) => {
|
||||
transform?.(x)
|
||||
return x.data!
|
||||
}),
|
||||
)
|
||||
: skipToken,
|
||||
})
|
||||
|
||||
export async function bootstrapDirectory(input: {
|
||||
|
|
@ -247,12 +265,7 @@ export async function bootstrapDirectory(input: {
|
|||
if (Object.keys(input.store.config).length === 0 && Object.keys(input.global.config).length > 0) {
|
||||
input.setStore("config", input.global.config)
|
||||
}
|
||||
if (loading || input.store.provider.all.length === 0) {
|
||||
input.setStore("provider_ready", false)
|
||||
}
|
||||
input.setStore("mcp_ready", false)
|
||||
input.setStore("mcp", {})
|
||||
input.setStore("lsp_ready", false)
|
||||
input.setStore("lsp", [])
|
||||
if (loading) input.setStore("status", "partial")
|
||||
|
||||
|
|
@ -339,34 +352,20 @@ export async function bootstrapDirectory(input: {
|
|||
}),
|
||||
),
|
||||
() => Promise.resolve(input.loadSessions(input.directory)),
|
||||
() => input.queryClient.fetchQuery(loadMcpQuery(input.directory, input.sdk)),
|
||||
() =>
|
||||
retry(() =>
|
||||
input.sdk.mcp.status().then((x) => {
|
||||
input.setStore("mcp", x.data!)
|
||||
input.setStore("mcp_ready", true)
|
||||
}),
|
||||
input.queryClient.ensureQueryData(
|
||||
loadProvidersQuery(input.directory, input.sdk),
|
||||
// .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),
|
||||
// })
|
||||
// })
|
||||
),
|
||||
() =>
|
||||
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()
|
||||
|
|
|
|||
|
|
@ -14,8 +14,9 @@ import {
|
|||
type VcsCache,
|
||||
} from "./types"
|
||||
import { canDisposeDirectory, pickDirectoriesToEvict } from "./eviction"
|
||||
import { useQuery } from "@tanstack/solid-query"
|
||||
import { loadPathQuery } from "./bootstrap"
|
||||
import { useQueries } from "@tanstack/solid-query"
|
||||
import { loadPathQuery, loadProvidersQuery } from "./bootstrap"
|
||||
import { loadLspQuery, loadMcpQuery } from "../global-sync"
|
||||
|
||||
export function createChildStoreManager(input: {
|
||||
owner: Owner
|
||||
|
|
@ -158,12 +159,22 @@ export function createChildStoreManager(input: {
|
|||
createRoot((dispose) => {
|
||||
const initialIcon = icon[0].value
|
||||
|
||||
const pathQuery = useQuery(() => loadPathQuery(directory))
|
||||
const [pathQuery, mcpQuery, lspQuery, providerQuery] = useQueries(() => ({
|
||||
queries: [
|
||||
loadPathQuery(directory),
|
||||
loadMcpQuery(directory),
|
||||
loadLspQuery(directory),
|
||||
loadProvidersQuery(directory),
|
||||
],
|
||||
}))
|
||||
|
||||
const child = createStore<State>({
|
||||
project: "",
|
||||
projectMeta: undefined,
|
||||
icon: initialIcon,
|
||||
provider_ready: false,
|
||||
get provider_ready() {
|
||||
return providerQuery.isLoading
|
||||
},
|
||||
provider: { all: [], connected: [], default: {} },
|
||||
config: {},
|
||||
get path() {
|
||||
|
|
@ -181,9 +192,13 @@ export function createChildStoreManager(input: {
|
|||
todo: {},
|
||||
permission: {},
|
||||
question: {},
|
||||
mcp_ready: false,
|
||||
get mcp_ready() {
|
||||
return mcpQuery.isLoading
|
||||
},
|
||||
mcp: {},
|
||||
lsp_ready: false,
|
||||
get lsp_ready() {
|
||||
return lspQuery.isLoading
|
||||
},
|
||||
lsp: [],
|
||||
vcs: vcsStore.value,
|
||||
limit: 5,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue