fix(plugin-loader): support Claude Code v3 flat array format for installed_plugins.json

This commit is contained in:
Robin Mordasiewicz
2026-03-14 04:40:27 +00:00
parent 913fcf270d
commit a7f0a4cf46
2 changed files with 45 additions and 4 deletions

View File

@@ -4,6 +4,7 @@ import { join } from "path"
import { log } from "../../shared/logger"
import type {
InstalledPluginsDatabase,
InstalledPluginEntryV3,
PluginInstallation,
PluginManifest,
LoadedPlugin,
@@ -96,9 +97,26 @@ function isPluginEnabled(
return true
}
function v3EntryToInstallation(entry: InstalledPluginEntryV3): PluginInstallation {
return {
scope: entry.scope,
installPath: entry.installPath,
version: entry.version,
installedAt: entry.lastUpdated,
lastUpdated: entry.lastUpdated,
gitCommitSha: entry.gitCommitSha,
}
}
function extractPluginEntries(
db: InstalledPluginsDatabase,
): Array<[string, PluginInstallation | undefined]> {
if (Array.isArray(db)) {
return db.map((entry) => [
`${entry.name}@${entry.marketplace}`,
v3EntryToInstallation(entry),
])
}
if (db.version === 1) {
return Object.entries(db.plugins).map(([key, installation]) => [key, installation])
}
@@ -111,7 +129,7 @@ export function discoverInstalledPlugins(options?: PluginLoaderOptions): PluginL
const plugins: LoadedPlugin[] = []
const errors: PluginLoadError[] = []
if (!db || !db.plugins) {
if (!db || (!Array.isArray(db) && !db.plugins)) {
return { plugins, errors }
}

View File

@@ -30,19 +30,42 @@ export interface InstalledPluginsDatabaseV1 {
}
/**
* Installed plugins database v2 (current)
* plugins stored as arrays
* Installed plugins database v2
* plugins stored as arrays keyed by plugin identifier
*/
export interface InstalledPluginsDatabaseV2 {
version: 2
plugins: Record<string, PluginInstallation[]>
}
/**
* Installed plugins database v3 entry (current Claude Code format)
* A flat array of plugin entries, each containing name and marketplace fields
* used to construct the plugin key as "name@marketplace".
*/
export interface InstalledPluginEntryV3 {
name: string
marketplace: string
scope: PluginScope
version: string
installPath: string
lastUpdated: string
gitCommitSha?: string
}
/**
* Installed plugins database structure
* Located at ~/.claude/plugins/installed_plugins.json
*
* Supports three formats:
* - v1: { version: 1, plugins: Record<string, PluginInstallation> }
* - v2: { version: 2, plugins: Record<string, PluginInstallation[]> }
* - v3: InstalledPluginEntryV3[] (flat array, current Claude Code format)
*/
export type InstalledPluginsDatabase = InstalledPluginsDatabaseV1 | InstalledPluginsDatabaseV2
export type InstalledPluginsDatabase =
| InstalledPluginsDatabaseV1
| InstalledPluginsDatabaseV2
| InstalledPluginEntryV3[]
/**
* Plugin author information