command.ts 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. export * as CommandV2 from "./command"
  2. import { Context, Effect, Layer, Schema } from "effect"
  3. import { castDraft, type Draft } from "immer"
  4. import { ModelV2 } from "./model"
  5. import { State } from "./state"
  6. export class Info extends Schema.Class<Info>("CommandV2.Info")({
  7. name: Schema.String,
  8. template: Schema.String,
  9. description: Schema.String.pipe(Schema.optional),
  10. agent: Schema.String.pipe(Schema.optional),
  11. model: ModelV2.Ref.pipe(Schema.optional),
  12. subtask: Schema.Boolean.pipe(Schema.optional),
  13. }) {}
  14. export type Data = {
  15. commands: Map<string, Info>
  16. }
  17. export type Editor = {
  18. list: () => readonly Info[]
  19. get: (name: string) => Info | undefined
  20. update: (name: string, update: (command: Draft<Info>) => void) => void
  21. remove: (name: string) => void
  22. }
  23. export interface Interface {
  24. readonly transform: State.Interface<Data, Editor>["transform"]
  25. readonly update: State.Interface<Data, Editor>["update"]
  26. readonly get: (name: string) => Effect.Effect<Info | undefined>
  27. readonly list: () => Effect.Effect<Info[]>
  28. }
  29. export class Service extends Context.Service<Service, Interface>()("@opencode/v2/Command") {}
  30. export const layer = Layer.effect(
  31. Service,
  32. Effect.sync(() => {
  33. const state = State.create<Data, Editor>({
  34. initial: () => ({ commands: new Map() }),
  35. editor: (draft) => ({
  36. list: () => Array.from(draft.commands.values()) as Info[],
  37. get: (name) => draft.commands.get(name),
  38. update: (name, update) => {
  39. const current = draft.commands.get(name) ?? castDraft(new Info({ name, template: "" }))
  40. if (!draft.commands.has(name)) draft.commands.set(name, current)
  41. update(current)
  42. current.name = name
  43. },
  44. remove: (name) => {
  45. draft.commands.delete(name)
  46. },
  47. }),
  48. })
  49. return Service.of({
  50. update: state.update,
  51. transform: state.transform,
  52. get: Effect.fn("CommandV2.get")(function* (name) {
  53. return state.get().commands.get(name)
  54. }),
  55. list: Effect.fn("CommandV2.list")(function* () {
  56. return Array.from(state.get().commands.values())
  57. }),
  58. })
  59. }),
  60. )
  61. export const locationLayer = layer