Skip to content

/status shows mangled plugin names for path-registered plugins on Windows #46560

Description

@CarterLeeAlt

Environment

  • opencode 1.18.25 (Windows x64, installed via npm opencode-ai)
  • OS: Windows 11
  • Same code present in dev branch (packages/tui/src/component/dialog-status.tsx) — not fixed

Bug

Plugins registered by file path in opencode.jsonc are displayed as a truncated path instead of their name in the /status dialog:

// opencode.jsonc
"plugin": [
  "C:/Users/<user>/.config/opencode/plugins/opencode-mem",
  "C:/Users/<user>/.config/opencode/plugins/opencode-provider-proxy"
]

Actual display:

2 Plugins
• C:\Users\<user>\
• C:\Users\<user>\

Expected:

2 Plugins
• opencode-mem
• opencode-provider-proxy

Root cause

packages/tui/src/component/dialog-status.tsx derives the display name like this:

if (value.startsWith("file://")) {
  const path = fileURLToPath(value)          // Windows: "C:\Users\...\opencode-mem" (backslashes)
  const parts = path.split("/")              // ← never splits on Windows
  const filename = parts.pop() || path
  if (!filename.includes(".")) return { name: filename }
  const basename = filename.split(".")[0]    // ← truncated at the FIRST dot of the whole path
  ...
}

On Windows fileURLToPath() returns a backslash path, so split("/") never splits. The fallback
filename.split(".")[0] — intended to strip file extensions — then cuts the whole path at its first
dot (e.g. C:\Users\<user>\.config\...C:\Users\<user>).

Note: the server resolves every local path spec to a file:// URL (resolvePluginSpec in
packages/opencode/src/config/plugin.ts), so all path-registered plugins hit this branch on Windows.
npm-spec plugins are unaffected (name @version branch).

Suggested fix

Make the split separator-agnostic:

- const parts = path.split("/")
+ const parts = path.split(/[\\/]/)

With this, the directory basename opencode-mem (no dot) takes the !filename.includes(".") branch
and is shown as-is. Optionally, for dotted file names the existing split(".")[0] / index handling
can stay as-is.

A more robust alternative: since the server already reads each plugin's package.json
(resolvePluginId / plugin meta), it could send a resolved display name to the TUI instead of
re-deriving it from the spec string client-side.

Metadata

Metadata

Assignees

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