Version OpenCode skills and plugins
Repository sits at the OpenCode config root rather than inside skills/ or
plugins/. OpenCode scans exactly those two subdirectories, and a .git
directory inside either one is picked up as a plugin and fails to load:
loading plugin id=.../plugins/.git entrypoint=.../plugins/.git/index
failed to load plugin ... AggregateError: 2 errors building .../plugins/.git/index
The watcher.ignore config option does not help: it only suppresses filesystem
update events, not plugin discovery, and the "-" disable prefix only applies to
plugins listed in opencode.json(c), not auto-discovered ones.
.gitignore admits only skills/ and plugins/ (plus itself). Personal config
(opencode.jsonc, cli.json, service.json) and node_modules stay local.
skills/opencode-plugins V2-only plugin authoring reference and 7 templates,
transcribed from the V2 docs with the URL on every file
plugins/searxng-search searxng_search tool over a self-hosted SearXNG JSON API
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
// RPC implementation (Effect flavor) — template
|
||||
//
|
||||
// Docs: https://opencode.ai/v2/docs/build/plugins/effect/rpc/
|
||||
//
|
||||
// Needs templates/rpc-effect.ts copied next to this file as src/rpc.ts, so the
|
||||
// doc's "./rpc.js" specifier resolves. Rename it rpc.ts on save; the contract
|
||||
// shape is identical, only the schema dialect differs.
|
||||
//
|
||||
// Registration goes inside the plugin `effect`, NOT `setup`.
|
||||
|
||||
//
|
||||
// The docs use "@opencode/plugin" and "@opencode/plugin/effect". Install the
|
||||
// package at your OpenCode version and restart the service first — see the
|
||||
// PREREQUISITE block in promise-plugin.ts.
|
||||
import { Plugin } from "@opencode/plugin/effect"
|
||||
import { Effect, Stream } from "effect"
|
||||
import { Acme } from "./rpc.js"
|
||||
|
||||
export default Plugin.define({
|
||||
id: "acme-effect-plugin",
|
||||
|
||||
effect: (ctx) =>
|
||||
Effect.gen(function* () {
|
||||
const registration = yield* ctx.rpc.register(Acme, {
|
||||
// Input arrives already decoded — destructure it, do not cast.
|
||||
search: ({ query }, context) =>
|
||||
findText(query).pipe(
|
||||
Effect.flatMap((text) =>
|
||||
text
|
||||
? Effect.succeed({ text })
|
||||
: Effect.fail(context.error("not_found", "Result not found", { query })),
|
||||
),
|
||||
),
|
||||
})
|
||||
|
||||
// The same plugin can call its own RPC.
|
||||
const acme = ctx.rpc(Acme)
|
||||
const result = yield* acme.search({ query: "hello" })
|
||||
|
||||
yield* registration.events.emit("updated", { itemID: "item-1", text: result.text })
|
||||
|
||||
// Subscriptions are a Stream; forkScoped handles interruption.
|
||||
// "Subscriptions are live only and close when Stream consumption stops."
|
||||
yield* acme.events.subscribe("updated").pipe(
|
||||
Stream.runForEach((event) => Effect.logInfo(event.data.text)),
|
||||
Effect.forkScoped,
|
||||
)
|
||||
|
||||
// context.signal is NOT documented on the Effect page. Use interruption.
|
||||
}).pipe(Effect.orDie),
|
||||
})
|
||||
|
||||
// Calling over HTTP uses the Effect client and needs an HTTP client layer:
|
||||
//
|
||||
// import { OpenCode } from "@opencode/client/effect"
|
||||
// import { Effect } from "effect"
|
||||
// import { FetchHttpClient } from "effect/unstable/http"
|
||||
// import { Acme } from "opencode-acme-plugin/rpc"
|
||||
//
|
||||
// const program = Effect.gen(function* () {
|
||||
// const client = yield* OpenCode.make({ baseUrl: "http://localhost:4096" })
|
||||
// const acme = client.rpc(Acme)
|
||||
// return yield* acme.search({ query: "hello" })
|
||||
// })
|
||||
//
|
||||
// const result = await Effect.runPromise(
|
||||
// program.pipe(Effect.provide(FetchHttpClient.layer)),
|
||||
// )
|
||||
//
|
||||
// Another Effect plugin calls it with ctx.rpc(Acme). events.on and the
|
||||
// prefixed event type are documented only on the Promise page — check before
|
||||
// relying on either here.
|
||||
|
||||
declare function findText(query: string): Effect.Effect<string | undefined>
|
||||
Reference in New Issue
Block a user