Skip to content

TUI plugin fails to load on registry installs: dist/tui.js statically imports @opentui/solid, which is only in devDependencies #35

Closed

Description

@rodrigocora

Summary

dist/tui.js (the ./tui entrypoint) statically imports @opentui/solid at runtime, but @opentui/solid is declared only in devDependencies. Any plain registry install (dev deps omitted) therefore cannot resolve it, and the TUI plugin fails to load.

Environment

  • opencode-rag-plugin 2.4.4 (current latest)
  • Node v24.19.0 / npm 12.0.2, Linux x64
  • Installed as a regular dependency in ~/.opencode (standard OpenCode V2 plugin layout: a shim in plugins/ that re-exports ../node_modules/opencode-rag-plugin/dist/tui.js)

Reproduction

  1. npm install opencode-rag-plugin in any directory (no dev deps).
  2. Load the TUI entrypoint from an OpenCode plugin shim: import plugin from '../node_modules/opencode-rag-plugin/dist/tui.js'.
  3. The OpenCode server log reports:
    failed to load plugin ... cause="Cause([Die(ResolveMessage: Cannot find package '@opentui/solid' imported from <dir>/node_modules/opencode-rag-plugin/dist/tui.js)])"

Root cause

dist/tui.js, line 5:

import { createElement, insert, setProp } from "@opentui/solid";

@opentui/solid is listed under devDependencies in package.json. npm omits devDependencies for regular and global installs, so the bare specifier is unresolvable at runtime in those installs.

Note: the failure is masked when (a) a global install was created with --include=dev, or (b) the package is symlinked into a tree whose real path already contains @opentui/* (Node walks up from the real path). That is why it surfaces specifically for plain registry/local installs.

Only dist/tui.js is affected: the core server plugin (dist/plugin-entry.js) has no @opentui imports and loads fine. (@opentui/core/@opentui/keymap are also devDependencies, but 2.4.4 has no runtime imports of them — verified by scanning dist/.)

Suggested fix

Move @opentui/solid from devDependencies to dependencies (and keep core/keymap in sync if they ever become runtime imports), or make the @opentui import lazy (dynamic import() only when the TUI is actually rendered).

Workaround (until fixed)

Install the missing peer alongside the plugin package:

npm install @opentui/solid@^0.5.11

Activity

  1. MrDoe commented on Oct 19, 2026

    @MrDoe
    Owner

    Fixed in v2.4.5 — thank you for the pinpoint report, @rodrigocora. The devDependencies analysis and the ResolveMessage trace made this a five-minute diagnosis.

    Your root cause is exactly right, and while reproducing it with a clean registry install we found a second, independent breakage on OpenCode 2. Both are fixed:

    1. @opentui/solid is now imported lazily

    dist/tui.js no longer touches @opentui/solid at module scope. The import moved inside loadOpenTui(), which is only reached from the TUI branch of setup() (which returns early for server-role loads). Verified by copying dist/ into a tree with no node_modules at all: the module imports cleanly, server-role setup({}) is a no-op, and only the TUI path attempts the import — where OpenCode's runtime provides it.

    @opentui/core, @opentui/solid and solid-js are now declared as optional peerDependencies (>=0.5.10, matching what @opencode/plugin itself requires):

    "peerDependenciesMeta": {
      "@opentui/core": { "optional": true },
      "@opentui/solid": { "optional": true },
      "solid-js": { "optional": true }
    }

    The OpenCode TUI runtime rewrites these specifiers from its own bundle (@opentui/core/runtime-plugin.js handles them, dynamic imports included), so plain registry installs never need to resolve them locally — which is also why the bug only ever surfaced outside --include=dev / symlinked trees, exactly as you observed.

    2. OpenCode 2 loads TUI plugins only from directories (found while testing your shim layout)

    OpenCode 2's TUI discovery (packages/tui/src/plugin/discovery.ts) keeps only directories/symlinks under .opencode/plugins/ — a flat *.js file registers in the server role only, silently. Workspaces initialized by older versions had exactly that flat layout, so even with the import fixed the sidebar would never appear. init / setup now write:

    .opencode/plugins/opencode-rag/
    ├── index.js   ← server role
    └── tui.js     ← terminal UI
    

    and migrate the V1 flat entries + .opencode/tui.json away — but only when a file's content exactly matches what the old init generated, so anything hand-written is kept and reported.

    While in there

    • providers/models are read from data.location.provider/model.list(location) (legacy shape kept as fallback)
    • the sidebar now reports the plugin's own version instead of context.app.version (which is OpenCode's own)

    Updating

    npm update -g opencode-rag-plugin    # or: npm install opencode-rag-plugin@latest in ~/.opencode
    opencode-rag setup                   # re-sync the runtime symlink
    opencode-rag init                    # rewrite the workspace plugin files in the new directory layout

    For your ~/.opencode dependency install, updating the package there is enough — your shim keeps working, since the @opentui/solid import is now deferred to the TUI setup path, where OpenCode's runtime resolves it.

    Restart OpenCode afterwards and you should get the sidebar back, plus the settings dialog (ctrl+shift+r), the file-list injector (ctrl+enter) and the RAG-chunks injector (ctrl+alt+enter). Plugin load failures still land in ~/.local/share/opencode/log/opencode.log, and doc/troubleshooting.md now documents the expected layout if anything looks off.

    Thanks again — reports like this are why the fix ended up covering both failure modes. 🙏

  2. self-assigned this
    on Oct 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions