application-tools.ts 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
  1. export * as ApplicationTools from "./application-tools"
  2. import { Context, Effect, Layer, Scope } from "effect"
  3. import { castDraft, enableMapSet } from "immer"
  4. import { State } from "../state"
  5. import { NativeTool } from "./native"
  6. type Data = {
  7. readonly entries: Map<string, NativeTool.Any>
  8. }
  9. type Editor = {
  10. readonly set: (name: string, tool: NativeTool.Any) => void
  11. }
  12. export interface Interface {
  13. readonly attach: (tools: Readonly<Record<string, NativeTool.Any>>) => Effect.Effect<void, never, Scope.Scope>
  14. readonly entries: () => ReadonlyMap<string, NativeTool.Any>
  15. }
  16. export class Service extends Context.Service<Service, Interface>()("@opencode/ApplicationTools") {}
  17. enableMapSet()
  18. export const layer = Layer.effect(
  19. Service,
  20. Effect.gen(function* () {
  21. const state = State.create<Data, Editor>({
  22. initial: () => ({ entries: new Map() }),
  23. editor: (draft) => ({
  24. set: (name, tool) => {
  25. draft.entries.set(
  26. name,
  27. castDraft(tool) as typeof draft.entries extends Map<string, infer Value> ? Value : never,
  28. )
  29. },
  30. }),
  31. })
  32. return Service.of({
  33. attach: Effect.fn("ApplicationTools.attach")(function* (tools) {
  34. const entries = Object.entries(tools)
  35. const transform = yield* state.transform()
  36. yield* transform((editor) => {
  37. for (const [name, tool] of entries) editor.set(name, tool)
  38. })
  39. }),
  40. entries: () => state.get().entries,
  41. })
  42. }),
  43. )