Something went wrong. Try again.
source dump of claude code forked from oppi.li/claude-code
Something went wrong. Try again.
4.4 kB · 127 lines
TypeScript
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128/** * Plugin delisting detection. * * Compares installed plugins against marketplace manifests to find plugins * that have been removed, and auto-uninstalls them. * * The security.json fetch was removed (see #25447) — ~29.5M/week GitHub hits * for UI reason/text only. If re-introduced, serve from downloads.claude.ai. */
import { uninstallPluginOp } from '../../services/plugins/pluginOperations.js'import { logForDebugging } from '../debug.js'import { errorMessage } from '../errors.js'import { loadInstalledPluginsV2 } from './installedPluginsManager.js'import { getMarketplace, loadKnownMarketplacesConfigSafe,} from './marketplaceManager.js'import { addFlaggedPlugin, getFlaggedPlugins, loadFlaggedPlugins,} from './pluginFlagging.js'import type { InstalledPluginsFileV2, PluginMarketplace } from './schemas.js'
/** * Detect plugins installed from a marketplace that are no longer listed there. * * @param installedPlugins All installed plugins * @param marketplace The marketplace to check against * @param marketplaceName The marketplace name suffix (e.g. "claude-plugins-official") * @returns List of delisted plugin IDs in "name@marketplace" format */export function detectDelistedPlugins( installedPlugins: InstalledPluginsFileV2, marketplace: PluginMarketplace, marketplaceName: string,): string[] { const marketplacePluginNames = new Set(marketplace.plugins.map(p => p.name)) const suffix = `@${marketplaceName}`
const delisted: string[] = [] for (const pluginId of Object.keys(installedPlugins.plugins)) { if (!pluginId.endsWith(suffix)) continue
const pluginName = pluginId.slice(0, -suffix.length) if (!marketplacePluginNames.has(pluginName)) { delisted.push(pluginId) } }
return delisted}
/** * Detect delisted plugins across all marketplaces, auto-uninstall them, * and record them as flagged. * * This is the core delisting enforcement logic, shared between interactive * mode (useManagePlugins) and headless mode (main.tsx print path). * * @returns List of newly flagged plugin IDs */export async function detectAndUninstallDelistedPlugins(): Promise<string[]> { await loadFlaggedPlugins()
const installedPlugins = loadInstalledPluginsV2() const alreadyFlagged = getFlaggedPlugins() // Read-only iteration — Safe variant so a corrupted config doesn't throw // out of this function (it's called in the same try-block as loadAllPlugins // in useManagePlugins, so a throw here would void loadAllPlugins' resilience). const knownMarketplaces = await loadKnownMarketplacesConfigSafe() const newlyFlagged: string[] = []
for (const marketplaceName of Object.keys(knownMarketplaces)) { try { const marketplace = await getMarketplace(marketplaceName)
if (!marketplace.forceRemoveDeletedPlugins) continue
const delisted = detectDelistedPlugins( installedPlugins, marketplace, marketplaceName, )
for (const pluginId of delisted) { if (pluginId in alreadyFlagged) continue
// Skip managed-only plugins — enterprise admin should handle those const installations = installedPlugins.plugins[pluginId] ?? [] const hasUserInstall = installations.some( i => i.scope === 'user' || i.scope === 'project' || i.scope === 'local', ) if (!hasUserInstall) continue
// Auto-uninstall the delisted plugin from all user-controllable scopes for (const installation of installations) { const { scope } = installation if (scope !== 'user' && scope !== 'project' && scope !== 'local') { continue } try { await uninstallPluginOp(pluginId, scope) } catch (error) { logForDebugging( `Failed to auto-uninstall delisted plugin ${pluginId} from ${scope}: ${errorMessage(error)}`, { level: 'error' }, ) } }
await addFlaggedPlugin(pluginId) newlyFlagged.push(pluginId) } } catch (error) { // Marketplace may not be available yet — log and continue logForDebugging( `Failed to check for delisted plugins in "${marketplaceName}": ${errorMessage(error)}`, { level: 'warn' }, ) } }
return newlyFlagged}