import { createSimpleContext } from "@opencode/ui/context" import type { LocationGetOutput, LocationRef } from "@opencode/client/promise" import { retry } from "@opencode/util/retry" import { type Accessor, createEffect, createMemo, onCleanup } from "solid-js" import { type LocationContext, useServerSDK } from "@/runtime/server/client" import { useData, useServer } from "@/runtime/server/current" export type { LocationContext } from "@/runtime/server/client" export type WorkspaceLocation = LocationContext & { readonly ref: LocationRef readonly current: LocationGetOutput | undefined } const context = createSimpleContext({ name: "Location", init: (props: { directory: string | Accessor; workspaceID?: string | Accessor }) => { const serverSDK = useServerSDK() const server = useServer() const data = useData() const ref = createMemo( () => ({ directory: typeof props.directory === "function" ? props.directory() : props.directory, workspaceID: typeof props.workspaceID === "function" ? props.workspaceID() : props.workspaceID, }), undefined, { equals: (previous, next) => previous.directory === next.directory && previous.workspaceID === next.workspaceID, }, ) const current = createMemo(() => data.location.info(ref())) createEffect(() => { const location = ref() let stale = false onCleanup(() => { stale = true }) if (serverSDK.connection.status() !== "connected") return // A failed sync does not prove the directory is missing. Keep recovery local to reads. void retry(() => (stale ? Promise.resolve() : data.location.sync(location)), { retryIf: () => !stale, }).catch(() => undefined) }) createEffect(() => { const id = current()?.project.id if (!id || serverSDK.connection.status() !== "connected") return // Showing a Location is the demand for its project's worktree inventory (workspace styling, picker). void server.ctx.sync.worktrees.list(id).then(() => server.ctx.sync.worktrees.refresh(id)) }) const location = createMemo(() => serverSDK.ensureDirSdkContext(current()?.directory ?? ref().directory)) return createMemo(() => ({ ...location(), ref: ref(), current: current(), })) }, }) export const useWorkspaceLocation: () => Accessor = context.use export const LocationProvider = context.provider