diff --git a/packages/opencode/src/control-plane/adapters/index.ts b/packages/opencode/src/control-plane/adapters/index.ts index 79148e1671..1f04ffcfbf 100644 --- a/packages/opencode/src/control-plane/adapters/index.ts +++ b/packages/opencode/src/control-plane/adapters/index.ts @@ -7,27 +7,12 @@ import { type WorkspaceAdapter, WorkspaceAdapterError, type WorkspaceAdapterEntr import type { Interface as WorktreeService } from "@/worktree" import { WorktreeAdapterEntry, worktreeAdapter } from "./worktree" -export interface AdapterServices { - readonly worktree: WorktreeService -} +const BUILTIN: WorkspaceAdapterEntry[] = [{ type: "worktree", ...WorktreeAdapterEntry }] -const BUILTIN: Record = { - worktree: { type: "worktree", ...WorktreeAdapterEntry }, -} +export const makeBuiltinAdapters = (worktree: WorktreeService) => + new Map([["worktree", worktreeAdapter(worktree)]]) -const builtinAdapter = (type: string, services: AdapterServices): WorkspaceAdapter | undefined => { - if (type === "worktree") return worktreeAdapter(services.worktree) -} - -export const makeBuiltinAdapters = (services: AdapterServices) => - new Map( - Object.keys(BUILTIN).flatMap((type) => { - const adapter = builtinAdapter(type, services) - return adapter ? [[type, adapter] as const] : [] - }), - ) - -const state = new Map>() +const plugins = new Map>() const emptyBuiltinAdapters = new Map() export function getAdapter( @@ -35,7 +20,7 @@ export function getAdapter( type: string, builtin: ReadonlyMap = emptyBuiltinAdapters, ): WorkspaceAdapter { - const custom = state.get(projectID)?.get(type) + const custom = plugins.get(projectID)?.get(type) if (custom) return custom const adapter = builtin.get(type) @@ -45,20 +30,12 @@ export function getAdapter( } export async function listAdapters(projectID: ProjectID): Promise { - const custom = [...(state.get(projectID)?.entries() ?? [])].map(([type, adapter]) => ({ + const custom = [...(plugins.get(projectID)?.entries() ?? [])].map(([type, adapter]) => ({ type, name: adapter.name, description: adapter.description, })) - return [...Object.values(BUILTIN), ...custom] -} - -// Plugins can be loaded per-project so we need to scope them. If you -// want to install a global one pass `ProjectID.global` -export function registerEffectAdapter(projectID: ProjectID, type: string, adapter: WorkspaceAdapter) { - const adapters = state.get(projectID) ?? new Map() - adapters.set(type, adapter) - state.set(projectID, adapters) + return [...BUILTIN, ...custom] } const adapterError = (cause: unknown) => new WorkspaceAdapterError({ message: errorMessage(cause), cause }) @@ -92,5 +69,9 @@ function fromPromiseAdapter(adapter: PluginWorkspaceAdapter): WorkspaceAdapter { } export function registerAdapter(projectID: ProjectID, type: string, adapter: PluginWorkspaceAdapter) { - registerEffectAdapter(projectID, type, fromPromiseAdapter(adapter)) + // Plugins can be loaded per-project so we need to scope them. If you + // want to install a global one pass `ProjectID.global`. + const adapters = plugins.get(projectID) ?? new Map() + adapters.set(type, fromPromiseAdapter(adapter)) + plugins.set(projectID, adapters) } diff --git a/packages/opencode/src/control-plane/workspace.ts b/packages/opencode/src/control-plane/workspace.ts index 5ee9969b90..ea25118248 100644 --- a/packages/opencode/src/control-plane/workspace.ts +++ b/packages/opencode/src/control-plane/workspace.ts @@ -176,10 +176,12 @@ export const layer = Layer.effect( const worktree = yield* Worktree.Service const connections = new Map() const syncFibers = yield* FiberMap.make() - const adapters = makeBuiltinAdapters({ worktree }) + const builtinAdapters = makeBuiltinAdapters(worktree) + const adapterFor = (space: { projectID: ProjectID; type: string }) => + getAdapter(space.projectID, space.type, builtinAdapters) const target = Effect.fn("Workspace.target")(function* (space: Info) { - return yield* getAdapter(space.projectID, space.type, adapters).target(space) + return yield* adapterFor(space).target(space) }) const setStatus = (id: WorkspaceID, status: ConnectionStatus["status"]) => { @@ -465,7 +467,7 @@ export const layer = Layer.effect( const create = Effect.fn("Workspace.create")(function* (input: CreateInput) { const id = WorkspaceID.ascending(input.id) - const adapter = getAdapter(input.projectID, input.type, adapters) + const adapter = adapterFor(input) const config = yield* adapter.configure({ ...input, id, name: Slug.create(), directory: null }) const info: Info = { @@ -730,8 +732,7 @@ export const layer = Layer.effect( const info = fromRow(row) yield* Effect.catch( Effect.gen(function* () { - const adapter = getAdapter(info.projectID, row.type, adapters) - yield* adapter.remove(info) + yield* adapterFor(info).remove(info) }), () => Effect.sync(() => {