Dashboard › opencode › Distillation
87d7d1c8-ca07-4b62-951d-5aa77ce64901["lore_tm_v1_5UQUZnS75sx7DZqVWX7kar0vzm4n2eaWzK6jdcO6qWA","lore_tm_v1_SPxdWKB_4a8cHlYxbdjZiiNv2lS4LrsI9YwyoU_MOTY","lore_tm_v1_FF8v-ASy8aw0Sc0xLbrgHgqI4J69nLUIlzjQG97tvc0","lore_tm_v1_FUtd221GyL-bXyA7Vx-MhOJRI0RFd0DzJ1YabrQymo0","lore_tm_v1_Vazy662k3_-VEgeOMNOqhQRg9f66WRS21pjN0ZVtZYk","lore_tm_v1_yb-q0LolxqxZMxVN5SICnFdaWpADwvRj-NZ9IK57rZo","lore_tm_v1_0PfEmg_aeWt9bR_tE1MMF_3Bm7udQm6wIOU-BMveaXc"]
/home/byk/Code/opencode-v2-pilot/packages/plugin/src/promise/index.ts (20 lines). It exports types PluginOptions from ../options.js and StorageEntry, StorageScanOptions, StorageScanResult from ../storage.js; exports namespace Plugin from ./plugin.js; and re-exports schema namespaces Agent, Command, Connection, Credential, Integration, Location, Mcp, Model, PersistentPty, Provider, Reference, Rpc, Skill, Vcs, WebSearch, and Worktree from their respective @opencode/schema/* modules./home/byk/Code/opencode-v2-pilot/packages/plugin/src/promise/registration.ts (21 lines). Registration has readonly dispose: () => Promise<void>; ModelHookOptions has optional readonly providerID?: string, limiting a hook to one provider while unscoped hooks apply to all providers.Hooks<Spec> in packages/plugin/src/promise/registration.ts:10-13 is a generic function accepting name: Name and callback: (input: Spec[Name]) => Promise<void> | void, returning Promise<Registration>.ModelHooks<Spec> in packages/plugin/src/promise/registration.ts:15-19 additionally accepts options?: Spec[Name] extends { readonly model: unknown } ? ModelHookOptions : never, so provider scoping is available only for events whose input has a readonly model.Transform<Input> in packages/plugin/src/promise/registration.ts:21 is exactly (callback: (input: Input) => void) => Promise<Registration>./home/byk/Code/opencode-v2-pilot/packages/plugin/src/promise/adapter.ts (639 lines), which adapts Promise plugins into Effect plugins via fromPromise(plugin: Plugin) so the existing Effect-only Core plugin runtime can execute them unchanged.packages/plugin/src/promise/adapter.ts imports Tool from @opencode/schema/tool, Rpc from @opencode/schema/rpc, RpcCallOptions and RpcEventPayload from @opencode/client/promise/api, Effect, Schema, SchemaAST, Stream, and Scope from effect, HttpApiEndpoint and HttpApiSchema from effect/unstable/httpapi, Effect-plugin define from ../effect/plugin.js, Promise Plugin from ./plugin.js, Promise tool Info from ./tool.js, and RpcDomain/RpcHandlers from ./rpc.js.HostRegistration = { readonly dispose: Effect.Effect<void> }, Registration = { readonly dispose: () => Promise<void> }, PromiseContext = Parameters<Plugin["setup"]>[0], PromiseEvent inferred from PromiseContext["event"]["subscribe"], HostRpc inferred from the Effect plugin host, and StreamAdapter converting Stream.Stream<A, E> plus optional AbortSignal into AsyncIterable<A>.compiledEndpoints, a WeakMap<object, CompiledEndpoint>. CompiledEndpoint contains decode: ReadonlyArray<(input: unknown) => Effect.Effect<unknown, Schema.SchemaError>>, encode: (output: unknown) => Effect.Effect<unknown, Schema.SchemaError>, and noContent: boolean.TypedFailure, which stores an unknown error, and ReturnedRpcError extends Error, which stores RPC type, message, and optional data.makeStreams (packages/plugin/src/promise/adapter.ts:48-78) captures a Scope.Scope, tracks async-iterator close functions in a Set, and registers an Effect finalizer that closes all subscriptions when the plugin unloads. Each iterator removes itself and its abort listener on close, supports an optional AbortSignal, closes immediately if already aborted, closes on normal completion or iteration error, and exposes return: close.rpcFromEffect (packages/plugin/src/promise/adapter.ts:80-164) adapts Effect RPC clients and registrations to the Promise RpcDomain: generated methods run through Effect.runPromiseWith(context) and forward options?.signal; event subscribe uses the stream adapter; event on combines its own AbortController.signal with a caller signal via AbortSignal.any, asynchronously invokes the handler for each event, logs loop errors with Effect.logError, and returns a function that aborts the controller.Reflect.apply(handler, undefined, [input, { signal, error }]); the supplied error(type, message, data?) constructs ReturnedRpcError. Returned or thrown ReturnedRpcError instances are translated by hostRpcError() into context.error(error.type, error.message, error.data), while other errors pass through unchanged. Registration results expose Promise dispose() and events.emit(...).compileEndpoint(endpoint) (packages/plugin/src/promise/adapter.ts:171-207) returns a cached compilation when available; gathers payload and success schemas; throws Error(\Unsupported API schema cardinality: ${endpoint.identifier}`)if either cardinality exceeds 1; decodes params, query converted withSchema.toType, headers, and payload; defaults success to HttpApiSchema.NoContent; detects no-content responses; unwraps a sole object property named datawhen appropriate; compiles decoders withSchema.decodeUnknownEffectand the output encoder withSchema.encodeUnknownEffect`; then caches the result.fromPromise documentation states that async-setup hook registrations attach to the plugin scope so unloading disposes them, while the captured fiber context preserves boot-time batching so Promise-plugin transforms coalesce into one reload per domain.fromPromise(plugin) dynamically imports ClientApi from @opencode/protocol/client and OpenCodeEvent from @opencode/protocol/groups/event, then obtains endpoint groups for server.agent, server.command, server.experimental, server.generate, server.integration, server.mcp, server.model, server.plugin, server.permission, server.provider, server.reference, server.session, server.skill, server.vcs, server.websearch, and server.worktree.fromPromise captures the Effect scope and builds streams; its local register() runs a host registration in that scope and returns Promise dispose(), while run() executes arbitrary Effects with the captured context.promiseExecutor adapts Effect tool execution to Promise tool execution and rewrites progress(update) as Effect.promise(() => context.progress(update)).adaptApiMethod<PromiseMethod> compiles an HttpApiEndpoint.Top, decodes all input schemas from input ?? {}, merges decoded objects with Object.assign({}, ...decoded), calls the host method, returns undefined for no-content endpoints, otherwise encodes the result, and executes the Effect with the captured context.transform() adapter registers a Promise editor callback against an Effect domain transform.fromPromise passes through app, location, and options from the host.agent domain maps get to endpoint agent.get, list to agent.list, adapts transform, and maps reload to run(host.agent.reload()).aisdk.hook(name, callback, options) registers host.aisdk.hook and wraps callback completion with Effect.promise(() => Promise.resolve(callback(event))).catalog domain exposes provider list/get via provider.list/provider.get, model list/default via model.list/model.default, plus adapted transform and reload.command domain exposes list, reload, and a transform editor whose add(definition) wraps definition.execute(input) in Effect.tryPromise({ try: ..., catch: (cause) => cause }).event.subscribe(options) streams host.event.subscribe(), encodes each event through Schema.encodeUnknownEffect(OpenCodeEvent), casts it to PromiseEvent, and applies the callerβs stream options.experimental.terminal.read uses endpoint persistentPty.read, and adapted generate.text uses endpoint generate.text.integration API exposes list, get, connect.key; OAuth connect, status, complete, cancel; command-based connect, status, cancel; plus transform, reload, and connection active(id)/resolve(connection).list, get, update, remove, and method list/remove. Method update(input) directly delegates when authorize is absent; otherwise it wraps authorize(answer) in an Effect, preserves mode: "auto" callbacks without a code argument, wraps non-auto callbacks with (code), and wraps optional refresh(credential) in Effect.promise.mcp exposes list, transform, and reload.permission exposes hook, assert, list, get, and reply; hook wraps Promise callback completion; assert catches host Effect errors and dies with new TypedFailure(error); API methods map to session.permission.list, session.permission.get, and session.permission.reply.plugin.list maps endpoint plugin.list; adapted reference and skill each expose list, transform, and reload; and adapted rpc is produced by yield* rpcFromEffect(host.rpc, streams).storage directly wraps host get(key), set(key, value), remove(key), and scan(options) using run().tool exposes reload, transform, and hook. The transform editor wraps listed and retrieved tools with Promise-compatible execute; passes through namespace and remove; adapts added tools via executePromiseTool(tool, input, context); and on update creates a Promise-facing Info, invokes the updater, then writes back output, options, and an Effect-facing execute.tool.hook(name, callback) registers the host hook and wraps callback completion with Effect.promise(() => Promise.resolve(callback(event))).vcs exposes endpoint-backed get, base, branches, status, diff, plus reload and transform. Its transform add(definition) preserves id and name; binds optional base to definition; and wraps info, optional base, branches, status, and diff through attempt((signal) => ...(..., { signal })); it also passes through editor.default.websearch exposes endpoint-backed providers and query, plus reload and transform. Its transform adds definitions with id, name, and signal-aware execute, and passes through editor.default.worktree exposes endpoint-backed list, create, remove, and refresh, plus reload and transform. Its transform adds definitions with id and signal-aware create, remove, and list(directory).session exposes provider-scopable hook(name, callback, options) and endpoint-backed methods in this order: create, get, switchAgent, switchModel, prompt, generate, command, synthetic, interrupt, rename, move, wait, and context.shell.hook(name, callback) registers the host hook and wraps Promise callback completion.fromPromise executes plugin.setup(context2) under Effect.acquireRelease; on scope release, a truthy returned cleanup function is invoked through Effect.promise(() => Promise.resolve(cleanup())), otherwise release is Effect.void.attempt<A>(evaluate) returns Effect.tryPromise({ try: evaluate, catch: (cause) => cause }), and RuntimeSchema is Schema.Codec<unknown, unknown>.executePromiseTool wraps tool.execute in Effect.tryPromise, adapts progress via Effect.runPromise(context.progress(update)), and handles failures as follows: a TypedFailure becomes Effect.fail(new Tool.Error({ message, error })), with message selected from string error.feedback, then Error.message, then String(error); all other errors become defects via Effect.die(error)./home/byk/Code/opencode-v2-pilot/packages/core/test/plugin/worktree.test.ts imports Plugin from @opencode/plugin at line 3 and calls PluginPromise.fromPromise( at line 22; /home/byk/Code/opencode-v2-pilot/packages/core/test/plugin.test.ts imports fromPromise from @opencode/plugin/promise/adapter at line 16 and uses it at lines 441, 469, and 499./home/byk/Code/opencode-v2-pilot/packages/core/test/plugin.test.ts covering plugin activation/runtime behavior, including Permission.CorrectedError({ feedback: correctedFeedback }), plugin activation and module creation with Watcher.testLayer, a command transform adding { name: "greet", execute: () => Effect.void }, a test named "disables a plugin whose transform fails after setup without publishing its partial edits", a replay-failure attribution test named "attributes replay failure to the broken plugin rather than a later plugin reading the registry", Promise definitions created with fromPromise, permission-tool execution using session ID Session.ID.make("ses_promise_permission_tool"), and integration transform/connection resolution coverage.ctx.session.hook("prompt", ...) in /home/byk/Code/opencode-v2-pilot/packages/sdk/test/instances.test.ts at lines 38, 166, 242, and 325; Effect ctx.session.hook("context", ...) at line 70 and ctx.session.hook("prompt", ...) at lines 180 and 268 in /home/byk/Code/opencode-v2-pilot/packages/sdk/test/instances-effect.test.ts; Promise ctx.session.hook("prompt", ...) at line 43 in /home/byk/Code/opencode-v2-pilot/packages/core/test/session-activation.test.ts; Effect ctx.shell.hook("create.before", ...) at line 34 in /home/byk/Code/opencode-v2-pilot/packages/core/test/plugin-failure.test.ts; and Effect ctx.session.hook("prompt", ...), ctx.session.hook("context", ...), and ctx.permission.hook("evaluate", ...) at lines 90, 95, and 100 in /home/byk/Code/opencode-v2-pilot/packages/server/test/session-instances.test.ts.