Question
Rework the server plugin entry (src/index.ts) and orchestrator (src/runtime/orchestrator.ts) to the v2 module contract: default export { id, setup(ctx) } instead of { id, server: async (input) => hooks }.
Key work:
- v2 loads only the default export; the
__testOnly named-export workaround is dead code — retire it, moving test seams to wherever the v2 contract offers (constructor injection, or a separate export consumed only by tests via direct import, e.g. a createRuntime() factory in a non-entry module).
- Wire v2 hooks:
ctx.tool.hook("execute.before"|"execute.after", ...) (payloads changed: before has mutable input, rejection via Tool.Error; after has { status, result?/error? } with mutable result), ctx.session.hook("context", ...) for transient injection, ctx.session.synthetic(...) for durable injection (replaces the chat.message hook path), and ctx.session.prompt(..., { resume: false }) for the awaited no-reply admission.
pluginInput.client → the v2 plugin context is itself the client (ctx.session, etc.); adapt src/runtime/client-adapter.ts.
- Note: v2 synthetic messages do NOT run prompt hooks; check whether
chat-capture.ts (which reads chat.message input for model/agent tracking) has a v2 source of truth (e.g. context hook event fields, or ctx.session.context).
- Keep hooks' registration signature aligned with
packages/plugin/src/promise/{tool,session}.ts from the sst/opencode beta branch.
Question
Rework the server plugin entry (
src/index.ts) and orchestrator (src/runtime/orchestrator.ts) to the v2 module contract: default export{ id, setup(ctx) }instead of{ id, server: async (input) => hooks }.Key work:
__testOnlynamed-export workaround is dead code — retire it, moving test seams to wherever the v2 contract offers (constructor injection, or a separate export consumed only by tests via direct import, e.g. acreateRuntime()factory in a non-entry module).ctx.tool.hook("execute.before"|"execute.after", ...)(payloads changed:beforehas mutableinput, rejection via Tool.Error;afterhas{ status, result?/error? }with mutableresult),ctx.session.hook("context", ...)for transient injection,ctx.session.synthetic(...)for durable injection (replaces thechat.messagehook path), andctx.session.prompt(..., { resume: false })for the awaited no-reply admission.pluginInput.client→ the v2 plugin context is itself the client (ctx.session, etc.); adaptsrc/runtime/client-adapter.ts.chat-capture.ts(which readschat.messageinput for model/agent tracking) has a v2 source of truth (e.g.contexthook event fields, orctx.session.context).packages/plugin/src/promise/{tool,session}.tsfrom the sst/opencodebetabranch.