Repository navigation
feat: support opencode 2 plugin API - #24
Conversation
|
Depends on #22 for npm installs on opencode 1.x: opencode 1.18 only loads an npm plugin through |
opencode 2 rejects the V1 function export with only a log warning, so the gate silently stopped running. The default export now carries both the V2 id/setup and the V1 server(), and the guard covers the V2 tool names (shell, patch) and the edit/write `path` field.
|
#22 is merged and this branch is rebased onto it. Checked through the npm install path, not a local directory: on opencode 1.19.3 the published 0.7.0 never loads and this build's |
| | | opencode | pi | Claude Code | | ||
| |---|---|---|---| | ||
| | Hook | `tool.execute.before`: bash judged; `edit`, `write` and `apply_patch` checked against the protected paths | `tool_call`, including calls a codemode script makes: bash judged; `edit` and `write` checked against the protected paths | hooks module: `tool.call` on `Bash` and on `Monitor` when it runs a `command`; `Edit`, `Write` and `NotebookEdit` checked against the protected paths; `session.start` freezes the policy, the root and the environment | | ||
| | Hook | 1.x `tool.execute.before`: bash judged; `edit`, `write` and `apply_patch` checked against the protected paths. 2.x `tool.hook("execute.before")`: the same for `shell`, `edit`, `write` and `patch` | `tool_call`, including calls a codemode script makes: bash judged; `edit` and `write` checked against the protected paths | hooks module: `tool.call` on `Bash` and on `Monitor` when it runs a `command`; `Edit`, `Write` and `NotebookEdit` checked against the protected paths; `session.start` freezes the policy, the root and the environment | |
There was a problem hiding this comment.
🟡 nit — The 1.x row says only "bash" is judged; the code now also matches shell on the 1.x path (needed since 1.19.x renamed the tool — 0.7.0 gated nothing there).
|
|
||
| export const SystemOneGate = (async ({ directory, client }) => { | ||
| async function guard(gate: Gate, tool: string, args: Args): Promise<void> { | ||
| if (tool === "bash" || tool === "shell") { |
There was a problem hiding this comment.
✅ good — Matching both bash and shell also fixes 0.7.0 silently gating nothing on opencode 1.19.x, where the Bash tool was renamed to shell.
ReviewSummaryAdds opencode 2.x support to the opencode adapter via one dual-shape default export ( RiskLOW — I verified the opencode 2 contract against the real engine and SDK packages ( Notably, this PR also fixes a pre-existing silent gap: current opencode 1.19.x renamed the Bash tool to Issues
Suggestions
ArchitectureClean consolidation: one shared Inline findingsBerget AI (berget/zai-org/GLM-5.3-Flash) | PR #24 |
|
@berget re-review the opencode adapter port end to end: the V2 setup()/execute.before path, the V1 server() path on opencode 1.18.29–1.19.x (including the bash vs shell tool name), and whether README/SECURITY match the code. |
There was a problem hiding this comment.
# Review
Generated/downloaded the full review above.
**Verdict list (all verified items marked):**
- Appended-bash gating for opencode 1.19: still present in old code — now fixed by `guard()` checking both `bash` and `shell`[]`
Review
Summary
Adds opencode 2 plugin support to the same entrypoint (default export carrying V2 id+setup() and a V1 server(), both funneled through one guard() that accepts both generations' tool and argument names), and updates README/SECURITY/version accordingly.
Risk
LOW — I verified the port against the released @opencode/plugin@2.1.2 type definitions and the official opencode 2 docs (plugins + migrate-v1 + tools): the V2 shape (ctx.location.directory, ctx.tool.hook("execute.before", event: {tool, input}), throw-to-block), the plugins config key, opencode plugin list, and the official statement "V1 object entrypoints are supported in OpenCode 1.18.29" all match the code exactly; notably, current opencode 1.x has no bash tool (its built-in list is shell, edit, write, …, apply_patch), so the old code's "bash"-only check had silently stopped gating on 1.19.x — this PR's tool === "bash" || tool === "shell" check is the required fix and is present.
Issues
- nit
adapters/opencode.ts:20—@opencode/pluginis imported (type-only) but is declared neither in dependencies nor devDependencies; CI never typechecks (andimport typeis erased, so the esbuild bundle checks pass), but any localtsc/IDE run will report an unresolved module. Same pre-existing pattern as@opencode-ai/plugin, so consistency-consistent; cheap fix isnpm i -D @opencode/plugin. - nit
README.md:459— the harness table says 1.x judges "bash", but current 1.x (1.19.x) names the built-in toolshellin its docs and has nobashtool; behavior is correct becauseguard()checks both names, only the table wording is stale.
Suggestions
- None — the dual-spelling extras (
filePath/path,apply_patch/patch) are defensively correct and match the official V2 tool contract (shell→command,edit/write→path,patch→patchText); V2 warning handling ("no toast API, warnings only reach block reasons") is confirmed by both the@opencode/pluginContext type (no TUI domain) andcheck()/checkPath()appendinggate.warningsto reasons; README/SECURITY claims (pluginskey,opencode plugin list,.opencode/plugins/discovery, 1.18.29 minimum,SYSTEMONE_GATE=offhonored bycheckPath) all check out against code and docs.
Berget AI (berget/zai-org/GLM-5.3-Flash) | PR #24
|
|
||
| export const SystemOneGate = (async ({ directory, client }) => { | ||
| async function guard(gate: Gate, tool: string, args: Args): Promise<void> { | ||
| if (tool === "bash" || tool === "shell") { |
There was a problem hiding this comment.
✅ good — Checking both "bash" and "shell" is what fixes gating on opencode 1.19.x — current 1.x has no "bash" built-in, only "shell".
| }) satisfies V1Plugin | ||
|
|
||
| export default SystemOneGate | ||
| export default { |
There was a problem hiding this comment.
✅ good — The dual id/setup()/server() default export matches the officially documented V1+V2 support shape (V1 object entrypoints supported since 1.18.29).
| */ | ||
| import type { Plugin } from "@opencode-ai/plugin" | ||
| import type { Plugin as V1Plugin } from "@opencode-ai/plugin" | ||
| import type { Plugin as V2 } from "@opencode/plugin" |
There was a problem hiding this comment.
🟡 nit — @opencode/plugin is imported for types but not declared in package.json; only fails in local tsc/IDE runs since CI never typechecks and import type is erased.
| | | opencode | pi | Claude Code | | ||
| |---|---|---|---| | ||
| | Hook | `tool.execute.before`: bash judged; `edit`, `write` and `apply_patch` checked against the protected paths | `tool_call`, including calls a codemode script makes: bash judged; `edit` and `write` checked against the protected paths | hooks module: `tool.call` on `Bash` and on `Monitor` when it runs a `command`; `Edit`, `Write` and `NotebookEdit` checked against the protected paths; `session.start` freezes the policy, the root and the environment | | ||
| | Hook | 1.x `tool.execute.before`: bash judged; `edit`, `write` and `apply_patch` checked against the protected paths. 2.x `tool.hook("execute.before")`: the same for `shell`, `edit`, `write` and `patch` | `tool_call`, including calls a codemode script makes: bash judged; `edit` and `write` checked against the protected paths | hooks module: `tool.call` on `Bash` and on `Monitor` when it runs a `command`; `Edit`, `Write` and `NotebookEdit` checked against the protected paths; `session.start` freezes the policy, the root and the environment | |
There was a problem hiding this comment.
🟡 nit — 1.x judges the "shell" tool (no "bash" built-in exists in current 1.x); wording only — guard() gates both names.
There was a problem hiding this comment.
Follow-up review
New changes: 1 commit (3f4977a) — docs-only: README now says the over-2000-char warning appears in block messages always, and at startup only on opencode 1.x.
Previous findings:
- ⏳ nit #1 still present —
@opencode/pluginis still type-only imported and absent frompackage.json(grep confirms no match); untouched by this commit. - ⏳ nit #2 still present — the Harness-differences table still reads "1.x
tool.execute.before: bash judged"; wording remains stale (1.x's built-in isshell).
New findings: None — verified the claim against code: adapters/opencode.ts:11-12 and 72-74 confirm 1.x surfaces config warnings as a load-time toast while 2.x has no toast API, so the new "except on opencode 2, also at startup" wording is accurate, and block-message warnings are appended for both generations (core.ts:503-504, 565-566).
Berget AI (berget/zai-org/GLM-5.3-Flash) | PR #24
Summary
opencode 2 rejects the current plugin with only a log warning, so on 2.x every shell command runs ungated. This ports the opencode adapter so one package serves opencode 1.18.29+ and 2.x.
Changes
Dual export: the default export carries the V2
id/setup(ctx)and the V1server(), following the V1→V2 migration guide. Plugin types are type-only imports, so no runtime dependency is added.V2 tool names: the guard covers
shellandpatchalongsidebashandapply_patch, and checks bothfilePathandpathonedit/write, so a call carrying both cannot slip past on the field the tool ignores.Docs: README covers the
pluginsconfig key, the minimum opencode version,opencode plugin listto confirm the gate loaded, the rootindex.tsthat a manual install needs on 2.x, andBERGET_API_KEYon 2.x (it never refreshes the 1.x seat token). SECURITY.md notes that opencode 2 skips a plugin that fails to load and lets bash run ungated.Version: 0.8.0 in
package.jsonand.claude-plugin/plugin.json, so the next release ships opencode 2 support and the./serverexport from fix: export ./server so opencode loads the plugin from npm #22.