feat(plugin): add namespaced hook API (#33416)
This commit is contained in:
parent
dc468bdcfd
commit
909a1a6d78
150 changed files with 3276 additions and 3906 deletions
|
|
@ -1,6 +1,6 @@
|
|||
export * as ConfigAgentPlugin from "./agent"
|
||||
|
||||
import { define } from "@opencode-ai/plugin/v2/effect"
|
||||
import { define } from "../../plugin/internal"
|
||||
import path from "path"
|
||||
import { Effect, Option, Schema } from "effect"
|
||||
import { AgentV2 } from "../../agent"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
export * as ConfigCommandPlugin from "./command"
|
||||
|
||||
import { define } from "@opencode-ai/plugin/v2/effect"
|
||||
import { define } from "../../plugin/internal"
|
||||
import path from "path"
|
||||
import { Effect, Option, Schema } from "effect"
|
||||
import { CommandV2 } from "../../command"
|
||||
|
|
|
|||
99
packages/core/src/config/plugin/external.ts
Normal file
99
packages/core/src/config/plugin/external.ts
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
export * as ConfigExternalPlugin from "./external"
|
||||
|
||||
import type { Plugin as EffectPlugin } from "@opencode-ai/plugin/v2/effect"
|
||||
import type { Plugin as PromisePlugin } from "@opencode-ai/plugin/v2/promise"
|
||||
import { Effect, Schema } from "effect"
|
||||
import path from "path"
|
||||
import { fileURLToPath, pathToFileURL } from "url"
|
||||
import { Config } from "../../config"
|
||||
import { FSUtil } from "../../fs-util"
|
||||
import { Location } from "../../location"
|
||||
import { Npm } from "../../npm"
|
||||
import { define } from "../../plugin/internal"
|
||||
import { PluginPromise } from "../../plugin/promise"
|
||||
|
||||
const PluginModule = Schema.Struct({
|
||||
default: Schema.Union([
|
||||
Schema.Struct({
|
||||
id: Schema.String,
|
||||
effect: Schema.declare<EffectPlugin["effect"]>(
|
||||
(input): input is EffectPlugin["effect"] => typeof input === "function",
|
||||
),
|
||||
}),
|
||||
Schema.Struct({
|
||||
id: Schema.String,
|
||||
setup: Schema.declare<PromisePlugin["setup"]>(
|
||||
(input): input is PromisePlugin["setup"] => typeof input === "function",
|
||||
),
|
||||
}),
|
||||
]),
|
||||
})
|
||||
|
||||
export const Plugin = define({
|
||||
id: "config-plugin",
|
||||
effect: Effect.fn(function* (ctx) {
|
||||
const config = yield* Config.Service
|
||||
const fs = yield* FSUtil.Service
|
||||
const location = yield* Location.Service
|
||||
const npm = yield* Npm.Service
|
||||
const loaded: EffectPlugin[] = []
|
||||
|
||||
yield* ctx.plugin.transform((plugins) => {
|
||||
for (const plugin of loaded) plugins.add(plugin)
|
||||
})
|
||||
|
||||
yield* Effect.gen(function* () {
|
||||
const configured: { package: string; options?: Record<string, any> }[] = []
|
||||
|
||||
for (const entry of yield* config.entries()) {
|
||||
if (entry.type === "document") {
|
||||
const directory = entry.path ? path.dirname(entry.path) : location.directory
|
||||
for (const item of entry.info.plugins ?? []) {
|
||||
const ref = typeof item === "string" ? { package: item } : item
|
||||
const packageName = (() => {
|
||||
if (ref.package.startsWith("file://")) return fileURLToPath(ref.package)
|
||||
if (ref.package.startsWith("./") || ref.package.startsWith("../")) {
|
||||
return path.resolve(directory, ref.package)
|
||||
}
|
||||
return ref.package
|
||||
})()
|
||||
configured.push({ package: packageName, options: ref.options })
|
||||
}
|
||||
}
|
||||
|
||||
if (entry.type === "directory") {
|
||||
const files = yield* fs
|
||||
.glob("{plugin,plugins}/*.{ts,js}", {
|
||||
cwd: entry.path,
|
||||
absolute: true,
|
||||
include: "file",
|
||||
dot: true,
|
||||
symlink: true,
|
||||
})
|
||||
.pipe(Effect.orElseSucceed(() => []))
|
||||
files.sort()
|
||||
for (const file of files) configured.push({ package: file })
|
||||
}
|
||||
}
|
||||
|
||||
for (const ref of configured) {
|
||||
yield* Effect.gen(function* () {
|
||||
const entrypoint = path.isAbsolute(ref.package)
|
||||
? pathToFileURL(ref.package).href
|
||||
: (yield* npm.add(ref.package)).entrypoint
|
||||
if (!entrypoint) return
|
||||
|
||||
const mod = yield* Effect.promise(() => import(entrypoint))
|
||||
const value = (yield* Schema.decodeUnknownEffect(PluginModule)(mod)).default
|
||||
const plugin = "effect" in value ? value : PluginPromise.fromPromise(value)
|
||||
loaded.push({
|
||||
id: plugin.id,
|
||||
effect: (host) => plugin.effect({ ...host, options: ref.options ?? {} }),
|
||||
})
|
||||
}).pipe(Effect.ignoreCause)
|
||||
}
|
||||
|
||||
yield* ctx.plugin.reload()
|
||||
}).pipe(Effect.forkScoped({ startImmediately: true }))
|
||||
}),
|
||||
})
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
export * as ConfigProviderPlugin from "./provider"
|
||||
|
||||
import { define } from "@opencode-ai/plugin/v2/effect"
|
||||
import { define } from "../../plugin/internal"
|
||||
import { Effect } from "effect"
|
||||
import { Config } from "../../config"
|
||||
import { ModelV2 } from "../../model"
|
||||
|
|
|
|||
|
|
@ -1,24 +1,28 @@
|
|||
export * as ConfigReferencePlugin from "./reference"
|
||||
|
||||
import { define } from "@opencode-ai/plugin/v2/effect"
|
||||
import { define } from "../../plugin/internal"
|
||||
import path from "path"
|
||||
import { Effect } from "effect"
|
||||
import { Config } from "../../config"
|
||||
import { ConfigReference } from "../reference"
|
||||
import { Reference } from "../../reference"
|
||||
import { AbsolutePath } from "../../schema"
|
||||
import { Global } from "../../global"
|
||||
import { Location } from "../../location"
|
||||
|
||||
export const Plugin = define({
|
||||
id: "core/config-reference",
|
||||
effect: Effect.fn(function* (ctx) {
|
||||
const config = yield* Config.Service
|
||||
const location = yield* Location.Service
|
||||
const global = yield* Global.Service
|
||||
yield* ctx.reference.transform(
|
||||
Effect.fn(function* (draft) {
|
||||
const entries = new Map<string, Reference.Source>()
|
||||
for (const doc of (yield* config.entries()).filter(
|
||||
(entry): entry is Config.Document => entry.type === "document",
|
||||
)) {
|
||||
const directory = doc.path ? path.dirname(doc.path) : ctx.location.directory
|
||||
const directory = doc.path ? path.dirname(doc.path) : location.directory
|
||||
for (const [name, entry] of Object.entries(doc.info.references ?? {})) {
|
||||
if (!validAlias(name)) continue
|
||||
entries.set(
|
||||
|
|
@ -27,7 +31,7 @@ export const Plugin = define({
|
|||
? new Reference.LocalSource({
|
||||
type: "local",
|
||||
path: AbsolutePath.make(
|
||||
localPath(directory, ctx.path.home, typeof entry === "string" ? entry : entry.path),
|
||||
localPath(directory, global.home, typeof entry === "string" ? entry : entry.path),
|
||||
),
|
||||
description: typeof entry === "string" ? undefined : entry.description,
|
||||
hidden: typeof entry === "string" ? undefined : entry.hidden,
|
||||
|
|
|
|||
|
|
@ -1,16 +1,20 @@
|
|||
export * as ConfigSkillPlugin from "./skill"
|
||||
|
||||
import { define } from "@opencode-ai/plugin/v2/effect"
|
||||
import { define } from "../../plugin/internal"
|
||||
import path from "path"
|
||||
import { Effect } from "effect"
|
||||
import { Config } from "../../config"
|
||||
import { AbsolutePath } from "../../schema"
|
||||
import { SkillV2 } from "../../skill"
|
||||
import { Global } from "../../global"
|
||||
import { Location } from "../../location"
|
||||
|
||||
export const Plugin = define({
|
||||
id: "config-skill",
|
||||
effect: Effect.fn(function* (ctx) {
|
||||
const config = yield* Config.Service
|
||||
const global = yield* Global.Service
|
||||
const location = yield* Location.Service
|
||||
yield* ctx.skill.transform(
|
||||
Effect.fn(function* (draft) {
|
||||
const entries = yield* config.entries()
|
||||
|
|
@ -29,13 +33,11 @@ export const Plugin = define({
|
|||
draft.source(new SkillV2.UrlSource({ type: "url", url: item }))
|
||||
continue
|
||||
}
|
||||
const expanded = item.startsWith("~/") ? path.join(ctx.path.home, item.slice(2)) : item
|
||||
const expanded = item.startsWith("~/") ? path.join(global.home, item.slice(2)) : item
|
||||
draft.source(
|
||||
new SkillV2.DirectorySource({
|
||||
type: "directory",
|
||||
path: AbsolutePath.make(
|
||||
path.isAbsolute(expanded) ? expanded : path.join(ctx.location.directory, expanded),
|
||||
),
|
||||
path: AbsolutePath.make(path.isAbsolute(expanded) ? expanded : path.join(location.directory, expanded)),
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue