| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219 |
- export * as PluginHost from "./host"
- import type { PluginContext as Interface } from "@opencode-ai/plugin/v2/effect"
- import { Effect, Schema } from "effect"
- import { AgentV2 } from "../agent"
- import { AISDK } from "../aisdk"
- import { Catalog } from "../catalog"
- import { CommandV2 } from "../command"
- import { Credential } from "../credential"
- import { Integration } from "../integration"
- import { ModelV2 } from "../model"
- import { PluginV2 } from "../plugin"
- import { ProviderV2 } from "../provider"
- import { Reference } from "../reference"
- import type { DeepMutable } from "../schema"
- import { SkillV2 } from "../skill"
- const mutable = <T>(value: T) => value as DeepMutable<T>
- export const make = Effect.fn("PluginHost.make")(function* (plugin: PluginV2.Interface) {
- const agents = yield* AgentV2.Service
- const aisdk = yield* AISDK.Service
- const catalog = yield* Catalog.Service
- const commands = yield* CommandV2.Service
- const integration = yield* Integration.Service
- const reference = yield* Reference.Service
- const skill = yield* SkillV2.Service
- return {
- options: {},
- agent: {
- reload: agents.reload,
- transform: (callback) =>
- agents.transform((draft) =>
- callback({
- list: () => mutable(draft.list()),
- get: (id) => mutable(draft.get(AgentV2.ID.make(id))),
- default: (id) => draft.default(id === undefined ? undefined : AgentV2.ID.make(id)),
- update: (id, update) => draft.update(AgentV2.ID.make(id), update),
- remove: (id) => draft.remove(AgentV2.ID.make(id)),
- }),
- ),
- },
- aisdk: {
- sdk: (callback) =>
- aisdk.hook.sdk((event) => {
- const output = {
- model: mutable(event.model),
- package: event.package,
- options: event.options,
- sdk: event.sdk,
- }
- const result = callback(output)
- return Effect.suspend(() => (Effect.isEffect(result) ? result : Effect.void)).pipe(
- Effect.tap(() => Effect.sync(() => (event.sdk = output.sdk))),
- )
- }),
- language: (callback) =>
- aisdk.hook.language((event) => {
- const output = {
- model: mutable(event.model),
- sdk: event.sdk,
- options: event.options,
- language: event.language,
- }
- const result = callback(output)
- return Effect.suspend(() => (Effect.isEffect(result) ? result : Effect.void)).pipe(
- Effect.tap(() => Effect.sync(() => (event.language = output.language))),
- )
- }),
- },
- catalog: {
- reload: catalog.reload,
- transform: (callback) =>
- catalog.transform((draft) =>
- callback({
- provider: {
- list: () => mutable(draft.provider.list()),
- get: (id) => mutable(draft.provider.get(ProviderV2.ID.make(id))),
- update: (id, update) => draft.provider.update(ProviderV2.ID.make(id), update),
- remove: (id) => draft.provider.remove(ProviderV2.ID.make(id)),
- },
- model: {
- get: (providerID, modelID) =>
- mutable(draft.model.get(ProviderV2.ID.make(providerID), ModelV2.ID.make(modelID))),
- update: (providerID, modelID, update) =>
- draft.model.update(ProviderV2.ID.make(providerID), ModelV2.ID.make(modelID), update),
- remove: (providerID, modelID) =>
- draft.model.remove(ProviderV2.ID.make(providerID), ModelV2.ID.make(modelID)),
- default: {
- get: draft.model.default.get,
- set: (providerID, modelID) =>
- draft.model.default.set(ProviderV2.ID.make(providerID), ModelV2.ID.make(modelID)),
- },
- },
- }),
- ),
- },
- command: {
- reload: commands.reload,
- transform: commands.transform,
- },
- integration: {
- reload: integration.reload,
- connection: {
- active: (id) => integration.connection.active(Integration.ID.make(id)),
- resolve: (connection) =>
- integration.connection.resolve(
- connection.type === "credential" ? { ...connection, id: Credential.ID.make(connection.id) } : connection,
- ),
- },
- transform: (callback) =>
- integration.transform((draft) =>
- callback({
- list: () => mutable(draft.list()),
- get: (id) => mutable(draft.get(Integration.ID.make(id))),
- update: (id, update) => draft.update(Integration.ID.make(id), update),
- remove: (id) => draft.remove(Integration.ID.make(id)),
- method: {
- list: (id) => mutable(draft.method.list(Integration.ID.make(id))),
- update: (input) => {
- if ("authorize" in input) {
- const methodID = Integration.MethodID.make(input.method.id)
- const refresh = input.refresh
- draft.method.update({
- integrationID: Integration.ID.make(input.integrationID),
- method: { ...input.method, id: methodID },
- authorize: (inputs) =>
- input.authorize(inputs).pipe(
- Effect.map((authorization) => {
- if (authorization.mode === "auto") {
- return {
- ...authorization,
- callback: authorization.callback.pipe(
- Effect.map((credential) =>
- Credential.OAuth.make({
- ...credential,
- methodID: Integration.MethodID.make(credential.methodID),
- }),
- ),
- ),
- }
- }
- return {
- ...authorization,
- callback: (code: string) =>
- authorization.callback(code).pipe(
- Effect.map((credential) =>
- Credential.OAuth.make({
- ...credential,
- methodID: Integration.MethodID.make(credential.methodID),
- }),
- ),
- ),
- }
- }),
- ),
- ...(refresh
- ? {
- refresh: (value: Credential.OAuth) =>
- refresh(value).pipe(
- Effect.map((next) =>
- Credential.OAuth.make({
- ...next,
- methodID: Integration.MethodID.make(next.methodID),
- }),
- ),
- ),
- }
- : {}),
- ...(input.label ? { label: input.label } : {}),
- })
- return
- }
- if (input.method.type === "env") {
- draft.method.update({
- integrationID: Integration.ID.make(input.integrationID),
- method: { type: "env", names: input.method.names },
- })
- return
- }
- draft.method.update({
- integrationID: Integration.ID.make(input.integrationID),
- method: { type: "key", label: input.method.label },
- })
- },
- remove: (id, method) =>
- draft.method.remove(Integration.ID.make(id), Schema.decodeUnknownSync(Integration.Method)(method)),
- },
- }),
- ),
- },
- plugin: {
- add: (input) => plugin.add(PluginV2.ID.make(input.id), input.effect),
- remove: (id) => plugin.remove(PluginV2.ID.make(id)),
- },
- reference: {
- reload: reference.reload,
- transform: (callback) =>
- reference.transform((draft) =>
- callback({
- add: (name, source) => draft.add(name, Schema.decodeUnknownSync(Reference.Source)(source)),
- remove: draft.remove,
- list: draft.list,
- }),
- ),
- },
- skill: {
- reload: skill.reload,
- transform: (callback) =>
- skill.transform((draft) =>
- callback({
- source: (source) => draft.source(Schema.decodeUnknownSync(SkillV2.Source)(source)),
- list: draft.list,
- }),
- ),
- },
- } satisfies Interface
- })
|