mirror of
https://github.com/max-sixty/worktrunk.git
synced 2026-09-14 20:00:38 +08:00
8e420cb8c4
## Problem `wt config plugins opencode install` writes a plugin OpenCode 2 silently ignores, reported in #4014. OpenCode 2's loader decodes a plugin module's default export against a schema that accepts `{ id, effect }` or `{ id, setup }` — a bare default-exported function, which is what this plugin has always been, fails the decode and the load is dropped without a message ([`packages/core/src/plugin/module.ts#L60`](https://github.com/sst/opencode/blob/b2cecc6350d377c382e1ec32ee66ec63ad68f715/packages/core/src/plugin/module.ts#L60) on the `beta` branch, which is where the OpenCode 2 prereleases come from — `dev` is the 1.18.x line). The plugin also ran `wt` through Bun's `$`, which the host only supplies when it is itself running under Bun. ## Solution One file, both runtimes: the default export is now `{ id, setup, server }`, and `wt` is spawned with `node:child_process` instead of Bun's shell. OpenCode 2 reads `setup` and subscribes to session events; OpenCode 1.16+ reads `server` and gets exactly the hooks it has today. Each version ignores the other's key, so the install path, filename, and marker behavior are all unchanged. Two details in the `setup` arm that differ from the port in the issue's thread — both from reading the shipped `@opencode-ai/plugin@beta` types: `session.status` carries `status.type ∈ {idle, busy, retry}` and `session.idle` is annotated deprecated, so the status is read rather than the event name; and `session.status` with an `idle` status sets 💬 rather than 🤖. **The part worth a maintainer's call**: this keeps the OpenCode 1 shape rather than switching cleanly to v2 alone. OpenCode 2 is still prerelease (`npm dist-tags` for `@opencode-ai/plugin`: `latest` 1.18.29, `beta` 0.0.0-beta-19192), so a v2-only file would make every current stable install fail with `Plugin … must default export an object with server()`. The cost is the `server` arm plus its two local types — say the word and I will cut it to `{ id, setup }`. Either way OpenCode below 1.14.19 loses the plugin: that is where `readV1Plugin` — the function that admits an object-shaped default export — first appears, and older releases accept only the bare function. 1.16 is the floor worth documenting, though, because it is where the host began filtering events to each plugin instance's directory ([v1.16.0](https://github.com/sst/opencode/blob/6cb74317a6efacd656483cb0489d8e7e3701c12e/packages/opencode/src/plugin/index.ts#L258-L259)); [v1.15.0](https://github.com/sst/opencode/blob/2662a4f955e563fd22cd5c4873ca350d21745275/packages/opencode/src/plugin/index.ts#L246) fans every bus event to every instance, so on 1.14.19–1.15.x the marker follows the worktree the instance was created for rather than the session that is active — the same behavior today's plugin has, not a regression. ## Verification `cargo test --test integration test_docs_are_in_sync`, the twelve `opencode` integration tests, and `packaged_assets` pass. Beyond that I ran the new file through both loaders' own logic under `node --experimental-strip-types`, with a stub `wt` on `PATH` recording its arguments. <details><summary>Loader checks and recorded marker calls</summary> Decoding the real module with the exact schema OpenCode 2 uses (`effect@4.0.0-rc.112`, the version its plugin package depends on), and with OpenCode 1's [`readV1Plugin`](https://github.com/sst/opencode/blob/337fd144d2ba144743368f78d9579a99cce175bd/packages/opencode/src/plugin/shared.ts#L272) detect-mode logic: ``` OpenCode 2 module decode : ok, id=worktrunk OpenCode 1 readV1Plugin : ok, id=worktrunk v2 setup returned cleanup: true v2 setup on a 1.18 context: bails, no throw ``` The last line covers a case worth calling out: OpenCode 1.18 also carries a `{ id, setup }` loader, but the context it passes has neither `location` nor `event`. `setup` returns early there instead of throwing, and `server` drives the marker. Feeding a fake event stream, the commands the plugin actually issued: ``` v2: set 🤖 (status busy) set 🤖 (status retry) set 💬 (status idle) — skipped, event location is another worktree — set 💬 (session.idle) clear (session.deleted) clear (cleanup) v1: set 🤖 / set 💬 / clear (unchanged from today) ``` What I could not check from CI is the plugin running inside a real OpenCode 2 session — @pragmaticivan, if you are still up for testing, `wt config plugins opencode install` off this branch should behave the same as your local port. Install location is unchanged and confirmed on `beta`: plugins are still discovered as `.ts`/`.js` files under `plugin/`, `plugins/` in each config directory ([`source-directory.ts#L7`](https://github.com/sst/opencode/blob/b2cecc6350d377c382e1ec32ee66ec63ad68f715/packages/core/src/plugin/source-directory.ts#L7)). </details> Closes #4014 --------- Co-authored-by: worktrunk-bot <254187624+worktrunk-bot@users.noreply.github.com>
4.8 KiB
4.8 KiB