Skip to content

Plugin silently fails to load on Node.js runtime — no slash commands, no tools, no error #40

Description

@woohahahaaa

Summary

I installed opencode-pty following the README verbatim, with the $schema and plugin fields set exactly as documented:

{
  "$schema": "https://opencode.ai/config.json",
  "plugin": ["opencode-pty"]
}

The plugin silently fails to load. The async PTYPlugin factory is never invoked, so:

  • the config hook that registers pty-open-background-spy / pty-show-server-url never runs,
  • the tool block (pty_spawn, pty_read, pty_write, pty_list, pty_kill) is never registered,
  • the command.execute.before interceptor is never installed.

opencode still lists the plugin under its loaded-plugins set, but no error is shown in the TUI — the failure is completely invisible to the user.

How I diagnosed it

I narrowed the failure to the plugin module by checking the command palette: typing /pty-open in the prompt shows no /pty-open-background-spy (or /pty-show-server-url) entry in the candidate list. Since the only path that adds these commands is the plugin's config hook, their absence proves the PTYPlugin function was never called. Same for the agent tools — the AI has no pty_spawn etc. available.

Tracing further:

  • package.json main: dist/index.js

  • dist/index.jsdist/src/plugin.js

  • dist/src/plugin.jsimport { initManager, manager } from "./plugin/pty/manager.js"

  • dist/src/plugin/pty/manager.js opens with:

    import { semver } from 'bun';                        // ← throws on Node
    import { Terminal } from 'bun-pty';                  // ← needs bun:ffi
    import { version as bunPtyVersion } from 'bun-pty/package.json';

Under Node.js, import { semver } from 'bun' throws ERR_MODULE_NOT_FOUND immediately at module load time. The exception propagates out of the top-level import, the entire plugin module never finishes loading, and PTYPlugin is never reached.

Verified directly:

$ node -e "require('bun')"
Error: Cannot find module 'bun'
code: 'MODULE_NOT_FOUND'

Environment

Item Value
OS Windows 11 (win32)
opencode 1.17.7 (opencode-ai npm package)
Plugin opencode-pty@0.3.4
Bun 1.3.14 installed on the system, but not used to launch opencode (see below)
Config ~/.config/opencode/opencode.json with $schema and plugin fields set per README

Why "use Bun" is not a real workaround for the documented install

opencode-ai@1.17.7 is a standard Node application. bun add -g opencode-ai only installs the same Node binary under Bun's global modules; running opencode (or ~/.bun/bin/opencode.exe) still spawns a Node process. To get the plugin to actually load, a user has to know to launch with bun --bun x opencode-ai (or bunx opencode-ai) — which is not mentioned anywhere in the README, and is not flagged by package.json engines (it only specifies "opencode": ">=1.3.13").

Following the documented install produces a broken setup for the majority of users on every OS.

Suggested fixes (any one of these)

  1. Lazy / dynamic import the Bun-specific bits. Replace the top-level import { semver } from 'bun' with a await import('bun') that only runs when actually needed, and guard the Terminal.prototype._startReadLoop monkey-patch. The plugin would still load under Node; the tools would fail at runtime with a clear error, but the config hook would still register the slash commands.

  2. Polyfill semver. The Bun.semver import is only used to compare bun-pty versions (semver.order(bunPtyVersion, '0.4.8')). A simple split+Number comparison or the semver npm package would do.

  3. Detect-and-warn at load time. Wrap the Bun-specific imports in a try/catch, log a clear warning (something like [opencode-pty] ⚠ Plugin loaded but the PTY backend is NOT available), and skip the tool registration. The config hook should still run so the slash commands at least show up and the user gets a clear message instead of a silent no-op.

  4. Document the runtime requirement prominently. The README installation snippet should make it explicit that the user must run opencode via bunx opencode-ai (or bun --bun opencode), not just opencode.

Option (1) is the smallest change with the biggest user-visible win. Option (3) is the most defensive.

Reference: relevant files

  • src/plugin.ts — exports PTYPlugin, registers the config hook
  • src/plugin/pty/manager.ts — source that compiles to the file with the offending import { semver } from 'bun'
  • package.jsonengines.opencode: ">=1.3.13" does not advertise the Bun runtime requirement

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions