Skip to content

OpenCode V2: installer emits a V1 plugin (fails to load) and registers it under the V1 "plugin" key #3732

Description

@dyyptons

Summary

graphify install --platform opencode writes a V1-format OpenCode plugin that OpenCode V2 refuses to load, and registers it in .opencode/opencode.json under the V1 plugin key, which V2 also rejects. The result is a failed server plugin load plus a spurious npm-install error.

Environment

  • OpenCode v2.0.12 (Bun-compiled binary, background service)
  • graphify 0.9.65 (latest on PyPI at the time of writing)

Observed

OpenCode server log (~/.local/share/opencode/log/opencode.log, role=server):

level=WARN message="failed to load plugin"
target=.../.opencode/plugins/graphify.js ref=err_...
cause="Cause([Fail(PluginModule.LoadError: Plugin must export a default definition
with an id and an effect or setup function. (cause: SchemaError(Missing key at ["default"])))])"

A second, separate failure comes from the config registration being treated as an npm package spec:

level=WARN message="failed to load plugin" target=.opencode/plugins/graphify.js
cause="Cause([Fail(NpmInstallFailedError (cause: Error: Could not read package.json:
ENOTDIR: not a directory, open '.../.opencode/plugins/graphify.js/package.json'))])"

Cause

  • OpenCode V2 requires a plugin to default-export a definition with an id and a setup (or effect) function, and hooks are registered on their domain via ctx.tool.hook("execute.before", ...). V1 plugin functions (named export returning a "tool.execute.before" object) no longer run.
  • V2 renamed the shell tool id from bash to shell.
  • graphify/install.py::_OPENCODE_PLUGIN_JS is still the V1 shape.
  • _install_opencode_plugin registers the file under the V1 plugin key using a bare relative path. V2 reads plugins, and a bare path is interpreted as an npm package, producing the NpmInstallFailedError.
  • V2 auto-discovers plugins under .opencode/plugins/, so the config registration is unnecessary.

Suggested fix

  • Emit a V2 default-export plugin. A plain object literal is sufficient; Plugin.define from @opencode/plugin is not resolvable from a loose file under .opencode/plugins/ (no node_modules).
  • Drop the opencode.json registration (auto-discovery handles it), or move it to plugins with a resolvable path.
  • Accept both shell (V2) and bash (V1) tool ids, and use event.input.command instead of output.args.command.

Reference port:

import { existsSync } from "fs";
import { join } from "path";

export default {
  id: "graphify",
  async setup(ctx) {
    let reminded = false;
    await ctx.tool.hook("execute.before", (event) => {
      if (reminded) return;
      if (!existsSync(join(ctx.location.directory, "graphify-out", "graph.json"))) return;
      if (event.tool === "shell" || event.tool === "bash") {
        event.input.command =
          'echo "[graphify] ..." ; ' + event.input.command;
        reminded = true;
      }
    });
  },
};

A local patch to install.py and tests/test_install.py is available on request.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions