diff --git a/src/features/claude-code-agent-loader/loader.ts b/src/features/claude-code-agent-loader/loader.ts index ef84995cb..d2ef89b03 100644 --- a/src/features/claude-code-agent-loader/loader.ts +++ b/src/features/claude-code-agent-loader/loader.ts @@ -43,12 +43,15 @@ function loadAgentsFromDir(agentsDir: string, scope: AgentScope): LoadedAgent[] const formattedDescription = `(${scope}) ${originalDescription}` const mappedModelOverride = mapClaudeModelToOpenCode(data.model) + const modelString = mappedModelOverride + ? `${mappedModelOverride.providerID}/${mappedModelOverride.modelID}` + : undefined const config: ClaudeCodeAgentConfig = { description: formattedDescription, mode: data.mode || "subagent", prompt: body.trim(), - ...(mappedModelOverride ? { model: mappedModelOverride } : {}), + ...(modelString ? { model: modelString } : {}), } const toolsConfig = parseToolsConfig(data.tools) diff --git a/src/features/claude-code-plugin-loader/agent-loader.ts b/src/features/claude-code-plugin-loader/agent-loader.ts index 215e29d1b..1aff57e0c 100644 --- a/src/features/claude-code-plugin-loader/agent-loader.ts +++ b/src/features/claude-code-plugin-loader/agent-loader.ts @@ -47,12 +47,15 @@ export function loadPluginAgents(plugins: LoadedPlugin[]): Record).name === "string" && + typeof (entry as Record).marketplace === "string" && + typeof (entry as Record).installPath === "string" + ) +} + function extractPluginEntries( db: InstalledPluginsDatabase, ): Array<[string, PluginInstallation | undefined]> { + if (Array.isArray(db)) { + return db + .filter(isValidV3Entry) + .map((entry) => [ + `${entry.name}@${entry.marketplace}`, + v3EntryToInstallation(entry), + ]) + } if (db.version === 1) { return Object.entries(db.plugins).map(([key, installation]) => [key, installation]) } @@ -111,7 +141,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 } } diff --git a/src/features/claude-code-plugin-loader/types.ts b/src/features/claude-code-plugin-loader/types.ts index f384f4ef6..9a6d5ee1c 100644 --- a/src/features/claude-code-plugin-loader/types.ts +++ b/src/features/claude-code-plugin-loader/types.ts @@ -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 } +/** + * 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 } + * - v2: { version: 2, plugins: Record } + * - v3: InstalledPluginEntryV3[] (flat array, current Claude Code format) */ -export type InstalledPluginsDatabase = InstalledPluginsDatabaseV1 | InstalledPluginsDatabaseV2 +export type InstalledPluginsDatabase = + | InstalledPluginsDatabaseV1 + | InstalledPluginsDatabaseV2 + | InstalledPluginEntryV3[] /** * Plugin author information