57 lines
1.7 KiB
TypeScript
57 lines
1.7 KiB
TypeScript
export * as ApplicationTools from "./application-tools"
|
|
|
|
import { Context, Effect, Layer, Scope } from "effect"
|
|
import { State } from "../state"
|
|
import { Tool } from "./tool"
|
|
import { makeGlobalNode } from "../effect/app-node"
|
|
|
|
type Data = {
|
|
readonly entries: Map<string, Entry>
|
|
}
|
|
|
|
type Draft = {
|
|
readonly set: (name: string, entry: Entry) => void
|
|
}
|
|
|
|
export interface Entry {
|
|
readonly identity: object
|
|
readonly tool: Tool.AnyTool
|
|
}
|
|
|
|
export interface Interface {
|
|
readonly register: (
|
|
tools: Readonly<Record<string, Tool.AnyTool>>,
|
|
) => Effect.Effect<void, Tool.RegistrationError, Scope.Scope>
|
|
readonly entries: () => ReadonlyMap<string, Entry>
|
|
}
|
|
|
|
export class Service extends Context.Service<Service, Interface>()("@opencode/ApplicationTools") {}
|
|
|
|
const layer = Layer.effect(
|
|
Service,
|
|
Effect.gen(function* () {
|
|
const state = State.create<Data, Draft>({
|
|
initial: () => ({ entries: new Map() }),
|
|
draft: (draft) => ({
|
|
set: (name, tool) => {
|
|
draft.entries.set(name, tool)
|
|
},
|
|
}),
|
|
})
|
|
|
|
return Service.of({
|
|
register: Effect.fn("ApplicationTools.register")(function* (tools) {
|
|
const entries = Object.entries(tools)
|
|
if (entries.length === 0) return
|
|
yield* Effect.forEach(entries, ([name]) => Tool.validateName(name), { discard: true })
|
|
const registrations = entries.map(([name, tool]) => [name, { identity: {}, tool }] as const)
|
|
yield* state.transform((draft) => {
|
|
for (const [name, entry] of registrations) draft.set(name, entry)
|
|
})
|
|
}),
|
|
entries: () => state.get().entries,
|
|
})
|
|
}),
|
|
)
|
|
|
|
export const node = makeGlobalNode({ service: Service, layer, deps: [] })
|