mirror of
https://github.com/anomalyco/opencode.git
synced 2026-07-18 12:43:29 +00:00
feat(plugin): add promise plugin cleanup
This commit is contained in:
parent
278c510549
commit
c867e66ab5
6 changed files with 74 additions and 15 deletions
|
|
@ -130,7 +130,9 @@ export function fromPromise(plugin: PromisePlugin) {
|
|||
},
|
||||
}
|
||||
|
||||
yield* Effect.promise(() => Promise.resolve(plugin.setup(context2)))
|
||||
const cleanup = yield* Effect.promise(() => Promise.resolve(plugin.setup(context2)))
|
||||
if (!cleanup) return
|
||||
yield* Effect.addFinalizer(() => Effect.promise(() => Promise.resolve(cleanup())))
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,10 +4,10 @@ Use this guide as the starting point for work involving OpenCode itself. It
|
|||
covers the core concepts needed to configure and customize OpenCode, extend it
|
||||
with plugins, and build integrations with the OpenCode SDK, clients, and API.
|
||||
|
||||
Full documentation is available at <https://opencode.mintlify.site/>. Consult
|
||||
Full documentation is available at <https://v2.opencode.ai/>. Consult
|
||||
it when this overview does not contain enough detail for the task.
|
||||
|
||||
## Configuration
|
||||
## [Configuration](https://v2.opencode.ai/config)
|
||||
|
||||
OpenCode configuration uses JSON or JSONC. Include the published schema so the
|
||||
user's editor can validate fields and provide autocomplete:
|
||||
|
|
@ -34,14 +34,14 @@ Do not guess field names or shapes. Use
|
|||
<https://opencode.ai/config.json> as the source of truth and preserve unrelated
|
||||
settings when editing an existing file.
|
||||
|
||||
See the [full configuration guide](https://opencode.mintlify.site/config) for
|
||||
See the [full configuration guide](https://v2.opencode.ai/config) for
|
||||
every field, examples, config locations, and links to dedicated feature guides.
|
||||
|
||||
## V1 to V2 migration
|
||||
## [V1 to V2 migration](https://v2.opencode.ai/migrate-v1)
|
||||
|
||||
For any request to migrate OpenCode configuration, agents, commands, skills,
|
||||
plugins, integrations, or other behavior from V1 to V2, read the full
|
||||
[migration guide](https://opencode.mintlify.site/migrate-v1) before acting. In
|
||||
[migration guide](https://v2.opencode.ai/migrate-v1) before acting. In
|
||||
the repository, its source is `packages/docs/migrate-v1.mdx`.
|
||||
|
||||
V1 config files and `.opencode/` definitions are intended to remain compatible.
|
||||
|
|
@ -54,7 +54,7 @@ not attempt migration yet. Once the V2 plugin API is finalized, OpenCode should
|
|||
be able to migrate most plugins. If non-API V1 functionality fails in V2, use
|
||||
the `report` skill to file it as a compatibility bug.
|
||||
|
||||
## Service
|
||||
## [Service](https://v2.opencode.ai/troubleshooting#check-the-background-service)
|
||||
|
||||
OpenCode uses a client-server architecture. Interfaces such as the TUI connect
|
||||
to a background OpenCode service, which owns sessions, configuration, plugins,
|
||||
|
|
@ -73,7 +73,7 @@ Check its status after restarting:
|
|||
opencode2 service status
|
||||
```
|
||||
|
||||
## API
|
||||
## [API](https://v2.opencode.ai/api)
|
||||
|
||||
OpenCode exposes an HTTP API from its server. The API is described by an
|
||||
OpenAPI document available from the running server at `/openapi.json`.
|
||||
|
|
@ -101,12 +101,12 @@ connected to an explicit server instead of its managed background service, use
|
|||
the same configured server and authentication context rather than constructing
|
||||
an unauthenticated request separately.
|
||||
|
||||
See the [full API reference](https://opencode.mintlify.site/api) for available
|
||||
See the [full API reference](https://v2.opencode.ai/api) for available
|
||||
endpoints, parameters, request bodies, and response schemas. The
|
||||
raw [OpenAPI specification](https://opencode.mintlify.site/openapi.json) is also
|
||||
raw [OpenAPI specification](https://v2.opencode.ai/openapi.json) is also
|
||||
available for code generation and other tooling.
|
||||
|
||||
## Troubleshooting
|
||||
## [Troubleshooting](https://v2.opencode.ai/troubleshooting)
|
||||
|
||||
OpenCode runs a client and a background server. Start by determining whether a
|
||||
problem belongs to the client, the shared server, or one project.
|
||||
|
|
@ -124,6 +124,6 @@ problem belongs to the client, the shared server, or one project.
|
|||
- Redact API keys, authorization headers, prompts, file contents, and other
|
||||
sensitive data before sharing diagnostics.
|
||||
|
||||
See the [full troubleshooting guide](https://opencode.mintlify.site/troubleshooting)
|
||||
See the [full troubleshooting guide](https://v2.opencode.ai/troubleshooting)
|
||||
for service lifecycle commands, API inspection, log locations, explicit server
|
||||
connections, issue-reporting details, and local development paths.
|
||||
|
|
|
|||
|
|
@ -97,6 +97,33 @@ describe("fromPromise", () => {
|
|||
}),
|
||||
)
|
||||
|
||||
it.effect("runs the setup cleanup when the plugin scope closes", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugin = yield* PluginV2.Service
|
||||
const host = yield* PluginHost.make(plugin)
|
||||
const events: string[] = []
|
||||
const promisePlugin = Plugin.define({
|
||||
id: "promise-cleanup",
|
||||
setup: async () => {
|
||||
events.push("setup")
|
||||
return async () => {
|
||||
await Promise.resolve()
|
||||
events.push("cleanup")
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
yield* Effect.scoped(
|
||||
Effect.gen(function* () {
|
||||
yield* PluginPromise.fromPromise(promisePlugin).effect(host)
|
||||
expect(events).toEqual(["setup"])
|
||||
}),
|
||||
)
|
||||
|
||||
expect(events).toEqual(["setup", "cleanup"])
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("constructs plain Promise tool declarations in the host", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugins = yield* PluginV2.Service
|
||||
|
|
|
|||
23
packages/docs/build/plugins.mdx
vendored
23
packages/docs/build/plugins.mdx
vendored
|
|
@ -148,7 +148,25 @@ export default Plugin.define({
|
|||
```
|
||||
|
||||
`setup` runs each time the plugin is activated. Register long-lived behavior
|
||||
during setup; do not wait there on an infinite event stream.
|
||||
during setup; do not wait there on an infinite event stream. It may return a
|
||||
synchronous or asynchronous cleanup function. OpenCode awaits that cleanup
|
||||
when the plugin is disabled, reloaded, or shut down:
|
||||
|
||||
```ts
|
||||
setup: async (ctx) => {
|
||||
const controller = new AbortController()
|
||||
const task = synchronize(ctx, controller.signal)
|
||||
|
||||
return async () => {
|
||||
controller.abort()
|
||||
await task
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Hook registrations are released automatically with the same plugin scope. Use
|
||||
the returned cleanup for resources the plugin owns, such as timers, watchers,
|
||||
connections, and background tasks.
|
||||
|
||||
### Context
|
||||
|
||||
|
|
@ -216,7 +234,8 @@ export default Plugin.define({
|
|||
}
|
||||
|
||||
await refresh()
|
||||
setInterval(() => void refresh().catch(console.error), 60_000)
|
||||
const timer = setInterval(() => void refresh().catch(console.error), 60_000)
|
||||
return () => clearInterval(timer)
|
||||
},
|
||||
})
|
||||
```
|
||||
|
|
|
|||
|
|
@ -25,6 +25,15 @@ export default Plugin.define({
|
|||
```
|
||||
|
||||
Plugin setup registers hooks imperatively through each domain's `hook` method.
|
||||
It may return a synchronous or asynchronous cleanup function. OpenCode awaits
|
||||
the cleanup when the plugin is unloaded or replaced:
|
||||
|
||||
```ts
|
||||
setup: async (ctx) => {
|
||||
const timer = setInterval(refresh, 60_000)
|
||||
return () => clearInterval(timer)
|
||||
}
|
||||
```
|
||||
|
||||
Configuration supplied for the plugin is available as `ctx.options`.
|
||||
|
||||
|
|
|
|||
|
|
@ -26,9 +26,11 @@ export interface Context {
|
|||
readonly tool: ToolDomain
|
||||
}
|
||||
|
||||
export type Cleanup = () => Promise<void> | void
|
||||
|
||||
export interface Plugin {
|
||||
readonly id: string
|
||||
readonly setup: (context: Context) => Promise<void> | void
|
||||
readonly setup: (context: Context) => Promise<Cleanup | void> | Cleanup | void
|
||||
}
|
||||
|
||||
export function define(plugin: Plugin) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue