Skip to content

Conversation

@sgwannabe
Copy link

@sgwannabe sgwannabe commented Jan 10, 2026

Summary

Add CLI commands for managing OpenCode plugins, addressing the need for easy plugin updates without manual config editing.

Fixes #6159

Changes

Add opencode plugin subcommand with:

  • list - List installed plugins with current/latest version comparison
  • update [name] - Update all or specific plugin to latest version
  • add <name> - Add a plugin to config
  • remove <name> - Remove a plugin from config

Implementation Details

  • Uses existing utilities: Config.getPluginName() for consistent name extraction, BunProc.install() for package installation
  • Scoped package support: URL-encodes package names for npm registry fetches (@scope/pkg%40scope%2Fpkg)
  • Input normalization: update [email protected] and remove [email protected] correctly match foo plugin
  • Config validation: Safely handles non-array plugin field
  • Atomic config writes: Uses temp file + rename pattern to prevent corruption
  • Proper error handling: Distinguishes ENOENT (create new) from JSON parse errors (throw)
  • Truthful status reporting: Shows "latest unknown" when registry fetch fails instead of "up to date"
  • Spinner lifecycle: Properly stops spinner before re-starting

Demo Output

$ opencode plugin list
┌  Installed Plugins
◇  Version check complete
│
●  ✓ oh-my-opencode 2.14.0
●  ⬆ opencode-anthropic-auth 0.0.7 → 0.0.8
●  ! @scope/plugin 1.0.0 (latest unknown)
│
└  3 plugin(s), 1 update(s) available, 1 check(s) failed. Run: opencode plugin update

$ opencode plugin update
┌  Update Plugins
●    opencode-anthropic-auth 0.0.7 → 0.0.8
◇  ✓ opencode-anthropic-auth updated to 0.0.8
│
└  1 plugin(s) updated

How to verify

# List plugins and their versions
opencode plugin list

# Add a new plugin
opencode plugin add example-plugin

# Update all plugins
opencode plugin update

# Update specific plugin (accepts name with or without version)
opencode plugin update oh-my-opencode
opencode plugin update [email protected]  # also works

# Remove a plugin (accepts name with or without version)
opencode plugin remove example-plugin
opencode plugin remove [email protected]  # also works

Testing Done

  • plugin list - shows installed plugins with version info
  • plugin list - shows "latest unknown" when fetch fails
  • plugin update - updates all plugins to latest
  • plugin update <name> - updates specific plugin
  • plugin update <name>@<version> - normalizes input correctly
  • plugin add <name> - installs and adds plugin to config
  • plugin add <name>@<version> - installs specific version
  • plugin remove <name> - removes plugin from config
  • plugin remove <name>@<version> - normalizes input correctly
  • Error case: plugin not found (shows available plugins)
  • Error case: npm fetch failure (reports as skipped)
  • Local file:// plugins are skipped appropriately
  • Typecheck passes

@github-actions
Copy link
Contributor

The following comment was made by an LLM, it may be inaccurate:

No duplicate PRs found

@sgwannabe sgwannabe force-pushed the feat/plugin-management-cli branch from 6766492 to 988c76c Compare January 10, 2026 09:52
Add `opencode plugin` subcommand with:
- list: List installed plugins with current/latest version comparison
- update [name]: Update all or specific plugin to latest version
- add <name>: Add a plugin to config
- remove <name>: Remove a plugin from config

Implementation details:
- Use Config.getPluginName() for consistent name extraction
- URL-encode scoped packages for npm registry fetches
- Normalize user input (e.g., '[email protected]' matches 'foo')
- Validate config.plugin is array before processing
- Atomic config writes (temp file + rename)
- Proper error handling and status reporting
- Fix spinner lifecycle (stop before re-start)
- Show 'latest unknown' when registry fetch fails

Fixes anomalyco#6159
@sgwannabe sgwannabe force-pushed the feat/plugin-management-cli branch from 988c76c to 10e0f75 Compare January 10, 2026 10:01
Copy link

@henry-hsieh henry-hsieh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR is pretty helpful to install plugins without open TUI. I have some suggestions to the changes.

async function fetchLatestVersion(pkg: string): Promise<string | null> {
try {
const encodedPkg = encodeURIComponent(pkg).replace("%40", "@")
const response = await fetch(`https://registry.npmjs.org/${encodedPkg}/latest`, {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the registry should respect how the npm is configured like this code block.

Comment on lines +51 to +70
async function readGlobalConfig(): Promise<{ filePath: string; data: Config.Info }> {
const filePath = path.join(Global.Path.config, "opencode.json")
try {
const text = await fs.readFile(filePath, "utf-8")
const data = JSON.parse(text) as Config.Info
return { filePath, data }
} catch (err: unknown) {
if ((err as NodeJS.ErrnoException).code === "ENOENT") {
return { filePath, data: {} }
}
throw err
}
}

async function writeGlobalConfig(filePath: string, data: Config.Info): Promise<void> {
await fs.mkdir(path.dirname(filePath), { recursive: true })
const tempPath = `${filePath}.tmp.${process.pid}`
await fs.writeFile(tempPath, JSON.stringify(data, null, 2))
await fs.rename(tempPath, filePath)
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Directly modifying global config seems a little weird. OpenCode merges several configs into one internal config.

I think following 3 configs should be considered:
Global config (~/.config/opencode/opencode.json) - user preferences
Custom config (OPENCODE_CONFIG env var) - custom overrides
Project config (opencode.json in project) - project-specific settings

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Plugin Auto-Update Feature

2 participants