opencode_offline/packages/opencode/src/plugin/index.ts

71 lines
2.1 KiB
TypeScript
Raw Normal View History

2025-08-03 06:50:19 +08:00
import type { Hooks, Plugin as PluginInstance } from "@opencode-ai/plugin"
import { App } from "../app/app"
import { Config } from "../config/config"
import { Bus } from "../bus"
import { Log } from "../util/log"
import { createOpencodeClient } from "@opencode-ai/sdk"
2025-08-11 08:47:11 +08:00
// Lazy import to avoid circular dependency with session/tool registry
// import { Server } from "../server/server"
2025-08-04 09:19:03 +08:00
import { BunProc } from "../bun"
2025-08-03 06:50:19 +08:00
export namespace Plugin {
const log = Log.create({ service: "plugin" })
const state = App.state("plugin", async (app) => {
const client = createOpencodeClient({
baseUrl: "http://localhost:4096",
2025-08-11 08:47:11 +08:00
fetch: async (...args) => (await import("../server/server")).Server.app().fetch(...args),
2025-08-03 06:50:19 +08:00
})
const config = await Config.get()
const hooks = []
2025-08-04 09:19:03 +08:00
for (let plugin of config.plugin ?? []) {
2025-08-03 06:50:19 +08:00
log.info("loading plugin", { path: plugin })
2025-08-04 09:19:03 +08:00
if (!plugin.startsWith("file://")) {
const [pkg, version] = plugin.split("@")
plugin = await BunProc.install(pkg, version ?? "latest")
}
2025-08-03 06:50:19 +08:00
const mod = await import(plugin)
for (const [_name, fn] of Object.entries<PluginInstance>(mod)) {
const init = await fn({
client,
app,
$: Bun.$,
})
hooks.push(init)
}
}
return {
hooks,
}
})
export async function trigger<
2025-08-04 09:42:45 +08:00
Name extends keyof Required<Hooks>,
Input = Parameters<Required<Hooks>[Name]>[0],
Output = Parameters<Required<Hooks>[Name]>[1],
>(name: Name, input: Input, output: Output): Promise<Output> {
if (!name) return output
2025-08-03 06:50:19 +08:00
for (const hook of await state().then((x) => x.hooks)) {
2025-08-04 09:42:45 +08:00
const fn = hook[name]
2025-08-03 06:50:19 +08:00
if (!fn) continue
2025-08-04 05:09:19 +08:00
// @ts-expect-error if you feel adventurous, please fix the typing, make sure to bump the try-counter if you
// give up.
// try-counter: 2
2025-08-03 06:50:19 +08:00
await fn(input, output)
}
return output
}
export function init() {
Bus.subscribeAll(async (input) => {
const hooks = await state().then((x) => x.hooks)
for (const hook of hooks) {
hook["event"]?.({
event: input,
})
}
})
}
}