Skip to content

Conversation

@devxoul
Copy link
Contributor

@devxoul devxoul commented Dec 27, 2025

Summary

  • Add backward compatibility for installed_plugins.json v1 format to prevent destructuring errors when loading legacy plugin databases

Problem

The installed_plugins.json file has two versions with different structures:

Version Structure
v1 (legacy) plugins: Record<string, PluginInstallation> (direct object)
v2 (current) plugins: Record<string, PluginInstallation[]> (array)

The current implementation only supports v2 format, causing the following error when running opencode (while loading v1 databases):

TypeError: Cannot destructure property 'installPath' of null or undefined

Workaround (v2.6.0)

If you encounter this error, you can work around it by:

  1. Update Claude Code to the latest version
  2. Run Claude Code once (this will migrate the installed_plugins.json to v2 format)
  3. Run opencode again

Solution

  • Introduce discriminated union types (InstalledPluginsDatabaseV1 / InstalledPluginsDatabaseV2) for proper type narrowing
  • Add extractPluginEntries() helper that handles both formats based on version field
  • TypeScript correctly narrows types when checking db.version === 1

Changes

  • types.ts: Define separate interfaces for v1/v2 with literal version types
  • loader.ts: Add version-aware extraction logic with type narrowing

…ward compatibility

The installed_plugins.json file has two versions:
- v1: plugins stored as direct objects
- v2: plugins stored as arrays

Use discriminated union types (InstalledPluginsDatabaseV1/V2) for proper
type narrowing based on version field.
@github-actions
Copy link
Contributor

github-actions bot commented Dec 27, 2025

All contributors have signed the CLA. Thank you! ✅
Posted by the CLA Assistant Lite bot.

@devxoul
Copy link
Contributor Author

devxoul commented Dec 27, 2025

I have read the CLA Document and I hereby sign the CLA

github-actions bot added a commit that referenced this pull request Dec 27, 2025
@greptile-apps
Copy link

greptile-apps bot commented Dec 27, 2025

Greptile Summary

Added backward compatibility for installed_plugins.json v1 format to prevent destructuring errors when loading legacy plugin databases.

Key changes:

  • Split InstalledPluginsDatabase into discriminated union (InstalledPluginsDatabaseV1 | InstalledPluginsDatabaseV2) with literal version types
  • Added extractPluginEntries() helper that correctly handles both v1 (direct object) and v2 (array) formats based on version field
  • TypeScript type narrowing properly distinguishes between formats when checking db.version === 1

Impact:

  • Fixes TypeError when loading legacy v1 databases where plugins are stored as direct objects instead of arrays
  • Maintains full compatibility with current v2 format
  • Clean, type-safe implementation using discriminated unions

Confidence Score: 5/5

  • This PR is safe to merge with minimal risk
  • The implementation correctly uses TypeScript discriminated unions to handle two database formats. Type narrowing works correctly, the logic properly handles both v1 (direct object) and v2 (array) formats, and the change is focused and non-breaking. Type checking passes, and the solution directly addresses the described TypeError.
  • No files require special attention

Important Files Changed

Filename Overview
src/features/claude-code-plugin-loader/types.ts Split InstalledPluginsDatabase into discriminated union types (V1/V2) with literal version types for proper TypeScript narrowing
src/features/claude-code-plugin-loader/loader.ts Added extractPluginEntries() helper with version-aware logic to handle both v1 (direct object) and v2 (array) plugin formats

Sequence Diagram

sequenceDiagram
    participant Loader as Plugin Loader
    participant FS as File System
    participant Extract as extractPluginEntries()
    participant TypeCheck as TypeScript Type System
    
    Loader->>FS: Read installed_plugins.json
    FS-->>Loader: Return database content
    Loader->>Loader: Parse JSON as InstalledPluginsDatabase
    
    Note over Loader: Union type: V1 | V2
    
    Loader->>Extract: extractPluginEntries(db)
    Extract->>TypeCheck: Check db.version === 1
    
    alt Version 1 (Legacy)
        TypeCheck-->>Extract: Type narrowed to V1
        Note over Extract: plugins: Record<string, PluginInstallation>
        Extract->>Extract: Object.entries(db.plugins)
        Extract->>Extract: Map to [key, installation]
        Extract-->>Loader: Return entries with direct objects
    else Version 2 (Current)
        TypeCheck-->>Extract: Type narrowed to V2
        Note over Extract: plugins: Record<string, PluginInstallation[]>
        Extract->>Extract: Object.entries(db.plugins)
        Extract->>Extract: Map to [key, installations[0]]
        Extract-->>Loader: Return entries with first array element
    end
    
    Loader->>Loader: Iterate over entries
    Loader->>Loader: Process each plugin installation
Loading

@greptile-apps
Copy link

greptile-apps bot commented Dec 27, 2025

Greptile found no issues!

From now on, if a review finishes and we haven't found any issues, we will not post anything, but you can confirm that we reviewed your changes in the status check section.

This feature can be toggled off in your Code Review Settings by deselecting "Create a status check for each PR".

@code-yeongyu
Copy link
Owner

wow, didn't even knew how cc plugin has this kind of version stuff, thanks.

@code-yeongyu code-yeongyu merged commit 735f605 into code-yeongyu:master Dec 27, 2025
7 of 8 checks passed
code-yeongyu added a commit that referenced this pull request Dec 27, 2025
…ward compatibility (#288)

The installed_plugins.json file has two versions:
- v1: plugins stored as direct objects
- v2: plugins stored as arrays

Use discriminated union types (InstalledPluginsDatabaseV1/V2) for proper
type narrowing based on version field.

🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode)
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.

2 participants