feat(plugin): align hooks with client APIs
This commit is contained in:
@@ -122,6 +122,7 @@
|
|||||||
},
|
},
|
||||||
"packages/client": {
|
"packages/client": {
|
||||||
"name": "@opencode-ai/client",
|
"name": "@opencode-ai/client",
|
||||||
|
"version": "1.17.13",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@opencode-ai/protocol": "workspace:*",
|
"@opencode-ai/protocol": "workspace:*",
|
||||||
"@opencode-ai/schema": "workspace:*",
|
"@opencode-ai/schema": "workspace:*",
|
||||||
@@ -695,6 +696,7 @@
|
|||||||
"version": "1.17.13",
|
"version": "1.17.13",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ai-sdk/provider": "3.0.8",
|
"@ai-sdk/provider": "3.0.8",
|
||||||
|
"@opencode-ai/client": "workspace:*",
|
||||||
"@opencode-ai/llm": "workspace:*",
|
"@opencode-ai/llm": "workspace:*",
|
||||||
"@opencode-ai/protocol": "workspace:*",
|
"@opencode-ai/protocol": "workspace:*",
|
||||||
"@opencode-ai/schema": "workspace:*",
|
"@opencode-ai/schema": "workspace:*",
|
||||||
|
|||||||
@@ -1,16 +1,30 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://json.schemastore.org/package.json",
|
"$schema": "https://json.schemastore.org/package.json",
|
||||||
"name": "@opencode-ai/client",
|
"name": "@opencode-ai/client",
|
||||||
"private": true,
|
"version": "1.17.13",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/anomalyco/opencode.git",
|
||||||
|
"directory": "packages/client"
|
||||||
|
},
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "public"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
"exports": {
|
"exports": {
|
||||||
"./promise": "./src/promise/index.ts",
|
"./promise": "./src/promise/index.ts",
|
||||||
"./effect": "./src/effect/index.ts"
|
"./promise/api": "./src/promise/api.ts",
|
||||||
|
"./effect": "./src/effect/index.ts",
|
||||||
|
"./effect/api": "./src/effect/api.ts"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"build": "bun run script/build-package.ts",
|
||||||
"generate": "bun run script/build.ts",
|
"generate": "bun run script/build.ts",
|
||||||
"check:generated": "bun run generate && git diff --exit-code -- src/promise/generated src/effect/generated",
|
"check:generated": "bun run generate && git diff --exit-code -- src/promise/generated src/effect/generated src/effect/api",
|
||||||
"test": "bun test --timeout 5000",
|
"test": "bun test --timeout 5000",
|
||||||
"typecheck": "tsgo --noEmit"
|
"typecheck": "tsgo --noEmit"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#!/usr/bin/env bun
|
||||||
|
|
||||||
|
import { $ } from "bun"
|
||||||
|
import { fileURLToPath } from "node:url"
|
||||||
|
|
||||||
|
process.chdir(fileURLToPath(new URL("..", import.meta.url)))
|
||||||
|
|
||||||
|
await $`rm -rf dist`
|
||||||
|
await $`bun tsc -p tsconfig.build.json`
|
||||||
@@ -32,8 +32,8 @@ await Effect.runPromise(
|
|||||||
fileURLToPath(new URL("../src/effect/generated", import.meta.url)),
|
fileURLToPath(new URL("../src/effect/generated", import.meta.url)),
|
||||||
),
|
),
|
||||||
write(
|
write(
|
||||||
emitEffectShape(effectContract, { module: "@opencode-ai/protocol/client", api: "ClientApi" }),
|
emitEffectShape(effectContract, { module: "../../contract", api: "ClientApi" }),
|
||||||
fileURLToPath(new URL("../../plugin/src/v2/effect/generated", import.meta.url)),
|
fileURLToPath(new URL("../src/effect/api", import.meta.url)),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
{ concurrency: 3, discard: true },
|
{ concurrency: 3, discard: true },
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
#!/usr/bin/env bun
|
||||||
|
|
||||||
|
import { Script } from "@opencode-ai/script"
|
||||||
|
import { $ } from "bun"
|
||||||
|
import { rm } from "node:fs/promises"
|
||||||
|
import { fileURLToPath } from "node:url"
|
||||||
|
|
||||||
|
process.chdir(fileURLToPath(new URL("..", import.meta.url)))
|
||||||
|
|
||||||
|
const originalText = await Bun.file("package.json").text()
|
||||||
|
const pkg = JSON.parse(originalText) as {
|
||||||
|
name: string
|
||||||
|
version: string
|
||||||
|
exports: Record<string, string | { import: string; types: string }>
|
||||||
|
}
|
||||||
|
const tarball = `${pkg.name.replace("@", "").replace("/", "-")}-${pkg.version}.tgz`
|
||||||
|
|
||||||
|
if ((await $`npm view ${pkg.name}@${pkg.version} version`.nothrow()).exitCode === 0) {
|
||||||
|
console.log(`already published ${pkg.name}@${pkg.version}`)
|
||||||
|
process.exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await $`bun run typecheck`
|
||||||
|
await $`bun run build`
|
||||||
|
pkg.exports = Object.fromEntries(
|
||||||
|
Object.entries(pkg.exports).map(([key, value]) => {
|
||||||
|
if (typeof value !== "string") return [key, value]
|
||||||
|
return [
|
||||||
|
key,
|
||||||
|
{
|
||||||
|
import: value.replace("./src/", "./dist/").replace(/\.ts$/, ".js"),
|
||||||
|
types: value.replace("./src/", "./dist/").replace(/\.ts$/, ".d.ts"),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
await Bun.write("package.json", JSON.stringify(pkg, null, 2) + "\n")
|
||||||
|
await rm(tarball, { force: true })
|
||||||
|
await $`bun pm pack`
|
||||||
|
await $`npm publish ${tarball} --tag ${Script.channel} --access public`
|
||||||
|
} finally {
|
||||||
|
await Bun.write("package.json", originalText)
|
||||||
|
await rm(tarball, { force: true })
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import type { ModelApi, ProviderApi } from "./api/api.js"
|
||||||
|
|
||||||
|
export type * from "./api/api.js"
|
||||||
|
|
||||||
|
export interface CatalogApi<E = never> {
|
||||||
|
readonly provider: ProviderApi<E>
|
||||||
|
readonly model: ModelApi<E>
|
||||||
|
}
|
||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
// Generated by @opencode-ai/httpapi-codegen. Do not edit.
|
// Generated by @opencode-ai/httpapi-codegen. Do not edit.
|
||||||
import type { Effect, Stream } from "effect"
|
import type { Effect, Stream } from "effect"
|
||||||
import type { HttpApiClient } from "effect/unstable/httpapi"
|
import type { HttpApiClient } from "effect/unstable/httpapi"
|
||||||
import type { ClientApi } from "@opencode-ai/protocol/client"
|
import type { ClientApi } from "../../contract"
|
||||||
|
|
||||||
type RawClient = HttpApiClient.ForApi<typeof ClientApi>
|
type RawClient = HttpApiClient.ForApi<typeof ClientApi>
|
||||||
type EffectValue<A> = A extends Effect.Effect<infer Success, any, any> ? Success : never
|
type EffectValue<A> = A extends Effect.Effect<infer Success, any, any> ? Success : never
|
||||||
@@ -1,6 +1,21 @@
|
|||||||
// TODO: Keep additional network capabilities inside Schema and Protocol as the client grows; /effect must never import
|
// TODO: Keep additional network capabilities inside Schema and Protocol as the client grows; /effect must never import
|
||||||
// Core or Server. Preserve these datatype exports so internal model reorganizations do not require caller migrations.
|
// Core or Server. Preserve these datatype exports so internal model reorganizations do not require caller migrations.
|
||||||
|
import type { Effect } from "effect"
|
||||||
|
|
||||||
export * from "./generated/index"
|
export * from "./generated/index"
|
||||||
|
export type {
|
||||||
|
AgentApi,
|
||||||
|
AppApi,
|
||||||
|
CatalogApi,
|
||||||
|
CommandApi,
|
||||||
|
IntegrationApi,
|
||||||
|
ModelApi,
|
||||||
|
PluginApi,
|
||||||
|
ProviderApi,
|
||||||
|
ReferenceApi,
|
||||||
|
SessionApi,
|
||||||
|
SkillApi,
|
||||||
|
} from "./api.js"
|
||||||
export { Service } from "./service.js"
|
export { Service } from "./service.js"
|
||||||
export { Agent } from "@opencode-ai/schema/agent"
|
export { Agent } from "@opencode-ai/schema/agent"
|
||||||
export { Command } from "@opencode-ai/schema/command"
|
export { Command } from "@opencode-ai/schema/command"
|
||||||
@@ -27,3 +42,4 @@ export { SessionMessage } from "@opencode-ai/schema/session-message"
|
|||||||
export { Skill } from "@opencode-ai/schema/skill"
|
export { Skill } from "@opencode-ai/schema/skill"
|
||||||
export { Prompt } from "@opencode-ai/schema/prompt"
|
export { Prompt } from "@opencode-ai/schema/prompt"
|
||||||
export type { OpenCodeEvent } from "@opencode-ai/protocol/groups/event"
|
export type { OpenCodeEvent } from "@opencode-ai/protocol/groups/event"
|
||||||
|
export type OpenCodeClient = Effect.Success<ReturnType<typeof import("./generated/client").make>>
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
import type {
|
||||||
|
AgentApi as EffectAgentApi,
|
||||||
|
CommandApi as EffectCommandApi,
|
||||||
|
IntegrationApi as EffectIntegrationApi,
|
||||||
|
ModelApi as EffectModelApi,
|
||||||
|
PluginApi as EffectPluginApi,
|
||||||
|
ProviderApi as EffectProviderApi,
|
||||||
|
ReferenceApi as EffectReferenceApi,
|
||||||
|
SessionApi as EffectSessionApi,
|
||||||
|
SkillApi as EffectSkillApi,
|
||||||
|
} from "../effect/api/api.js"
|
||||||
|
import type { Effect, Stream } from "effect"
|
||||||
|
|
||||||
|
type PromisifyOperation<Operation> = Operation extends (
|
||||||
|
...args: infer Args
|
||||||
|
) => Effect.Effect<infer Success, unknown, unknown>
|
||||||
|
? (...args: Args) => Promise<Success>
|
||||||
|
: Operation extends (...args: infer Args) => Stream.Stream<infer Success, unknown, unknown>
|
||||||
|
? (...args: Args) => AsyncIterable<Success>
|
||||||
|
: Operation
|
||||||
|
|
||||||
|
type PromisifyApi<Api> = {
|
||||||
|
readonly [Name in keyof Api]: PromisifyOperation<Api[Name]>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type AgentApi = PromisifyApi<EffectAgentApi<unknown>>
|
||||||
|
export type CommandApi = PromisifyApi<EffectCommandApi<unknown>>
|
||||||
|
export type IntegrationApi = PromisifyApi<EffectIntegrationApi<unknown>>
|
||||||
|
export type ModelApi = PromisifyApi<EffectModelApi<unknown>>
|
||||||
|
export type PluginApi = PromisifyApi<EffectPluginApi<unknown>>
|
||||||
|
export type ProviderApi = PromisifyApi<EffectProviderApi<unknown>>
|
||||||
|
export type ReferenceApi = PromisifyApi<EffectReferenceApi<unknown>>
|
||||||
|
export type SessionApi = PromisifyApi<EffectSessionApi<unknown>>
|
||||||
|
export type SkillApi = PromisifyApi<EffectSkillApi<unknown>>
|
||||||
|
|
||||||
|
export interface CatalogApi {
|
||||||
|
readonly provider: ProviderApi
|
||||||
|
readonly model: ModelApi
|
||||||
|
}
|
||||||
@@ -1,3 +1,15 @@
|
|||||||
export * from "./generated/index"
|
export * from "./generated/index"
|
||||||
|
export type {
|
||||||
|
AgentApi,
|
||||||
|
CatalogApi,
|
||||||
|
CommandApi,
|
||||||
|
IntegrationApi,
|
||||||
|
ModelApi,
|
||||||
|
PluginApi,
|
||||||
|
ProviderApi,
|
||||||
|
ReferenceApi,
|
||||||
|
SessionApi,
|
||||||
|
SkillApi,
|
||||||
|
} from "./api.js"
|
||||||
export type { EventSubscribeOutput as OpenCodeEvent } from "./generated/types"
|
export type { EventSubscribeOutput as OpenCodeEvent } from "./generated/types"
|
||||||
export type OpenCodeClient = ReturnType<typeof import("./generated/client").make>
|
export type OpenCodeClient = ReturnType<typeof import("./generated/client").make>
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import { Effect } from "effect"
|
||||||
|
import { OpenCode as EffectOpenCode, type AppApi as EffectApi } from "../src/effect"
|
||||||
|
|
||||||
|
type EffectClient = Effect.Success<ReturnType<typeof EffectOpenCode.make>>
|
||||||
|
|
||||||
|
declare const effectClient: EffectClient
|
||||||
|
|
||||||
|
const effectApi: EffectApi<unknown> = effectClient
|
||||||
|
|
||||||
|
void effectApi
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://json.schemastore.org/tsconfig",
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"rootDir": "src",
|
||||||
|
"outDir": "dist",
|
||||||
|
"noEmit": false,
|
||||||
|
"declaration": true
|
||||||
|
},
|
||||||
|
"include": ["src"]
|
||||||
|
}
|
||||||
@@ -3,6 +3,8 @@
|
|||||||
"extends": "@tsconfig/bun/tsconfig.json",
|
"extends": "@tsconfig/bun/tsconfig.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"lib": ["ESNext", "DOM", "DOM.Iterable"],
|
"lib": ["ESNext", "DOM", "DOM.Iterable"],
|
||||||
|
"allowImportingTsExtensions": false,
|
||||||
|
"allowJs": false,
|
||||||
"noUncheckedIndexedAccess": false
|
"noUncheckedIndexedAccess": false
|
||||||
},
|
},
|
||||||
"include": ["src"]
|
"include": ["src"]
|
||||||
|
|||||||
@@ -38,8 +38,6 @@ export const Plugin = define({
|
|||||||
effect: Effect.fn(function* (ctx) {
|
effect: Effect.fn(function* (ctx) {
|
||||||
const config = yield* Config.Service
|
const config = yield* Config.Service
|
||||||
const fs = yield* FSUtil.Service
|
const fs = yield* FSUtil.Service
|
||||||
yield* ctx.agent.transform(
|
|
||||||
Effect.fn(function* (draft) {
|
|
||||||
const documents = yield* Effect.forEach(yield* config.entries(), (entry) => {
|
const documents = yield* Effect.forEach(yield* config.entries(), (entry) => {
|
||||||
if (entry.type === "document") return Effect.succeed([entry])
|
if (entry.type === "document") return Effect.succeed([entry])
|
||||||
return Effect.gen(function* () {
|
return Effect.gen(function* () {
|
||||||
@@ -58,6 +56,7 @@ export const Plugin = define({
|
|||||||
}).pipe(Effect.map((documents) => documents.flat()))
|
}).pipe(Effect.map((documents) => documents.flat()))
|
||||||
const global = documents.flatMap((document) => document.info.permissions ?? [])
|
const global = documents.flatMap((document) => document.info.permissions ?? [])
|
||||||
const configuredDefault = Config.latest(documents, "default_agent")
|
const configuredDefault = Config.latest(documents, "default_agent")
|
||||||
|
yield* ctx.agent.transform((draft) => {
|
||||||
if (configuredDefault !== undefined) draft.default(AgentV2.ID.make(configuredDefault))
|
if (configuredDefault !== undefined) draft.default(AgentV2.ID.make(configuredDefault))
|
||||||
for (const current of draft.list()) {
|
for (const current of draft.list()) {
|
||||||
draft.update(current.id, (agent) => agent.permissions.push(...global))
|
draft.update(current.id, (agent) => agent.permissions.push(...global))
|
||||||
@@ -95,8 +94,7 @@ export const Plugin = define({
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}),
|
})
|
||||||
)
|
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -17,8 +17,6 @@ export const Plugin = define({
|
|||||||
effect: Effect.fn(function* (ctx) {
|
effect: Effect.fn(function* (ctx) {
|
||||||
const config = yield* Config.Service
|
const config = yield* Config.Service
|
||||||
const fs = yield* FSUtil.Service
|
const fs = yield* FSUtil.Service
|
||||||
yield* ctx.command.transform(
|
|
||||||
Effect.fn(function* (draft) {
|
|
||||||
const documents = yield* Effect.forEach(yield* config.entries(), (entry) => {
|
const documents = yield* Effect.forEach(yield* config.entries(), (entry) => {
|
||||||
if (entry.type === "document") return Effect.succeed([{ commands: entry.info.commands }])
|
if (entry.type === "document") return Effect.succeed([{ commands: entry.info.commands }])
|
||||||
return loadDirectory(fs, entry.path).pipe(
|
return loadDirectory(fs, entry.path).pipe(
|
||||||
@@ -27,6 +25,7 @@ export const Plugin = define({
|
|||||||
]),
|
]),
|
||||||
)
|
)
|
||||||
}).pipe(Effect.map((documents) => documents.flat()))
|
}).pipe(Effect.map((documents) => documents.flat()))
|
||||||
|
yield* ctx.command.transform((draft) => {
|
||||||
for (const document of documents) {
|
for (const document of documents) {
|
||||||
for (const [name, command] of Object.entries(document.commands ?? {})) {
|
for (const [name, command] of Object.entries(document.commands ?? {})) {
|
||||||
draft.update(name, (item) => {
|
draft.update(name, (item) => {
|
||||||
@@ -44,8 +43,7 @@ export const Plugin = define({
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}),
|
})
|
||||||
)
|
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -9,16 +9,14 @@ export const Plugin = define({
|
|||||||
id: "config-provider",
|
id: "config-provider",
|
||||||
effect: Effect.fn(function* (ctx) {
|
effect: Effect.fn(function* (ctx) {
|
||||||
const config = yield* Config.Service
|
const config = yield* Config.Service
|
||||||
yield* ctx.integration.transform(
|
const entries = yield* config.entries()
|
||||||
Effect.fn(function* (integrations) {
|
const files = entries.filter((entry): entry is Config.Document => entry.type === "document")
|
||||||
const files = (yield* config.entries()).filter((entry): entry is Config.Document => entry.type === "document")
|
|
||||||
const configuredIntegrations = new Set(
|
const configuredIntegrations = new Set(
|
||||||
files.flatMap((file) =>
|
files.flatMap((file) =>
|
||||||
Object.entries(file.info.providers ?? {}).flatMap(([id, provider]) =>
|
Object.entries(file.info.providers ?? {}).flatMap(([id, provider]) => (provider.env === undefined ? [] : [id])),
|
||||||
provider.env === undefined ? [] : [id],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
yield* ctx.integration.transform((integrations) => {
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
for (const [id, item] of Object.entries(file.info.providers ?? {})) {
|
for (const [id, item] of Object.entries(file.info.providers ?? {})) {
|
||||||
const integrationID = id
|
const integrationID = id
|
||||||
@@ -34,14 +32,10 @@ export const Plugin = define({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}),
|
})
|
||||||
)
|
|
||||||
|
|
||||||
yield* ctx.catalog.transform(
|
|
||||||
Effect.fn(function* (catalog) {
|
|
||||||
const entries = yield* config.entries()
|
|
||||||
const files = entries.filter((entry): entry is Config.Document => entry.type === "document")
|
|
||||||
const configuredDefault = Config.latest(entries, "model")
|
const configuredDefault = Config.latest(entries, "model")
|
||||||
|
yield* ctx.catalog.transform((catalog) => {
|
||||||
if (configuredDefault !== undefined) {
|
if (configuredDefault !== undefined) {
|
||||||
const model = ModelV2.parse(configuredDefault)
|
const model = ModelV2.parse(configuredDefault)
|
||||||
catalog.model.default.set(model.providerID, model.modelID)
|
catalog.model.default.set(model.providerID, model.modelID)
|
||||||
@@ -110,7 +104,6 @@ export const Plugin = define({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}),
|
})
|
||||||
)
|
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -16,12 +16,8 @@ export const Plugin = define({
|
|||||||
const config = yield* Config.Service
|
const config = yield* Config.Service
|
||||||
const location = yield* Location.Service
|
const location = yield* Location.Service
|
||||||
const global = yield* Global.Service
|
const global = yield* Global.Service
|
||||||
yield* ctx.reference.transform(
|
|
||||||
Effect.fn(function* (draft) {
|
|
||||||
const entries = new Map<string, Reference.Source>()
|
const entries = new Map<string, Reference.Source>()
|
||||||
for (const doc of (yield* config.entries()).filter(
|
for (const doc of (yield* config.entries()).filter((entry): entry is Config.Document => entry.type === "document")) {
|
||||||
(entry): entry is Config.Document => entry.type === "document",
|
|
||||||
)) {
|
|
||||||
const directory = doc.path ? path.dirname(doc.path) : location.directory
|
const directory = doc.path ? path.dirname(doc.path) : location.directory
|
||||||
for (const [name, entry] of Object.entries(doc.info.references ?? {})) {
|
for (const [name, entry] of Object.entries(doc.info.references ?? {})) {
|
||||||
if (!validAlias(name)) continue
|
if (!validAlias(name)) continue
|
||||||
@@ -32,9 +28,7 @@ export const Plugin = define({
|
|||||||
local(entry)
|
local(entry)
|
||||||
? Reference.LocalSource.make({
|
? Reference.LocalSource.make({
|
||||||
type: "local",
|
type: "local",
|
||||||
path: AbsolutePath.make(
|
path: AbsolutePath.make(localPath(directory, global.home, typeof entry === "string" ? entry : entry.path)),
|
||||||
localPath(directory, global.home, typeof entry === "string" ? entry : entry.path),
|
|
||||||
),
|
|
||||||
...(description === undefined ? {} : { description }),
|
...(description === undefined ? {} : { description }),
|
||||||
...(hidden === undefined ? {} : { hidden }),
|
...(hidden === undefined ? {} : { hidden }),
|
||||||
})
|
})
|
||||||
@@ -48,9 +42,9 @@ export const Plugin = define({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
yield* ctx.reference.transform((draft) => {
|
||||||
for (const [name, source] of entries) draft.add(name, source)
|
for (const [name, source] of entries) draft.add(name, source)
|
||||||
}),
|
})
|
||||||
)
|
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -15,11 +15,10 @@ export const Plugin = define({
|
|||||||
const config = yield* Config.Service
|
const config = yield* Config.Service
|
||||||
const global = yield* Global.Service
|
const global = yield* Global.Service
|
||||||
const location = yield* Location.Service
|
const location = yield* Location.Service
|
||||||
yield* ctx.skill.transform(
|
|
||||||
Effect.fn(function* (draft) {
|
|
||||||
const entries = yield* config.entries()
|
const entries = yield* config.entries()
|
||||||
const directories = entries.flatMap((entry) => (entry.type === "directory" ? [entry.path] : []))
|
const directories = entries.flatMap((entry) => (entry.type === "directory" ? [entry.path] : []))
|
||||||
const items = entries.flatMap((entry) => (entry.type === "document" ? (entry.info.skills ?? []) : []))
|
const items = entries.flatMap((entry) => (entry.type === "document" ? (entry.info.skills ?? []) : []))
|
||||||
|
yield* ctx.skill.transform((draft) => {
|
||||||
for (const directory of directories) {
|
for (const directory of directories) {
|
||||||
draft.source(
|
draft.source(
|
||||||
SkillV2.DirectorySource.make({ type: "directory", path: AbsolutePath.make(path.join(directory, "skill")) }),
|
SkillV2.DirectorySource.make({ type: "directory", path: AbsolutePath.make(path.join(directory, "skill")) }),
|
||||||
@@ -44,7 +43,6 @@ export const Plugin = define({
|
|||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}),
|
})
|
||||||
)
|
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -52,6 +52,8 @@ export const make = Effect.fn("PluginHost.make")(function* (plugin: PluginV2.Int
|
|||||||
})
|
})
|
||||||
const isCurrentLocation = (ref: Location.Ref) =>
|
const isCurrentLocation = (ref: Location.Ref) =>
|
||||||
ref.directory === location.directory && ref.workspaceID === location.workspaceID
|
ref.directory === location.directory && ref.workspaceID === location.workspaceID
|
||||||
|
const response = <A, E, R>(effect: Effect.Effect<A, E, R>) =>
|
||||||
|
effect.pipe(Effect.map((data) => ({ location: locationInfo(), data })))
|
||||||
|
|
||||||
return {
|
return {
|
||||||
options: {},
|
options: {},
|
||||||
@@ -63,15 +65,15 @@ export const make = Effect.fn("PluginHost.make")(function* (plugin: PluginV2.Int
|
|||||||
},
|
},
|
||||||
reload: agents.reload,
|
reload: agents.reload,
|
||||||
transform: (callback) =>
|
transform: (callback) =>
|
||||||
agents.transform((draft) =>
|
agents.transform((draft) => {
|
||||||
callback({
|
callback({
|
||||||
list: () => mutable(draft.list()),
|
list: () => mutable(draft.list()),
|
||||||
get: (id) => mutable(draft.get(AgentV2.ID.make(id))),
|
get: (id) => mutable(draft.get(AgentV2.ID.make(id))),
|
||||||
default: (id) => draft.default(id === undefined ? undefined : 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),
|
update: (id, update) => draft.update(AgentV2.ID.make(id), update),
|
||||||
remove: (id) => draft.remove(AgentV2.ID.make(id)),
|
remove: (id) => draft.remove(AgentV2.ID.make(id)),
|
||||||
|
})
|
||||||
}),
|
}),
|
||||||
),
|
|
||||||
},
|
},
|
||||||
aisdk: {
|
aisdk: {
|
||||||
sdk: (callback) =>
|
sdk: (callback) =>
|
||||||
@@ -102,9 +104,26 @@ export const make = Effect.fn("PluginHost.make")(function* (plugin: PluginV2.Int
|
|||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
catalog: {
|
catalog: {
|
||||||
|
provider: {
|
||||||
|
list: () => response(catalog.provider.available()),
|
||||||
|
get: (input) =>
|
||||||
|
catalog.provider
|
||||||
|
.get(ProviderV2.ID.make(input.providerID))
|
||||||
|
.pipe(
|
||||||
|
Effect.flatMap((provider) =>
|
||||||
|
provider === undefined
|
||||||
|
? Effect.fail(new Error(`Provider not found: ${input.providerID}`))
|
||||||
|
: response(Effect.succeed(provider)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
model: {
|
||||||
|
list: () => response(catalog.model.available()),
|
||||||
|
default: () => response(catalog.model.default()),
|
||||||
|
},
|
||||||
reload: catalog.reload,
|
reload: catalog.reload,
|
||||||
transform: (callback) =>
|
transform: (callback) =>
|
||||||
catalog.transform((draft) =>
|
catalog.transform((draft) => {
|
||||||
callback({
|
callback({
|
||||||
provider: {
|
provider: {
|
||||||
list: () => mutable(draft.provider.list()),
|
list: () => mutable(draft.provider.list()),
|
||||||
@@ -125,14 +144,39 @@ export const make = Effect.fn("PluginHost.make")(function* (plugin: PluginV2.Int
|
|||||||
draft.model.default.set(ProviderV2.ID.make(providerID), ModelV2.ID.make(modelID)),
|
draft.model.default.set(ProviderV2.ID.make(providerID), ModelV2.ID.make(modelID)),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
})
|
||||||
}),
|
}),
|
||||||
),
|
|
||||||
},
|
},
|
||||||
command: {
|
command: {
|
||||||
|
list: () => response(commands.list()),
|
||||||
reload: commands.reload,
|
reload: commands.reload,
|
||||||
transform: commands.transform,
|
transform: (callback) =>
|
||||||
|
commands.transform((draft) => {
|
||||||
|
callback(draft)
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
integration: {
|
integration: {
|
||||||
|
list: () => response(integration.list()),
|
||||||
|
get: (input) => response(integration.get(Integration.ID.make(input.integrationID))),
|
||||||
|
connectKey: (input) =>
|
||||||
|
integration.connection.key({
|
||||||
|
integrationID: Integration.ID.make(input.integrationID),
|
||||||
|
key: input.key,
|
||||||
|
label: input.label,
|
||||||
|
}),
|
||||||
|
connectOauth: (input) =>
|
||||||
|
response(
|
||||||
|
integration.connection.oauth({
|
||||||
|
integrationID: Integration.ID.make(input.integrationID),
|
||||||
|
methodID: Integration.MethodID.make(input.methodID),
|
||||||
|
inputs: input.inputs,
|
||||||
|
label: input.label,
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
attemptStatus: (input) => response(integration.attempt.status(Integration.AttemptID.make(input.attemptID))),
|
||||||
|
attemptComplete: (input) =>
|
||||||
|
integration.attempt.complete({ attemptID: Integration.AttemptID.make(input.attemptID), code: input.code }),
|
||||||
|
attemptCancel: (input) => integration.attempt.cancel(Integration.AttemptID.make(input.attemptID)),
|
||||||
reload: integration.reload,
|
reload: integration.reload,
|
||||||
connection: {
|
connection: {
|
||||||
active: (id) => integration.connection.active(Integration.ID.make(id)),
|
active: (id) => integration.connection.active(Integration.ID.make(id)),
|
||||||
@@ -142,7 +186,7 @@ export const make = Effect.fn("PluginHost.make")(function* (plugin: PluginV2.Int
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
transform: (callback) =>
|
transform: (callback) =>
|
||||||
integration.transform((draft) =>
|
integration.transform((draft) => {
|
||||||
callback({
|
callback({
|
||||||
list: () => mutable(draft.list()),
|
list: () => mutable(draft.list()),
|
||||||
get: (id) => mutable(draft.get(Integration.ID.make(id))),
|
get: (id) => mutable(draft.get(Integration.ID.make(id))),
|
||||||
@@ -219,33 +263,36 @@ export const make = Effect.fn("PluginHost.make")(function* (plugin: PluginV2.Int
|
|||||||
remove: (id, method) =>
|
remove: (id, method) =>
|
||||||
draft.method.remove(Integration.ID.make(id), Schema.decodeUnknownSync(Integration.Method)(method)),
|
draft.method.remove(Integration.ID.make(id), Schema.decodeUnknownSync(Integration.Method)(method)),
|
||||||
},
|
},
|
||||||
|
})
|
||||||
}),
|
}),
|
||||||
),
|
|
||||||
},
|
},
|
||||||
plugin: {
|
plugin: {
|
||||||
|
list: () => response(plugin.list()),
|
||||||
add: (input) => plugin.add(PluginV2.ID.make(input.id), input.effect),
|
add: (input) => plugin.add(PluginV2.ID.make(input.id), input.effect),
|
||||||
remove: (id) => plugin.remove(PluginV2.ID.make(id)),
|
remove: (id) => plugin.remove(PluginV2.ID.make(id)),
|
||||||
},
|
},
|
||||||
reference: {
|
reference: {
|
||||||
|
list: () => response(reference.list()),
|
||||||
reload: reference.reload,
|
reload: reference.reload,
|
||||||
transform: (callback) =>
|
transform: (callback) =>
|
||||||
reference.transform((draft) =>
|
reference.transform((draft) => {
|
||||||
callback({
|
callback({
|
||||||
add: (name, source) => draft.add(name, Schema.decodeUnknownSync(Reference.Source)(source)),
|
add: (name, source) => draft.add(name, Schema.decodeUnknownSync(Reference.Source)(source)),
|
||||||
remove: draft.remove,
|
remove: draft.remove,
|
||||||
list: draft.list,
|
list: draft.list,
|
||||||
|
})
|
||||||
}),
|
}),
|
||||||
),
|
|
||||||
},
|
},
|
||||||
skill: {
|
skill: {
|
||||||
|
list: () => response(skill.list()),
|
||||||
reload: skill.reload,
|
reload: skill.reload,
|
||||||
transform: (callback) =>
|
transform: (callback) =>
|
||||||
skill.transform((draft) =>
|
skill.transform((draft) => {
|
||||||
callback({
|
callback({
|
||||||
source: (source) => draft.source(Schema.decodeUnknownSync(SkillV2.Source)(source)),
|
source: (source) => draft.source(Schema.decodeUnknownSync(SkillV2.Source)(source)),
|
||||||
list: draft.list,
|
list: draft.list,
|
||||||
|
})
|
||||||
}),
|
}),
|
||||||
),
|
|
||||||
},
|
},
|
||||||
tool: {
|
tool: {
|
||||||
register: (input) => tools.register(input),
|
register: (input) => tools.register(input),
|
||||||
|
|||||||
@@ -201,10 +201,9 @@ export const ModelsDevPlugin = define({
|
|||||||
effect: Effect.fn(function* (ctx) {
|
effect: Effect.fn(function* (ctx) {
|
||||||
const modelsDev = yield* ModelsDev.Service
|
const modelsDev = yield* ModelsDev.Service
|
||||||
const events = yield* EventV2.Service
|
const events = yield* EventV2.Service
|
||||||
yield* ctx.integration.transform(
|
const loaded = { data: yield* modelsDev.get() }
|
||||||
Effect.fn(function* (integrations) {
|
yield* ctx.integration.transform((integrations) => {
|
||||||
const data = yield* modelsDev.get()
|
for (const item of Object.values(loaded.data)) {
|
||||||
for (const item of Object.values(data)) {
|
|
||||||
if (item.env.length === 0) continue
|
if (item.env.length === 0) continue
|
||||||
const integrationID = item.id
|
const integrationID = item.id
|
||||||
integrations.update(integrationID, (integration) => (integration.name = item.name))
|
integrations.update(integrationID, (integration) => (integration.name = item.name))
|
||||||
@@ -217,12 +216,9 @@ export const ModelsDevPlugin = define({
|
|||||||
method: { type: "env", names: [...item.env] },
|
method: { type: "env", names: [...item.env] },
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}),
|
})
|
||||||
)
|
yield* ctx.catalog.transform((catalog) => {
|
||||||
yield* ctx.catalog.transform(
|
for (const item of Object.values(loaded.data)) {
|
||||||
Effect.fn(function* (catalog) {
|
|
||||||
const data = yield* modelsDev.get()
|
|
||||||
for (const item of Object.values(data)) {
|
|
||||||
const providerID = ProviderV2.ID.make(item.id)
|
const providerID = ProviderV2.ID.make(item.id)
|
||||||
catalog.provider.update(providerID, (provider) => {
|
catalog.provider.update(providerID, (provider) => {
|
||||||
provider.name = item.name
|
provider.name = item.name
|
||||||
@@ -255,10 +251,15 @@ export const ModelsDevPlugin = define({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}),
|
})
|
||||||
)
|
|
||||||
yield* events.subscribe(ModelsDev.Event.Refreshed).pipe(
|
yield* events.subscribe(ModelsDev.Event.Refreshed).pipe(
|
||||||
Stream.runForEach(() => ctx.integration.reload().pipe(Effect.andThen(ctx.catalog.reload()))),
|
Stream.runForEach(() =>
|
||||||
|
modelsDev.get().pipe(
|
||||||
|
Effect.tap((data) => Effect.sync(() => (loaded.data = data))),
|
||||||
|
Effect.andThen(ctx.integration.reload()),
|
||||||
|
Effect.andThen(ctx.catalog.reload()),
|
||||||
|
),
|
||||||
|
),
|
||||||
Effect.forkScoped({ startImmediately: true }),
|
Effect.forkScoped({ startImmediately: true }),
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
export * as PluginPromise from "./promise"
|
export * as PluginPromise from "./promise"
|
||||||
|
|
||||||
import { define } from "@opencode-ai/plugin/v2/effect"
|
import { define } from "@opencode-ai/plugin/v2/effect"
|
||||||
import type { Plugin, PluginContext, Registration } from "@opencode-ai/plugin/v2/promise"
|
import type { Plugin, PluginContext } from "@opencode-ai/plugin/v2/promise"
|
||||||
import { Effect, Scope } from "effect"
|
import { Effect, Scope } from "effect"
|
||||||
|
|
||||||
// The Effect host hands back this registration shape; mirror it structurally so
|
|
||||||
// we do not have to alias the Effect package's `Registration` against the Promise one.
|
|
||||||
type HostRegistration = { readonly dispose: Effect.Effect<void> }
|
type HostRegistration = { readonly dispose: Effect.Effect<void> }
|
||||||
|
type Registration = { readonly dispose: () => Promise<void> }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adapts a Promise plugin into an Effect plugin so the existing Effect-only
|
* Adapts a Promise plugin into an Effect plugin so the existing Effect-only
|
||||||
@@ -31,20 +30,23 @@ export function fromPromise(plugin: Plugin) {
|
|||||||
dispose: () => Effect.runPromiseWith(context)(registration.dispose),
|
dispose: () => Effect.runPromiseWith(context)(registration.dispose),
|
||||||
}))
|
}))
|
||||||
|
|
||||||
const run = (effect: Effect.Effect<void>) => Effect.runPromiseWith(context)(effect)
|
const run = <A, E>(effect: Effect.Effect<A, E>) => Effect.runPromiseWith(context)(effect)
|
||||||
|
|
||||||
const transform =
|
const transform =
|
||||||
<Draft>(domain: {
|
<Draft>(domain: {
|
||||||
transform: (
|
transform: (callback: (draft: Draft) => void) => Effect.Effect<HostRegistration, never, Scope.Scope>
|
||||||
callback: (draft: Draft) => Effect.Effect<void> | void,
|
|
||||||
) => Effect.Effect<HostRegistration, never, Scope.Scope>
|
|
||||||
}) =>
|
}) =>
|
||||||
(callback: (draft: Draft) => Promise<void> | void) =>
|
(callback: (draft: Draft) => void) =>
|
||||||
register(domain.transform((draft) => Effect.promise(() => Promise.resolve(callback(draft)))))
|
register(
|
||||||
|
domain.transform((draft) => {
|
||||||
|
callback(draft)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
const context2: PluginContext = {
|
const context2: PluginContext = {
|
||||||
options: host.options,
|
options: host.options,
|
||||||
agent: {
|
agent: {
|
||||||
|
list: (input) => run(host.agent.list(input)),
|
||||||
transform: transform(host.agent),
|
transform: transform(host.agent),
|
||||||
reload: () => run(host.agent.reload()),
|
reload: () => run(host.agent.reload()),
|
||||||
},
|
},
|
||||||
@@ -55,14 +57,30 @@ export function fromPromise(plugin: Plugin) {
|
|||||||
register(host.aisdk.language((event) => Effect.promise(() => Promise.resolve(callback(event))))),
|
register(host.aisdk.language((event) => Effect.promise(() => Promise.resolve(callback(event))))),
|
||||||
},
|
},
|
||||||
catalog: {
|
catalog: {
|
||||||
|
provider: {
|
||||||
|
list: (input) => run(host.catalog.provider.list(input)),
|
||||||
|
get: (input) => run(host.catalog.provider.get(input)),
|
||||||
|
},
|
||||||
|
model: {
|
||||||
|
list: (input) => run(host.catalog.model.list(input)),
|
||||||
|
default: (input) => run(host.catalog.model.default(input)),
|
||||||
|
},
|
||||||
transform: transform(host.catalog),
|
transform: transform(host.catalog),
|
||||||
reload: () => run(host.catalog.reload()),
|
reload: () => run(host.catalog.reload()),
|
||||||
},
|
},
|
||||||
command: {
|
command: {
|
||||||
|
list: (input) => run(host.command.list(input)),
|
||||||
transform: transform(host.command),
|
transform: transform(host.command),
|
||||||
reload: () => run(host.command.reload()),
|
reload: () => run(host.command.reload()),
|
||||||
},
|
},
|
||||||
integration: {
|
integration: {
|
||||||
|
list: (input) => run(host.integration.list(input)),
|
||||||
|
get: (input) => run(host.integration.get(input)),
|
||||||
|
connectKey: (input) => run(host.integration.connectKey(input)),
|
||||||
|
connectOauth: (input) => run(host.integration.connectOauth(input)),
|
||||||
|
attemptStatus: (input) => run(host.integration.attemptStatus(input)),
|
||||||
|
attemptComplete: (input) => run(host.integration.attemptComplete(input)),
|
||||||
|
attemptCancel: (input) => run(host.integration.attemptCancel(input)),
|
||||||
transform: transform(host.integration),
|
transform: transform(host.integration),
|
||||||
reload: () => run(host.integration.reload()),
|
reload: () => run(host.integration.reload()),
|
||||||
connection: {
|
connection: {
|
||||||
@@ -71,6 +89,7 @@ export function fromPromise(plugin: Plugin) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
plugin: {
|
plugin: {
|
||||||
|
list: (input) => run(host.plugin.list(input)),
|
||||||
add: (input) => {
|
add: (input) => {
|
||||||
const child = fromPromise(input)
|
const child = fromPromise(input)
|
||||||
return run(host.plugin.add(child))
|
return run(host.plugin.add(child))
|
||||||
@@ -78,13 +97,22 @@ export function fromPromise(plugin: Plugin) {
|
|||||||
remove: (id) => run(host.plugin.remove(id)),
|
remove: (id) => run(host.plugin.remove(id)),
|
||||||
},
|
},
|
||||||
reference: {
|
reference: {
|
||||||
|
list: (input) => run(host.reference.list(input)),
|
||||||
transform: transform(host.reference),
|
transform: transform(host.reference),
|
||||||
reload: () => run(host.reference.reload()),
|
reload: () => run(host.reference.reload()),
|
||||||
},
|
},
|
||||||
skill: {
|
skill: {
|
||||||
|
list: (input) => run(host.skill.list(input)),
|
||||||
transform: transform(host.skill),
|
transform: transform(host.skill),
|
||||||
reload: () => run(host.skill.reload()),
|
reload: () => run(host.skill.reload()),
|
||||||
},
|
},
|
||||||
|
session: {
|
||||||
|
create: (input) => run(host.session.create(input)),
|
||||||
|
get: (input) => run(host.session.get(input)),
|
||||||
|
prompt: (input) => run(host.session.prompt(input)),
|
||||||
|
command: (input) => run(host.session.command(input)),
|
||||||
|
interrupt: (input) => run(host.session.interrupt(input)),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
yield* Effect.promise(() => Promise.resolve(plugin.setup(context2)))
|
yield* Effect.promise(() => Promise.resolve(plugin.setup(context2)))
|
||||||
|
|||||||
@@ -62,8 +62,7 @@ function selectMantleModel(sdk: MantleSDK, modelID: string) {
|
|||||||
export const AmazonBedrockPlugin = define({
|
export const AmazonBedrockPlugin = define({
|
||||||
id: "amazon-bedrock",
|
id: "amazon-bedrock",
|
||||||
effect: Effect.fn(function* (ctx) {
|
effect: Effect.fn(function* (ctx) {
|
||||||
yield* ctx.catalog.transform(
|
yield* ctx.catalog.transform((evt) => {
|
||||||
Effect.fn(function* (evt) {
|
|
||||||
for (const item of evt.provider.list()) {
|
for (const item of evt.provider.list()) {
|
||||||
if (item.provider.api.type !== "aisdk") continue
|
if (item.provider.api.type !== "aisdk") continue
|
||||||
if (item.provider.api.package !== "@ai-sdk/amazon-bedrock") continue
|
if (item.provider.api.package !== "@ai-sdk/amazon-bedrock") continue
|
||||||
@@ -76,8 +75,7 @@ export const AmazonBedrockPlugin = define({
|
|||||||
delete provider.request.body.endpoint
|
delete provider.request.body.endpoint
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}),
|
})
|
||||||
)
|
|
||||||
yield* ctx.aisdk.sdk(
|
yield* ctx.aisdk.sdk(
|
||||||
Effect.fn(function* (evt) {
|
Effect.fn(function* (evt) {
|
||||||
if (!["@ai-sdk/amazon-bedrock", "@ai-sdk/amazon-bedrock/mantle"].includes(evt.package)) return
|
if (!["@ai-sdk/amazon-bedrock", "@ai-sdk/amazon-bedrock/mantle"].includes(evt.package)) return
|
||||||
|
|||||||
@@ -4,8 +4,7 @@ import { define } from "../internal"
|
|||||||
export const AnthropicPlugin = define({
|
export const AnthropicPlugin = define({
|
||||||
id: "anthropic",
|
id: "anthropic",
|
||||||
effect: Effect.fn(function* (ctx) {
|
effect: Effect.fn(function* (ctx) {
|
||||||
yield* ctx.catalog.transform(
|
yield* ctx.catalog.transform((evt) => {
|
||||||
Effect.fn(function* (evt) {
|
|
||||||
for (const item of evt.provider.list()) {
|
for (const item of evt.provider.list()) {
|
||||||
if (item.provider.api.type !== "aisdk") continue
|
if (item.provider.api.type !== "aisdk") continue
|
||||||
if (item.provider.api.package !== "@ai-sdk/anthropic") continue
|
if (item.provider.api.package !== "@ai-sdk/anthropic") continue
|
||||||
@@ -14,8 +13,7 @@ export const AnthropicPlugin = define({
|
|||||||
"interleaved-thinking-2025-05-14,fine-grained-tool-streaming-2025-05-14"
|
"interleaved-thinking-2025-05-14,fine-grained-tool-streaming-2025-05-14"
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}),
|
})
|
||||||
)
|
|
||||||
yield* ctx.aisdk.sdk(
|
yield* ctx.aisdk.sdk(
|
||||||
Effect.fn(function* (evt) {
|
Effect.fn(function* (evt) {
|
||||||
if (evt.package !== "@ai-sdk/anthropic") return
|
if (evt.package !== "@ai-sdk/anthropic") return
|
||||||
|
|||||||
@@ -13,8 +13,7 @@ function selectLanguage(sdk: any, modelID: string, useChat: boolean) {
|
|||||||
export const AzurePlugin = define({
|
export const AzurePlugin = define({
|
||||||
id: "azure",
|
id: "azure",
|
||||||
effect: Effect.fn(function* (ctx) {
|
effect: Effect.fn(function* (ctx) {
|
||||||
yield* ctx.catalog.transform(
|
yield* ctx.catalog.transform((evt) => {
|
||||||
Effect.fn(function* (evt) {
|
|
||||||
for (const item of evt.provider.list()) {
|
for (const item of evt.provider.list()) {
|
||||||
if (item.provider.api.type !== "aisdk") continue
|
if (item.provider.api.type !== "aisdk") continue
|
||||||
if (item.provider.api.package !== "@ai-sdk/azure") continue
|
if (item.provider.api.package !== "@ai-sdk/azure") continue
|
||||||
@@ -26,8 +25,7 @@ export const AzurePlugin = define({
|
|||||||
provider.request.body.resourceName = resourceName
|
provider.request.body.resourceName = resourceName
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}),
|
})
|
||||||
)
|
|
||||||
yield* ctx.aisdk.sdk(
|
yield* ctx.aisdk.sdk(
|
||||||
Effect.fn(function* (evt) {
|
Effect.fn(function* (evt) {
|
||||||
if (evt.package !== "@ai-sdk/azure") return
|
if (evt.package !== "@ai-sdk/azure") return
|
||||||
@@ -58,8 +56,7 @@ export const AzurePlugin = define({
|
|||||||
export const AzureCognitiveServicesPlugin = define({
|
export const AzureCognitiveServicesPlugin = define({
|
||||||
id: "azure-cognitive-services",
|
id: "azure-cognitive-services",
|
||||||
effect: Effect.fn(function* (ctx) {
|
effect: Effect.fn(function* (ctx) {
|
||||||
yield* ctx.catalog.transform(
|
yield* ctx.catalog.transform((evt) => {
|
||||||
Effect.fn(function* (evt) {
|
|
||||||
const resourceName = process.env.AZURE_COGNITIVE_SERVICES_RESOURCE_NAME
|
const resourceName = process.env.AZURE_COGNITIVE_SERVICES_RESOURCE_NAME
|
||||||
if (!resourceName) return
|
if (!resourceName) return
|
||||||
for (const item of evt.provider.list()) {
|
for (const item of evt.provider.list()) {
|
||||||
@@ -70,8 +67,7 @@ export const AzureCognitiveServicesPlugin = define({
|
|||||||
provider.request.body.baseURL = `https://${resourceName}.cognitiveservices.azure.com/openai`
|
provider.request.body.baseURL = `https://${resourceName}.cognitiveservices.azure.com/openai`
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}),
|
})
|
||||||
)
|
|
||||||
yield* ctx.aisdk.language(
|
yield* ctx.aisdk.language(
|
||||||
Effect.fn(function* (evt) {
|
Effect.fn(function* (evt) {
|
||||||
if (evt.model.providerID !== ProviderV2.ID.make("azure-cognitive-services")) return
|
if (evt.model.providerID !== ProviderV2.ID.make("azure-cognitive-services")) return
|
||||||
|
|||||||
@@ -4,8 +4,7 @@ import { define } from "../internal"
|
|||||||
export const CerebrasPlugin = define({
|
export const CerebrasPlugin = define({
|
||||||
id: "cerebras",
|
id: "cerebras",
|
||||||
effect: Effect.fn(function* (ctx) {
|
effect: Effect.fn(function* (ctx) {
|
||||||
yield* ctx.catalog.transform(
|
yield* ctx.catalog.transform((evt) => {
|
||||||
Effect.fn(function* (evt) {
|
|
||||||
for (const item of evt.provider.list()) {
|
for (const item of evt.provider.list()) {
|
||||||
if (item.provider.api.type !== "aisdk") continue
|
if (item.provider.api.type !== "aisdk") continue
|
||||||
if (item.provider.api.package !== "@ai-sdk/cerebras") continue
|
if (item.provider.api.package !== "@ai-sdk/cerebras") continue
|
||||||
@@ -13,8 +12,7 @@ export const CerebrasPlugin = define({
|
|||||||
provider.request.headers["X-Cerebras-3rd-Party-Integration"] = "opencode"
|
provider.request.headers["X-Cerebras-3rd-Party-Integration"] = "opencode"
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}),
|
})
|
||||||
)
|
|
||||||
yield* ctx.aisdk.sdk(
|
yield* ctx.aisdk.sdk(
|
||||||
Effect.fn(function* (evt) {
|
Effect.fn(function* (evt) {
|
||||||
if (evt.package !== "@ai-sdk/cerebras") return
|
if (evt.package !== "@ai-sdk/cerebras") return
|
||||||
|
|||||||
@@ -9,8 +9,7 @@ const providerID = ProviderV2.ID.make("cloudflare-workers-ai")
|
|||||||
export const CloudflareWorkersAIPlugin = define({
|
export const CloudflareWorkersAIPlugin = define({
|
||||||
id: "cloudflare-workers-ai",
|
id: "cloudflare-workers-ai",
|
||||||
effect: Effect.fn(function* (ctx) {
|
effect: Effect.fn(function* (ctx) {
|
||||||
yield* ctx.catalog.transform(
|
yield* ctx.catalog.transform((evt) => {
|
||||||
Effect.fn(function* (evt) {
|
|
||||||
const item = evt.provider.get(providerID)
|
const item = evt.provider.get(providerID)
|
||||||
if (!item) return
|
if (!item) return
|
||||||
evt.provider.update(item.provider.id, (provider) => {
|
evt.provider.update(item.provider.id, (provider) => {
|
||||||
@@ -19,8 +18,7 @@ export const CloudflareWorkersAIPlugin = define({
|
|||||||
const accountId = resolveAccountId(provider.request.body)
|
const accountId = resolveAccountId(provider.request.body)
|
||||||
if (accountId) provider.api.url = workersEndpoint(accountId)
|
if (accountId) provider.api.url = workersEndpoint(accountId)
|
||||||
})
|
})
|
||||||
}),
|
})
|
||||||
)
|
|
||||||
yield* ctx.aisdk.sdk(
|
yield* ctx.aisdk.sdk(
|
||||||
Effect.fn(function* (evt) {
|
Effect.fn(function* (evt) {
|
||||||
if (evt.model.providerID !== providerID) return
|
if (evt.model.providerID !== providerID) return
|
||||||
|
|||||||
@@ -14,8 +14,7 @@ function shouldUseResponses(modelID: string) {
|
|||||||
export const GithubCopilotPlugin = define({
|
export const GithubCopilotPlugin = define({
|
||||||
id: "github-copilot",
|
id: "github-copilot",
|
||||||
effect: Effect.fn(function* (ctx) {
|
effect: Effect.fn(function* (ctx) {
|
||||||
yield* ctx.catalog.transform(
|
yield* ctx.catalog.transform((evt) => {
|
||||||
Effect.fn(function* (evt) {
|
|
||||||
const item = evt.provider.get(ProviderV2.ID.githubCopilot)
|
const item = evt.provider.get(ProviderV2.ID.githubCopilot)
|
||||||
if (!item || !item.models.has(ModelV2.ID.make("gpt-5-chat-latest"))) return
|
if (!item || !item.models.has(ModelV2.ID.make("gpt-5-chat-latest"))) return
|
||||||
evt.model.update(item.provider.id, ModelV2.ID.make("gpt-5-chat-latest"), (model) => {
|
evt.model.update(item.provider.id, ModelV2.ID.make("gpt-5-chat-latest"), (model) => {
|
||||||
@@ -23,8 +22,7 @@ export const GithubCopilotPlugin = define({
|
|||||||
// so hide it only for Copilot rather than for every provider catalog.
|
// so hide it only for Copilot rather than for every provider catalog.
|
||||||
model.enabled = false
|
model.enabled = false
|
||||||
})
|
})
|
||||||
}),
|
})
|
||||||
)
|
|
||||||
yield* ctx.aisdk.sdk(
|
yield* ctx.aisdk.sdk(
|
||||||
Effect.fn(function* (evt) {
|
Effect.fn(function* (evt) {
|
||||||
if (evt.package !== "@ai-sdk/github-copilot") return
|
if (evt.package !== "@ai-sdk/github-copilot") return
|
||||||
|
|||||||
@@ -57,8 +57,7 @@ function authFetch(fetchWithRuntimeOptions?: unknown) {
|
|||||||
export const GoogleVertexPlugin = define({
|
export const GoogleVertexPlugin = define({
|
||||||
id: "google-vertex",
|
id: "google-vertex",
|
||||||
effect: Effect.fn(function* (ctx) {
|
effect: Effect.fn(function* (ctx) {
|
||||||
yield* ctx.catalog.transform(
|
yield* ctx.catalog.transform((evt) => {
|
||||||
Effect.fn(function* (evt) {
|
|
||||||
for (const item of evt.provider.list()) {
|
for (const item of evt.provider.list()) {
|
||||||
if (item.provider.api.type !== "aisdk") continue
|
if (item.provider.api.type !== "aisdk") continue
|
||||||
if (
|
if (
|
||||||
@@ -82,8 +81,7 @@ export const GoogleVertexPlugin = define({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}),
|
})
|
||||||
)
|
|
||||||
yield* ctx.aisdk.sdk(
|
yield* ctx.aisdk.sdk(
|
||||||
Effect.fn(function* (evt) {
|
Effect.fn(function* (evt) {
|
||||||
if (evt.model.providerID === ProviderV2.ID.googleVertex && evt.package.includes("@ai-sdk/openai-compatible")) {
|
if (evt.model.providerID === ProviderV2.ID.googleVertex && evt.package.includes("@ai-sdk/openai-compatible")) {
|
||||||
@@ -115,8 +113,7 @@ export const GoogleVertexPlugin = define({
|
|||||||
export const GoogleVertexAnthropicPlugin = define({
|
export const GoogleVertexAnthropicPlugin = define({
|
||||||
id: "google-vertex-anthropic",
|
id: "google-vertex-anthropic",
|
||||||
effect: Effect.fn(function* (ctx) {
|
effect: Effect.fn(function* (ctx) {
|
||||||
yield* ctx.catalog.transform(
|
yield* ctx.catalog.transform((evt) => {
|
||||||
Effect.fn(function* (evt) {
|
|
||||||
for (const item of evt.provider.list()) {
|
for (const item of evt.provider.list()) {
|
||||||
if (item.provider.api.type !== "aisdk") continue
|
if (item.provider.api.type !== "aisdk") continue
|
||||||
if (item.provider.api.package !== "@ai-sdk/google-vertex/anthropic") continue
|
if (item.provider.api.package !== "@ai-sdk/google-vertex/anthropic") continue
|
||||||
@@ -135,8 +132,7 @@ export const GoogleVertexAnthropicPlugin = define({
|
|||||||
provider.request.body.location = location
|
provider.request.body.location = location
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}),
|
})
|
||||||
)
|
|
||||||
yield* ctx.aisdk.sdk(
|
yield* ctx.aisdk.sdk(
|
||||||
Effect.fn(function* (evt) {
|
Effect.fn(function* (evt) {
|
||||||
if (evt.package !== "@ai-sdk/google-vertex/anthropic") return
|
if (evt.package !== "@ai-sdk/google-vertex/anthropic") return
|
||||||
|
|||||||
@@ -4,8 +4,7 @@ import { define } from "../internal"
|
|||||||
export const KiloPlugin = define({
|
export const KiloPlugin = define({
|
||||||
id: "kilo",
|
id: "kilo",
|
||||||
effect: Effect.fn(function* (ctx) {
|
effect: Effect.fn(function* (ctx) {
|
||||||
yield* ctx.catalog.transform(
|
yield* ctx.catalog.transform((evt) => {
|
||||||
Effect.fn(function* (evt) {
|
|
||||||
for (const item of evt.provider.list()) {
|
for (const item of evt.provider.list()) {
|
||||||
if (item.provider.api.type !== "aisdk") continue
|
if (item.provider.api.type !== "aisdk") continue
|
||||||
if (item.provider.api.package !== "@ai-sdk/openai-compatible") continue
|
if (item.provider.api.package !== "@ai-sdk/openai-compatible") continue
|
||||||
@@ -15,7 +14,6 @@ export const KiloPlugin = define({
|
|||||||
provider.request.headers["X-Title"] = "opencode"
|
provider.request.headers["X-Title"] = "opencode"
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}),
|
})
|
||||||
)
|
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -6,21 +6,20 @@ export const LLMGatewayPlugin = define({
|
|||||||
id: "llmgateway",
|
id: "llmgateway",
|
||||||
effect: Effect.fn(function* (ctx) {
|
effect: Effect.fn(function* (ctx) {
|
||||||
const integrations = yield* Integration.Service
|
const integrations = yield* Integration.Service
|
||||||
yield* ctx.catalog.transform(
|
const configured = new Set((yield* integrations.list()).map((integration) => integration.id))
|
||||||
Effect.fn(function* (evt) {
|
yield* ctx.catalog.transform((evt) => {
|
||||||
for (const item of evt.provider.list()) {
|
for (const item of evt.provider.list()) {
|
||||||
if (item.provider.disabled) continue
|
if (item.provider.disabled) continue
|
||||||
if (item.provider.api.type !== "aisdk") continue
|
if (item.provider.api.type !== "aisdk") continue
|
||||||
if (item.provider.api.package !== "@ai-sdk/openai-compatible") continue
|
if (item.provider.api.package !== "@ai-sdk/openai-compatible") continue
|
||||||
if (item.provider.api.url !== "https://api.llmgateway.io/v1") continue
|
if (item.provider.api.url !== "https://api.llmgateway.io/v1") continue
|
||||||
if (!(yield* integrations.get(Integration.ID.make(item.provider.id)))) continue
|
if (!configured.has(Integration.ID.make(item.provider.id))) continue
|
||||||
evt.provider.update(item.provider.id, (provider) => {
|
evt.provider.update(item.provider.id, (provider) => {
|
||||||
provider.request.headers["HTTP-Referer"] = "https://opencode.ai/"
|
provider.request.headers["HTTP-Referer"] = "https://opencode.ai/"
|
||||||
provider.request.headers["X-Title"] = "opencode"
|
provider.request.headers["X-Title"] = "opencode"
|
||||||
provider.request.headers["X-Source"] = "opencode"
|
provider.request.headers["X-Source"] = "opencode"
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}),
|
})
|
||||||
)
|
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -4,8 +4,7 @@ import { define } from "../internal"
|
|||||||
export const NvidiaPlugin = define({
|
export const NvidiaPlugin = define({
|
||||||
id: "nvidia",
|
id: "nvidia",
|
||||||
effect: Effect.fn(function* (ctx) {
|
effect: Effect.fn(function* (ctx) {
|
||||||
yield* ctx.catalog.transform(
|
yield* ctx.catalog.transform((evt) => {
|
||||||
Effect.fn(function* (evt) {
|
|
||||||
for (const item of evt.provider.list()) {
|
for (const item of evt.provider.list()) {
|
||||||
if (item.provider.api.type !== "aisdk") continue
|
if (item.provider.api.type !== "aisdk") continue
|
||||||
if (item.provider.api.package !== "@ai-sdk/openai-compatible") continue
|
if (item.provider.api.package !== "@ai-sdk/openai-compatible") continue
|
||||||
@@ -16,7 +15,6 @@ export const NvidiaPlugin = define({
|
|||||||
provider.request.headers["X-BILLING-INVOKE-ORIGIN"] ??= "OpenCode"
|
provider.request.headers["X-BILLING-INVOKE-ORIGIN"] ??= "OpenCode"
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}),
|
})
|
||||||
)
|
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -177,8 +177,7 @@ export const OpenAIPlugin = define({
|
|||||||
draft.method.update(browser)
|
draft.method.update(browser)
|
||||||
draft.method.update(headless)
|
draft.method.update(headless)
|
||||||
})
|
})
|
||||||
yield* ctx.catalog.transform(
|
yield* ctx.catalog.transform((evt) => {
|
||||||
Effect.fn(function* (evt) {
|
|
||||||
for (const item of evt.provider.list()) {
|
for (const item of evt.provider.list()) {
|
||||||
if (item.provider.api.type !== "aisdk") continue
|
if (item.provider.api.type !== "aisdk") continue
|
||||||
if (item.provider.api.package !== "@ai-sdk/openai") continue
|
if (item.provider.api.package !== "@ai-sdk/openai") continue
|
||||||
@@ -203,8 +202,7 @@ export const OpenAIPlugin = define({
|
|||||||
draft.cost = []
|
draft.cost = []
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}),
|
})
|
||||||
)
|
|
||||||
|
|
||||||
const refresh = () => loading.withPermit(load().pipe(Effect.andThen(ctx.catalog.reload())))
|
const refresh = () => loading.withPermit(load().pipe(Effect.andThen(ctx.catalog.reload())))
|
||||||
yield* events.subscribe(Integration.Event.ConnectionUpdated).pipe(
|
yield* events.subscribe(Integration.Event.ConnectionUpdated).pipe(
|
||||||
|
|||||||
@@ -5,8 +5,7 @@ import { define } from "../internal"
|
|||||||
export const OpenRouterPlugin = define({
|
export const OpenRouterPlugin = define({
|
||||||
id: "openrouter",
|
id: "openrouter",
|
||||||
effect: Effect.fn(function* (ctx) {
|
effect: Effect.fn(function* (ctx) {
|
||||||
yield* ctx.catalog.transform(
|
yield* ctx.catalog.transform((evt) => {
|
||||||
Effect.fn(function* (evt) {
|
|
||||||
for (const item of evt.provider.list()) {
|
for (const item of evt.provider.list()) {
|
||||||
if (item.provider.api.type !== "aisdk") continue
|
if (item.provider.api.type !== "aisdk") continue
|
||||||
if (item.provider.api.package !== "@openrouter/ai-sdk-provider") continue
|
if (item.provider.api.package !== "@openrouter/ai-sdk-provider") continue
|
||||||
@@ -23,8 +22,7 @@ export const OpenRouterPlugin = define({
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}),
|
})
|
||||||
)
|
|
||||||
yield* ctx.aisdk.sdk(
|
yield* ctx.aisdk.sdk(
|
||||||
Effect.fn(function* (evt) {
|
Effect.fn(function* (evt) {
|
||||||
if (evt.package !== "@openrouter/ai-sdk-provider") return
|
if (evt.package !== "@openrouter/ai-sdk-provider") return
|
||||||
|
|||||||
@@ -4,8 +4,7 @@ import { define } from "../internal"
|
|||||||
export const VercelPlugin = define({
|
export const VercelPlugin = define({
|
||||||
id: "vercel",
|
id: "vercel",
|
||||||
effect: Effect.fn(function* (ctx) {
|
effect: Effect.fn(function* (ctx) {
|
||||||
yield* ctx.catalog.transform(
|
yield* ctx.catalog.transform((evt) => {
|
||||||
Effect.fn(function* (evt) {
|
|
||||||
for (const item of evt.provider.list()) {
|
for (const item of evt.provider.list()) {
|
||||||
if (item.provider.api.type !== "aisdk") continue
|
if (item.provider.api.type !== "aisdk") continue
|
||||||
if (item.provider.api.package !== "@ai-sdk/vercel") continue
|
if (item.provider.api.package !== "@ai-sdk/vercel") continue
|
||||||
@@ -14,8 +13,7 @@ export const VercelPlugin = define({
|
|||||||
provider.request.headers["x-title"] = "opencode"
|
provider.request.headers["x-title"] = "opencode"
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}),
|
})
|
||||||
)
|
|
||||||
yield* ctx.aisdk.sdk(
|
yield* ctx.aisdk.sdk(
|
||||||
Effect.fn(function* (evt) {
|
Effect.fn(function* (evt) {
|
||||||
if (evt.package !== "@ai-sdk/vercel") return
|
if (evt.package !== "@ai-sdk/vercel") return
|
||||||
|
|||||||
@@ -4,8 +4,7 @@ import { define } from "../internal"
|
|||||||
export const ZenmuxPlugin = define({
|
export const ZenmuxPlugin = define({
|
||||||
id: "zenmux",
|
id: "zenmux",
|
||||||
effect: Effect.fn(function* (ctx) {
|
effect: Effect.fn(function* (ctx) {
|
||||||
yield* ctx.catalog.transform(
|
yield* ctx.catalog.transform((evt) => {
|
||||||
Effect.fn(function* (evt) {
|
|
||||||
for (const item of evt.provider.list()) {
|
for (const item of evt.provider.list()) {
|
||||||
if (item.provider.api.type !== "aisdk") continue
|
if (item.provider.api.type !== "aisdk") continue
|
||||||
if (item.provider.api.package !== "@ai-sdk/openai-compatible") continue
|
if (item.provider.api.package !== "@ai-sdk/openai-compatible") continue
|
||||||
@@ -15,7 +14,6 @@ export const ZenmuxPlugin = define({
|
|||||||
provider.request.headers["X-Title"] ??= "opencode"
|
provider.request.headers["X-Title"] ??= "opencode"
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}),
|
})
|
||||||
)
|
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -53,7 +53,15 @@ Review files`,
|
|||||||
})
|
})
|
||||||
|
|
||||||
const command = yield* CommandV2.Service
|
const command = yield* CommandV2.Service
|
||||||
yield* ConfigCommandPlugin.Plugin.effect(host({ command: { ...command, reload: command.reload } })).pipe(
|
yield* ConfigCommandPlugin.Plugin.effect(
|
||||||
|
host({
|
||||||
|
command: {
|
||||||
|
list: () => Effect.die("unused command.list"),
|
||||||
|
transform: command.transform,
|
||||||
|
reload: command.reload,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
).pipe(
|
||||||
Effect.provideService(
|
Effect.provideService(
|
||||||
Config.Service,
|
Config.Service,
|
||||||
Config.Service.of({
|
Config.Service.of({
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ describe("ConfigSkillPlugin.Plugin", () => {
|
|||||||
|
|
||||||
yield* ConfigSkillPlugin.Plugin.effect(
|
yield* ConfigSkillPlugin.Plugin.effect(
|
||||||
host({
|
host({
|
||||||
skill: { transform, reload: () => Effect.void },
|
skill: { list: () => Effect.die("unused skill.list"), transform, reload: () => Effect.void },
|
||||||
}),
|
}),
|
||||||
).pipe(
|
).pipe(
|
||||||
Effect.provideService(Global.Service, Global.Service.of({ ...Global.make(), home: "/home/test" })),
|
Effect.provideService(Global.Service, Global.Service.of({ ...Global.make(), home: "/home/test" })),
|
||||||
|
|||||||
@@ -23,7 +23,11 @@ describe("CommandPlugin.Plugin", () => {
|
|||||||
const command = yield* CommandV2.Service
|
const command = yield* CommandV2.Service
|
||||||
yield* CommandPlugin.Plugin.effect(
|
yield* CommandPlugin.Plugin.effect(
|
||||||
host({
|
host({
|
||||||
command: { transform: command.transform, reload: command.reload },
|
command: {
|
||||||
|
list: () => Effect.die("unused command.list"),
|
||||||
|
transform: command.transform,
|
||||||
|
reload: command.reload,
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
).pipe(
|
).pipe(
|
||||||
Effect.provideService(
|
Effect.provideService(
|
||||||
|
|||||||
@@ -23,14 +23,30 @@ export function host(overrides: Overrides = {}): PluginContext {
|
|||||||
language: () => Effect.die("unused aisdk.language"),
|
language: () => Effect.die("unused aisdk.language"),
|
||||||
},
|
},
|
||||||
catalog: overrides.catalog ?? {
|
catalog: overrides.catalog ?? {
|
||||||
|
provider: {
|
||||||
|
list: () => Effect.die("unused catalog.provider.list"),
|
||||||
|
get: () => Effect.die("unused catalog.provider.get"),
|
||||||
|
},
|
||||||
|
model: {
|
||||||
|
list: () => Effect.die("unused catalog.model.list"),
|
||||||
|
default: () => Effect.die("unused catalog.model.default"),
|
||||||
|
},
|
||||||
transform: () => Effect.die("unused catalog.transform"),
|
transform: () => Effect.die("unused catalog.transform"),
|
||||||
reload: () => Effect.die("unused catalog.reload"),
|
reload: () => Effect.die("unused catalog.reload"),
|
||||||
},
|
},
|
||||||
command: overrides.command ?? {
|
command: overrides.command ?? {
|
||||||
|
list: () => Effect.die("unused command.list"),
|
||||||
transform: () => Effect.die("unused command.transform"),
|
transform: () => Effect.die("unused command.transform"),
|
||||||
reload: () => Effect.die("unused command.reload"),
|
reload: () => Effect.die("unused command.reload"),
|
||||||
},
|
},
|
||||||
integration: overrides.integration ?? {
|
integration: overrides.integration ?? {
|
||||||
|
list: () => Effect.die("unused integration.list"),
|
||||||
|
get: () => Effect.die("unused integration.get"),
|
||||||
|
connectKey: () => Effect.die("unused integration.connectKey"),
|
||||||
|
connectOauth: () => Effect.die("unused integration.connectOauth"),
|
||||||
|
attemptStatus: () => Effect.die("unused integration.attemptStatus"),
|
||||||
|
attemptComplete: () => Effect.die("unused integration.attemptComplete"),
|
||||||
|
attemptCancel: () => Effect.die("unused integration.attemptCancel"),
|
||||||
transform: () => Effect.die("unused integration.transform"),
|
transform: () => Effect.die("unused integration.transform"),
|
||||||
reload: () => Effect.die("unused integration.reload"),
|
reload: () => Effect.die("unused integration.reload"),
|
||||||
connection: {
|
connection: {
|
||||||
@@ -39,14 +55,17 @@ export function host(overrides: Overrides = {}): PluginContext {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
plugin: overrides.plugin ?? {
|
plugin: overrides.plugin ?? {
|
||||||
|
list: () => Effect.die("unused plugin.list"),
|
||||||
add: () => Effect.die("unused plugin.add"),
|
add: () => Effect.die("unused plugin.add"),
|
||||||
remove: () => Effect.die("unused plugin.remove"),
|
remove: () => Effect.die("unused plugin.remove"),
|
||||||
},
|
},
|
||||||
reference: overrides.reference ?? {
|
reference: overrides.reference ?? {
|
||||||
|
list: () => Effect.die("unused reference.list"),
|
||||||
transform: () => Effect.die("unused reference.transform"),
|
transform: () => Effect.die("unused reference.transform"),
|
||||||
reload: () => Effect.die("unused reference.reload"),
|
reload: () => Effect.die("unused reference.reload"),
|
||||||
},
|
},
|
||||||
skill: overrides.skill ?? {
|
skill: overrides.skill ?? {
|
||||||
|
list: () => Effect.die("unused skill.list"),
|
||||||
transform: () => Effect.die("unused skill.transform"),
|
transform: () => Effect.die("unused skill.transform"),
|
||||||
reload: () => Effect.die("unused skill.reload"),
|
reload: () => Effect.die("unused skill.reload"),
|
||||||
},
|
},
|
||||||
@@ -94,6 +113,14 @@ export function agentHost(agent: AgentV2.Interface): PluginContext["agent"] {
|
|||||||
|
|
||||||
export function catalogHost(catalog: Catalog.Interface): PluginContext["catalog"] {
|
export function catalogHost(catalog: Catalog.Interface): PluginContext["catalog"] {
|
||||||
return {
|
return {
|
||||||
|
provider: {
|
||||||
|
list: () => Effect.die("unused catalog.provider.list"),
|
||||||
|
get: () => Effect.die("unused catalog.provider.get"),
|
||||||
|
},
|
||||||
|
model: {
|
||||||
|
list: () => Effect.die("unused catalog.model.list"),
|
||||||
|
default: () => Effect.die("unused catalog.model.default"),
|
||||||
|
},
|
||||||
reload: catalog.reload,
|
reload: catalog.reload,
|
||||||
transform: (callback) =>
|
transform: (callback) =>
|
||||||
catalog.transform((draft) =>
|
catalog.transform((draft) =>
|
||||||
@@ -158,6 +185,13 @@ export function catalogHost(catalog: Catalog.Interface): PluginContext["catalog"
|
|||||||
|
|
||||||
export function integrationHost(integration: Integration.Interface): PluginContext["integration"] {
|
export function integrationHost(integration: Integration.Interface): PluginContext["integration"] {
|
||||||
return {
|
return {
|
||||||
|
list: () => Effect.die("unused integration.list"),
|
||||||
|
get: () => Effect.die("unused integration.get"),
|
||||||
|
connectKey: () => Effect.die("unused integration.connectKey"),
|
||||||
|
connectOauth: () => Effect.die("unused integration.connectOauth"),
|
||||||
|
attemptStatus: () => Effect.die("unused integration.attemptStatus"),
|
||||||
|
attemptComplete: () => Effect.die("unused integration.attemptComplete"),
|
||||||
|
attemptCancel: () => Effect.die("unused integration.attemptCancel"),
|
||||||
reload: integration.reload,
|
reload: integration.reload,
|
||||||
connection: {
|
connection: {
|
||||||
active: (id) => integration.connection.active(Integration.ID.make(id)),
|
active: (id) => integration.connection.active(Integration.ID.make(id)),
|
||||||
|
|||||||
@@ -11,6 +11,35 @@ import { PluginTestLayer } from "./fixture"
|
|||||||
const it = testEffect(PluginTestLayer)
|
const it = testEffect(PluginTestLayer)
|
||||||
|
|
||||||
describe("fromPromise", () => {
|
describe("fromPromise", () => {
|
||||||
|
it.effect("forwards standard client reads", () =>
|
||||||
|
Effect.gen(function* () {
|
||||||
|
const plugin = yield* PluginV2.Service
|
||||||
|
const host = yield* PluginHost.make(plugin)
|
||||||
|
const seen: string[] = []
|
||||||
|
const promisePlugin = define({
|
||||||
|
id: "promise-client-reads",
|
||||||
|
setup: async (ctx) => {
|
||||||
|
const results = await Promise.all([
|
||||||
|
ctx.agent.list(),
|
||||||
|
ctx.catalog.provider.list(),
|
||||||
|
ctx.catalog.model.list(),
|
||||||
|
ctx.command.list(),
|
||||||
|
ctx.integration.list(),
|
||||||
|
ctx.plugin.list(),
|
||||||
|
ctx.reference.list(),
|
||||||
|
ctx.skill.list(),
|
||||||
|
])
|
||||||
|
seen.push(...results.map((result) => result.location.directory))
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
yield* PluginPromise.fromPromise(promisePlugin).effect(host)
|
||||||
|
|
||||||
|
expect(seen).toHaveLength(8)
|
||||||
|
expect(new Set(seen).size).toBe(1)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
it.effect("loads a promise plugin and registers a transform hook", () =>
|
it.effect("loads a promise plugin and registers a transform hook", () =>
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const agents = yield* AgentV2.Service
|
const agents = yield* AgentV2.Service
|
||||||
|
|||||||
@@ -19,7 +19,15 @@ describe("SkillPlugin.Plugin", () => {
|
|||||||
it.effect("registers built-in skills", () =>
|
it.effect("registers built-in skills", () =>
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const skill = yield* SkillV2.Service
|
const skill = yield* SkillV2.Service
|
||||||
yield* SkillPlugin.Plugin.effect(host({ skill: { ...skill, reload: skill.reload } })).pipe(
|
yield* SkillPlugin.Plugin.effect(
|
||||||
|
host({
|
||||||
|
skill: {
|
||||||
|
list: () => Effect.die("unused skill.list"),
|
||||||
|
transform: skill.transform,
|
||||||
|
reload: skill.reload,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
).pipe(
|
||||||
Effect.provideService(Config.Service, Config.Service.of({ entries: () => Effect.succeed([]) })),
|
Effect.provideService(Config.Service, Config.Service.of({ entries: () => Effect.succeed([]) })),
|
||||||
Effect.provideService(
|
Effect.provideService(
|
||||||
Location.Service,
|
Location.Service,
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ai-sdk/provider": "3.0.8",
|
"@ai-sdk/provider": "3.0.8",
|
||||||
|
"@opencode-ai/client": "workspace:*",
|
||||||
"@opencode-ai/llm": "workspace:*",
|
"@opencode-ai/llm": "workspace:*",
|
||||||
"@opencode-ai/protocol": "workspace:*",
|
"@opencode-ai/protocol": "workspace:*",
|
||||||
"@opencode-ai/schema": "workspace:*",
|
"@opencode-ai/schema": "workspace:*",
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import type { AgentV2Info } from "@opencode-ai/sdk/v2/types"
|
import type { AgentV2Info } from "@opencode-ai/sdk/v2/types"
|
||||||
import type { AgentApi } from "./generated/api.js"
|
import type { AgentApi } from "@opencode-ai/client/effect/api"
|
||||||
import type { Hooks } from "./registration.js"
|
import type { Effect } from "effect"
|
||||||
|
import type { TransformHook } from "./registration.js"
|
||||||
|
|
||||||
export interface AgentDraft {
|
export interface AgentDraft {
|
||||||
list(): readonly AgentV2Info[]
|
list(): readonly AgentV2Info[]
|
||||||
@@ -10,9 +11,7 @@ export interface AgentDraft {
|
|||||||
remove(id: string): void
|
remove(id: string): void
|
||||||
}
|
}
|
||||||
|
|
||||||
export type AgentHooks = Hooks<{
|
export interface AgentHooks extends AgentApi<unknown> {
|
||||||
transform: AgentDraft
|
readonly transform: TransformHook<AgentDraft>
|
||||||
}>
|
readonly reload: () => Effect.Effect<void>
|
||||||
|
}
|
||||||
export type AgentPluginApi = AgentHooks
|
|
||||||
export type AgentDomain = AgentApi & AgentPluginApi
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import type { ModelV2Info, ProviderV2Info } from "@opencode-ai/sdk/v2/types"
|
import type { ModelV2Info, ProviderV2Info } from "@opencode-ai/sdk/v2/types"
|
||||||
import type { Hooks } from "./registration.js"
|
import type { CatalogApi } from "@opencode-ai/client/effect/api"
|
||||||
|
import type { Effect } from "effect"
|
||||||
|
import type { TransformHook } from "./registration.js"
|
||||||
|
|
||||||
export interface CatalogProviderRecord {
|
export interface CatalogProviderRecord {
|
||||||
readonly provider: ProviderV2Info
|
readonly provider: ProviderV2Info
|
||||||
@@ -24,6 +26,7 @@ export interface CatalogDraft {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CatalogHooks = Hooks<{
|
export interface CatalogHooks extends CatalogApi<unknown> {
|
||||||
transform: CatalogDraft
|
readonly transform: TransformHook<CatalogDraft>
|
||||||
}>
|
readonly reload: () => Effect.Effect<void>
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import type { CommandV2Info } from "@opencode-ai/sdk/v2/types"
|
import type { CommandV2Info } from "@opencode-ai/sdk/v2/types"
|
||||||
import type { Hooks } from "./registration.js"
|
import type { CommandApi } from "@opencode-ai/client/effect/api"
|
||||||
|
import type { Effect } from "effect"
|
||||||
|
import type { TransformHook } from "./registration.js"
|
||||||
|
|
||||||
export interface CommandDraft {
|
export interface CommandDraft {
|
||||||
list(): readonly CommandV2Info[]
|
list(): readonly CommandV2Info[]
|
||||||
@@ -8,6 +10,7 @@ export interface CommandDraft {
|
|||||||
remove(name: string): void
|
remove(name: string): void
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CommandHooks = Hooks<{
|
export interface CommandHooks extends CommandApi<unknown> {
|
||||||
transform: CommandDraft
|
readonly transform: TransformHook<CommandDraft>
|
||||||
}>
|
readonly reload: () => Effect.Effect<void>
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { PluginOptions } from "../options.js"
|
import type { PluginOptions } from "../options.js"
|
||||||
import type { AgentDomain } from "./agent.js"
|
import type { AgentHooks } from "./agent.js"
|
||||||
import type { AISDKHooks } from "./aisdk.js"
|
import type { AISDKHooks } from "./aisdk.js"
|
||||||
import type { CatalogHooks } from "./catalog.js"
|
import type { CatalogHooks } from "./catalog.js"
|
||||||
import type { CommandHooks } from "./command.js"
|
import type { CommandHooks } from "./command.js"
|
||||||
@@ -7,20 +7,19 @@ import type { IntegrationHooks } from "./integration.js"
|
|||||||
import type { PluginDomain } from "./plugin.js"
|
import type { PluginDomain } from "./plugin.js"
|
||||||
import type { ReferenceHooks } from "./reference.js"
|
import type { ReferenceHooks } from "./reference.js"
|
||||||
import type { SkillHooks } from "./skill.js"
|
import type { SkillHooks } from "./skill.js"
|
||||||
import type { Reload } from "./registration.js"
|
|
||||||
import type { ToolDomain } from "./tool.js"
|
import type { ToolDomain } from "./tool.js"
|
||||||
import type { SessionDomain } from "./runtime.js"
|
import type { SessionHooks } from "./runtime.js"
|
||||||
|
|
||||||
export interface PluginContext {
|
export interface PluginContext {
|
||||||
readonly options: PluginOptions
|
readonly options: PluginOptions
|
||||||
readonly agent: AgentDomain & Reload
|
readonly agent: AgentHooks
|
||||||
readonly aisdk: AISDKHooks
|
readonly aisdk: AISDKHooks
|
||||||
readonly catalog: CatalogHooks & Reload
|
readonly catalog: CatalogHooks
|
||||||
readonly command: CommandHooks & Reload
|
readonly command: CommandHooks
|
||||||
readonly integration: IntegrationHooks & Reload
|
readonly integration: IntegrationHooks
|
||||||
readonly plugin: PluginDomain
|
readonly plugin: PluginDomain
|
||||||
readonly reference: ReferenceHooks & Reload
|
readonly reference: ReferenceHooks
|
||||||
readonly skill: SkillHooks & Reload
|
readonly skill: SkillHooks
|
||||||
readonly tool: ToolDomain
|
readonly tool: ToolDomain
|
||||||
readonly session: SessionDomain
|
readonly session: SessionHooks
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,13 @@
|
|||||||
export type { PluginContext } from "./context.js"
|
export type { PluginContext } from "./context.js"
|
||||||
export { define } from "./plugin.js"
|
export { define } from "./plugin.js"
|
||||||
export type { Plugin } from "./plugin.js"
|
export type { Plugin, PluginDomain } from "./plugin.js"
|
||||||
|
export type { AgentDraft, AgentHooks } from "./agent.js"
|
||||||
|
export type { AISDKHooks } from "./aisdk.js"
|
||||||
|
export type { CatalogDraft, CatalogHooks, CatalogProviderRecord } from "./catalog.js"
|
||||||
|
export type { CommandDraft, CommandHooks } from "./command.js"
|
||||||
|
export type { IntegrationDraft, IntegrationHooks, IntegrationMethodRegistration } from "./integration.js"
|
||||||
|
export type { ReferenceDraft, ReferenceHooks } from "./reference.js"
|
||||||
|
export type { SkillDraft, SkillHooks } from "./skill.js"
|
||||||
export * as Tool from "./tool.js"
|
export * as Tool from "./tool.js"
|
||||||
export type { ToolDomain, ToolExecuteBeforeEvent, ToolExecuteAfterEvent } from "./tool.js"
|
export type { ToolDomain, ToolExecuteBeforeEvent, ToolExecuteAfterEvent } from "./tool.js"
|
||||||
export type { SessionDomain } from "./runtime.js"
|
export type { SessionHooks } from "./runtime.js"
|
||||||
|
|||||||
@@ -9,8 +9,9 @@ import type {
|
|||||||
IntegrationOAuthMethod,
|
IntegrationOAuthMethod,
|
||||||
IntegrationRef,
|
IntegrationRef,
|
||||||
} from "@opencode-ai/sdk/v2/types"
|
} from "@opencode-ai/sdk/v2/types"
|
||||||
|
import type { IntegrationApi } from "@opencode-ai/client/effect/api"
|
||||||
import type { Effect, Scope } from "effect"
|
import type { Effect, Scope } from "effect"
|
||||||
import type { Hooks } from "./registration.js"
|
import type { TransformHook } from "./registration.js"
|
||||||
|
|
||||||
export type IntegrationOAuthAuthorization = {
|
export type IntegrationOAuthAuthorization = {
|
||||||
readonly url: string
|
readonly url: string
|
||||||
@@ -55,7 +56,9 @@ export interface IntegrationDraft {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IntegrationHooks extends Hooks<{ transform: IntegrationDraft }> {
|
export interface IntegrationHooks extends IntegrationApi<unknown> {
|
||||||
|
readonly transform: TransformHook<IntegrationDraft>
|
||||||
|
readonly reload: () => Effect.Effect<void>
|
||||||
readonly connection: {
|
readonly connection: {
|
||||||
readonly active: (integrationID: string) => Effect.Effect<ConnectionInfo | undefined>
|
readonly active: (integrationID: string) => Effect.Effect<ConnectionInfo | undefined>
|
||||||
readonly resolve: (connection: ConnectionInfo) => Effect.Effect<CredentialValue | undefined, unknown>
|
readonly resolve: (connection: ConnectionInfo) => Effect.Effect<CredentialValue | undefined, unknown>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import type { PluginApi } from "@opencode-ai/client/effect/api"
|
||||||
import type { Effect, Scope } from "effect"
|
import type { Effect, Scope } from "effect"
|
||||||
import type { PluginContext } from "./context.js"
|
import type { PluginContext } from "./context.js"
|
||||||
|
|
||||||
@@ -10,7 +11,7 @@ export function define<R = Scope.Scope>(plugin: Plugin<R>) {
|
|||||||
return plugin
|
return plugin
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PluginDomain {
|
export interface PluginDomain extends PluginApi<unknown> {
|
||||||
readonly add: (plugin: Plugin) => Effect.Effect<void>
|
readonly add: (plugin: Plugin) => Effect.Effect<void>
|
||||||
readonly remove: (id: string) => Effect.Effect<void>
|
readonly remove: (id: string) => Effect.Effect<void>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import type { ReferenceGitSource, ReferenceLocalSource } from "@opencode-ai/sdk/v2/types"
|
import type { ReferenceGitSource, ReferenceLocalSource } from "@opencode-ai/sdk/v2/types"
|
||||||
import type { Hooks } from "./registration.js"
|
import type { ReferenceApi } from "@opencode-ai/client/effect/api"
|
||||||
|
import type { Effect } from "effect"
|
||||||
|
import type { TransformHook } from "./registration.js"
|
||||||
|
|
||||||
export interface ReferenceDraft {
|
export interface ReferenceDraft {
|
||||||
add(name: string, source: ReferenceLocalSource | ReferenceGitSource): void
|
add(name: string, source: ReferenceLocalSource | ReferenceGitSource): void
|
||||||
@@ -7,6 +9,7 @@ export interface ReferenceDraft {
|
|||||||
list(): readonly (readonly [string, ReferenceLocalSource | ReferenceGitSource])[]
|
list(): readonly (readonly [string, ReferenceLocalSource | ReferenceGitSource])[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ReferenceHooks = Hooks<{
|
export interface ReferenceHooks extends ReferenceApi<unknown> {
|
||||||
transform: ReferenceDraft
|
readonly transform: TransformHook<ReferenceDraft>
|
||||||
}>
|
readonly reload: () => Effect.Effect<void>
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,12 +4,10 @@ export interface Registration {
|
|||||||
readonly dispose: Effect.Effect<void>
|
readonly dispose: Effect.Effect<void>
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Reload {
|
|
||||||
readonly reload: () => Effect.Effect<void>
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Hooks<Spec> = {
|
export type Hooks<Spec> = {
|
||||||
readonly [Name in keyof Spec]: (
|
readonly [Name in keyof Spec]: (
|
||||||
callback: (input: Spec[Name]) => Effect.Effect<void> | void,
|
callback: (input: Spec[Name]) => Effect.Effect<void> | void,
|
||||||
) => Effect.Effect<Registration, never, Scope.Scope>
|
) => Effect.Effect<Registration, never, Scope.Scope>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type TransformHook<Input> = (callback: (input: Input) => void) => Effect.Effect<Registration, never, Scope.Scope>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
import type { SessionApi } from "./generated/api.js"
|
import type { SessionApi } from "@opencode-ai/client/effect/api"
|
||||||
|
|
||||||
export type SessionDomain = Pick<SessionApi<unknown>, "create" | "get" | "prompt" | "command" | "interrupt">
|
export interface SessionHooks
|
||||||
|
extends Pick<SessionApi<unknown>, "create" | "get" | "prompt" | "command" | "interrupt"> {}
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
import type { SkillV2Source } from "@opencode-ai/sdk/v2/types"
|
import type { SkillV2Source } from "@opencode-ai/sdk/v2/types"
|
||||||
import type { Hooks } from "./registration.js"
|
import type { SkillApi } from "@opencode-ai/client/effect/api"
|
||||||
|
import type { Effect } from "effect"
|
||||||
|
import type { TransformHook } from "./registration.js"
|
||||||
|
|
||||||
export interface SkillDraft {
|
export interface SkillDraft {
|
||||||
source(source: SkillV2Source): void
|
source(source: SkillV2Source): void
|
||||||
list(): readonly SkillV2Source[]
|
list(): readonly SkillV2Source[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SkillHooks = Hooks<{
|
export interface SkillHooks extends SkillApi<unknown> {
|
||||||
transform: SkillDraft
|
readonly transform: TransformHook<SkillDraft>
|
||||||
}>
|
readonly reload: () => Effect.Effect<void>
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
|
import type { AgentApi } from "@opencode-ai/client/promise/api"
|
||||||
import type { AgentDraft } from "../effect/agent.js"
|
import type { AgentDraft } from "../effect/agent.js"
|
||||||
import type { Hooks } from "./registration.js"
|
import type { TransformHook } from "./registration.js"
|
||||||
|
|
||||||
export type { AgentDraft }
|
export type { AgentDraft }
|
||||||
|
|
||||||
export type AgentHooks = Hooks<{
|
export interface AgentHooks extends AgentApi {
|
||||||
transform: AgentDraft
|
readonly transform: TransformHook<AgentDraft>
|
||||||
}>
|
readonly reload: () => Promise<void>
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
|
import type { CatalogApi } from "@opencode-ai/client/promise/api"
|
||||||
import type { CatalogDraft, CatalogProviderRecord } from "../effect/catalog.js"
|
import type { CatalogDraft, CatalogProviderRecord } from "../effect/catalog.js"
|
||||||
import type { Hooks } from "./registration.js"
|
import type { TransformHook } from "./registration.js"
|
||||||
|
|
||||||
export type { CatalogDraft, CatalogProviderRecord }
|
export type { CatalogDraft, CatalogProviderRecord }
|
||||||
|
|
||||||
export type CatalogHooks = Hooks<{
|
export interface CatalogHooks extends CatalogApi {
|
||||||
transform: CatalogDraft
|
readonly transform: TransformHook<CatalogDraft>
|
||||||
}>
|
readonly reload: () => Promise<void>
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
|
import type { CommandApi } from "@opencode-ai/client/promise/api"
|
||||||
import type { CommandDraft } from "../effect/command.js"
|
import type { CommandDraft } from "../effect/command.js"
|
||||||
import type { Hooks } from "./registration.js"
|
import type { TransformHook } from "./registration.js"
|
||||||
|
|
||||||
export type { CommandDraft }
|
export type { CommandDraft }
|
||||||
|
|
||||||
export type CommandHooks = Hooks<{
|
export interface CommandHooks extends CommandApi {
|
||||||
transform: CommandDraft
|
readonly transform: TransformHook<CommandDraft>
|
||||||
}>
|
readonly reload: () => Promise<void>
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,17 +6,18 @@ import type { CommandHooks } from "./command.js"
|
|||||||
import type { IntegrationHooks } from "./integration.js"
|
import type { IntegrationHooks } from "./integration.js"
|
||||||
import type { PluginDomain } from "./plugin.js"
|
import type { PluginDomain } from "./plugin.js"
|
||||||
import type { ReferenceHooks } from "./reference.js"
|
import type { ReferenceHooks } from "./reference.js"
|
||||||
|
import type { SessionHooks } from "./runtime.js"
|
||||||
import type { SkillHooks } from "./skill.js"
|
import type { SkillHooks } from "./skill.js"
|
||||||
import type { Reload } from "./registration.js"
|
|
||||||
|
|
||||||
export interface PluginContext {
|
export interface PluginContext {
|
||||||
readonly options: PluginOptions
|
readonly options: PluginOptions
|
||||||
readonly agent: AgentHooks & Reload
|
readonly agent: AgentHooks
|
||||||
readonly aisdk: AISDKHooks
|
readonly aisdk: AISDKHooks
|
||||||
readonly catalog: CatalogHooks & Reload
|
readonly catalog: CatalogHooks
|
||||||
readonly command: CommandHooks & Reload
|
readonly command: CommandHooks
|
||||||
readonly integration: IntegrationHooks & Reload
|
readonly integration: IntegrationHooks
|
||||||
readonly plugin: PluginDomain
|
readonly plugin: PluginDomain
|
||||||
readonly reference: ReferenceHooks & Reload
|
readonly reference: ReferenceHooks
|
||||||
readonly skill: SkillHooks & Reload
|
readonly session: SessionHooks
|
||||||
|
readonly skill: SkillHooks
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,11 +2,11 @@ export type { PluginContext } from "./context.js"
|
|||||||
export type { PluginOptions } from "../options.js"
|
export type { PluginOptions } from "../options.js"
|
||||||
export { define } from "./plugin.js"
|
export { define } from "./plugin.js"
|
||||||
export type { Plugin, PluginDomain } from "./plugin.js"
|
export type { Plugin, PluginDomain } from "./plugin.js"
|
||||||
export type { Registration, Reload } from "./registration.js"
|
|
||||||
export type { AgentDraft, AgentHooks } from "./agent.js"
|
export type { AgentDraft, AgentHooks } from "./agent.js"
|
||||||
export type { AISDKHooks } from "./aisdk.js"
|
export type { AISDKHooks } from "./aisdk.js"
|
||||||
export type { CatalogDraft, CatalogHooks, CatalogProviderRecord } from "./catalog.js"
|
export type { CatalogDraft, CatalogHooks, CatalogProviderRecord } from "./catalog.js"
|
||||||
export type { CommandDraft, CommandHooks } from "./command.js"
|
export type { CommandDraft, CommandHooks } from "./command.js"
|
||||||
export type { IntegrationDraft, IntegrationHooks, IntegrationMethodRegistration } from "./integration.js"
|
export type { IntegrationDraft, IntegrationHooks, IntegrationMethodRegistration } from "./integration.js"
|
||||||
export type { ReferenceDraft, ReferenceHooks } from "./reference.js"
|
export type { ReferenceDraft, ReferenceHooks } from "./reference.js"
|
||||||
|
export type { SessionHooks } from "./runtime.js"
|
||||||
export type { SkillDraft, SkillHooks } from "./skill.js"
|
export type { SkillDraft, SkillHooks } from "./skill.js"
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
|
import type { IntegrationApi } from "@opencode-ai/client/promise/api"
|
||||||
import type { IntegrationDraft, IntegrationMethodRegistration } from "../effect/integration.js"
|
import type { IntegrationDraft, IntegrationMethodRegistration } from "../effect/integration.js"
|
||||||
import type { CredentialValue } from "@opencode-ai/sdk/v2/types"
|
import type { CredentialValue } from "@opencode-ai/sdk/v2/types"
|
||||||
import type { Hooks } from "./registration.js"
|
import type { TransformHook } from "./registration.js"
|
||||||
|
|
||||||
export type { IntegrationDraft, IntegrationMethodRegistration }
|
export type { IntegrationDraft, IntegrationMethodRegistration }
|
||||||
|
|
||||||
export interface IntegrationHooks extends Hooks<{ transform: IntegrationDraft }> {
|
export interface IntegrationHooks extends IntegrationApi {
|
||||||
|
readonly transform: TransformHook<IntegrationDraft>
|
||||||
|
readonly reload: () => Promise<void>
|
||||||
readonly connection: {
|
readonly connection: {
|
||||||
readonly active: (integrationID: string) => Promise<import("@opencode-ai/sdk/v2/types").ConnectionInfo | undefined>
|
readonly active: (integrationID: string) => Promise<import("@opencode-ai/sdk/v2/types").ConnectionInfo | undefined>
|
||||||
readonly resolve: (
|
readonly resolve: (
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import type { PluginApi } from "@opencode-ai/client/promise/api"
|
||||||
import type { PluginContext } from "./context.js"
|
import type { PluginContext } from "./context.js"
|
||||||
|
|
||||||
export interface Plugin {
|
export interface Plugin {
|
||||||
@@ -9,7 +10,7 @@ export function define(plugin: Plugin) {
|
|||||||
return plugin
|
return plugin
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PluginDomain {
|
export interface PluginDomain extends PluginApi {
|
||||||
readonly add: (plugin: Plugin) => Promise<void>
|
readonly add: (plugin: Plugin) => Promise<void>
|
||||||
readonly remove: (id: string) => Promise<void>
|
readonly remove: (id: string) => Promise<void>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
|
import type { ReferenceApi } from "@opencode-ai/client/promise/api"
|
||||||
import type { ReferenceDraft } from "../effect/reference.js"
|
import type { ReferenceDraft } from "../effect/reference.js"
|
||||||
import type { Hooks } from "./registration.js"
|
import type { TransformHook } from "./registration.js"
|
||||||
|
|
||||||
export type { ReferenceDraft }
|
export type { ReferenceDraft }
|
||||||
|
|
||||||
export type ReferenceHooks = Hooks<{
|
export interface ReferenceHooks extends ReferenceApi {
|
||||||
transform: ReferenceDraft
|
readonly transform: TransformHook<ReferenceDraft>
|
||||||
}>
|
readonly reload: () => Promise<void>
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,10 +2,8 @@ export interface Registration {
|
|||||||
readonly dispose: () => Promise<void>
|
readonly dispose: () => Promise<void>
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Reload {
|
|
||||||
readonly reload: () => Promise<void>
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Hooks<Spec> = {
|
export type Hooks<Spec> = {
|
||||||
readonly [Name in keyof Spec]: (callback: (input: Spec[Name]) => Promise<void> | void) => Promise<Registration>
|
readonly [Name in keyof Spec]: (callback: (input: Spec[Name]) => Promise<void> | void) => Promise<Registration>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type TransformHook<Input> = (callback: (input: Input) => void) => Promise<Registration>
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
import type { SessionApi } from "@opencode-ai/client/promise/api"
|
||||||
|
|
||||||
|
export interface SessionHooks extends Pick<SessionApi, "create" | "get" | "prompt" | "command" | "interrupt"> {}
|
||||||
@@ -1,8 +1,10 @@
|
|||||||
|
import type { SkillApi } from "@opencode-ai/client/promise/api"
|
||||||
import type { SkillDraft } from "../effect/skill.js"
|
import type { SkillDraft } from "../effect/skill.js"
|
||||||
import type { Hooks } from "./registration.js"
|
import type { TransformHook } from "./registration.js"
|
||||||
|
|
||||||
export type { SkillDraft }
|
export type { SkillDraft }
|
||||||
|
|
||||||
export type SkillHooks = Hooks<{
|
export interface SkillHooks extends SkillApi {
|
||||||
transform: SkillDraft
|
readonly transform: TransformHook<SkillDraft>
|
||||||
}>
|
readonly reload: () => Promise<void>
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user