(name: string)
| 1935 | * @throws If marketplace with given name is not found |
| 1936 | */ |
| 1937 | export async function removeMarketplaceSource(name: string): Promise<void> { |
| 1938 | const config = await loadKnownMarketplacesConfig() |
| 1939 | |
| 1940 | if (!config[name]) { |
| 1941 | throw new Error(`Marketplace '${name}' not found`) |
| 1942 | } |
| 1943 | |
| 1944 | // Seed-registered marketplaces are admin-baked into the container — removing |
| 1945 | // them is a category error. They'd resurrect on next startup anyway. Guide |
| 1946 | // the user to the right action instead. |
| 1947 | const entry = config[name] |
| 1948 | const seedDir = seedDirFor(entry.installLocation) |
| 1949 | if (seedDir) { |
| 1950 | throw new Error( |
| 1951 | `Marketplace '${name}' is registered from the read-only seed directory ` + |
| 1952 | `(${seedDir}) and will be re-registered on next startup. ` + |
| 1953 | `To stop using its plugins: claude plugin disable <plugin>@${name}`, |
| 1954 | ) |
| 1955 | } |
| 1956 | |
| 1957 | // Remove from config |
| 1958 | delete config[name] |
| 1959 | await saveKnownMarketplacesConfig(config) |
| 1960 | |
| 1961 | // Clean up cached files (both directory and JSON formats) |
| 1962 | const fs = getFsImplementation() |
| 1963 | const cacheDir = getMarketplacesCacheDir() |
| 1964 | const cachePath = join(cacheDir, name) |
| 1965 | await fs.rm(cachePath, { recursive: true, force: true }) |
| 1966 | const jsonCachePath = join(cacheDir, `${name}.json`) |
| 1967 | await fs.rm(jsonCachePath, { force: true }) |
| 1968 | |
| 1969 | // Clean up settings.json - remove marketplace from extraKnownMarketplaces |
| 1970 | // and remove related plugin entries from enabledPlugins |
| 1971 | |
| 1972 | // Check each editable settings source |
| 1973 | const editableSources: Array< |
| 1974 | 'userSettings' | 'projectSettings' | 'localSettings' |
| 1975 | > = ['userSettings', 'projectSettings', 'localSettings'] |
| 1976 | |
| 1977 | for (const source of editableSources) { |
| 1978 | const settings = getSettingsForSource(source) |
| 1979 | if (!settings) continue |
| 1980 | |
| 1981 | let needsUpdate = false |
| 1982 | const updates: { |
| 1983 | extraKnownMarketplaces?: typeof settings.extraKnownMarketplaces |
| 1984 | enabledPlugins?: typeof settings.enabledPlugins |
| 1985 | } = {} |
| 1986 | |
| 1987 | // Remove from extraKnownMarketplaces if present |
| 1988 | if (settings.extraKnownMarketplaces?.[name]) { |
| 1989 | const updatedMarketplaces: Partial< |
| 1990 | SettingsJson['extraKnownMarketplaces'] |
| 1991 | > = { ...settings.extraKnownMarketplaces } |
| 1992 | // Use undefined values (NOT delete) to signal key removal via mergeWith |
| 1993 | updatedMarketplaces[name] = undefined |
| 1994 | updates.extraKnownMarketplaces = |
no test coverage detected