MCPcopy
hub / github.com/codeaashu/claude-code / addMarketplaceSource

Function addMarketplaceSource

src/utils/plugins/marketplaceManager.ts:1782–1924  ·  view source on GitHub ↗
(
  source: MarketplaceSource,
  onProgress?: MarketplaceProgressCallback,
)

Source from the content-addressed store, hash-verified

1780 * @throws If source format is invalid or marketplace cannot be loaded
1781 */
1782export async function addMarketplaceSource(
1783 source: MarketplaceSource,
1784 onProgress?: MarketplaceProgressCallback,
1785): Promise<{
1786 name: string
1787 alreadyMaterialized: boolean
1788 resolvedSource: MarketplaceSource
1789}> {
1790 // Resolve relative directory/file paths to absolute so state is cwd-independent
1791 let resolvedSource = source
1792 if (isLocalMarketplaceSource(source) && !isAbsolute(source.path)) {
1793 resolvedSource = { ...source, path: resolve(source.path) }
1794 }
1795
1796 // Check policy FIRST, before any network/filesystem operations
1797 // This prevents downloading/cloning when the source is blocked
1798 if (!isSourceAllowedByPolicy(resolvedSource)) {
1799 // Check if explicitly blocked vs not in allowlist for better error messages
1800 if (isSourceInBlocklist(resolvedSource)) {
1801 throw new Error(
1802 `Marketplace source '${formatSourceForDisplay(resolvedSource)}' is blocked by enterprise policy.`,
1803 )
1804 }
1805 // Not in allowlist - build helpful error message
1806 const allowlist = getStrictKnownMarketplaces() || []
1807 const hostPatterns = getHostPatternsFromAllowlist()
1808 const sourceHost = extractHostFromSource(resolvedSource)
1809
1810 let errorMessage = `Marketplace source '${formatSourceForDisplay(resolvedSource)}'`
1811 if (sourceHost) {
1812 errorMessage += ` (${sourceHost})`
1813 }
1814 errorMessage += ' is blocked by enterprise policy.'
1815
1816 if (allowlist.length > 0) {
1817 errorMessage += ` Allowed sources: ${allowlist.map(s => formatSourceForDisplay(s)).join(', ')}`
1818 } else {
1819 errorMessage += ' No external marketplaces are allowed.'
1820 }
1821
1822 // If source is a github shorthand and there are hostPatterns, suggest using full URL
1823 if (resolvedSource.source === 'github' && hostPatterns.length > 0) {
1824 errorMessage +=
1825 `\n\nTip: The shorthand "${resolvedSource.repo}" assumes github.com. ` +
1826 `For internal GitHub Enterprise, use the full URL:\n` +
1827 ` git@your-github-host.com:${resolvedSource.repo}.git`
1828 }
1829
1830 throw new Error(errorMessage)
1831 }
1832
1833 // Source-idempotency: if this exact source already exists, skip clone
1834 const existingConfig = await loadKnownMarketplacesConfig()
1835 for (const [existingName, existingEntry] of Object.entries(existingConfig)) {
1836 if (isEqual(existingEntry.source, resolvedSource)) {
1837 logForDebugging(
1838 `Source already materialized as '${existingName}', skipping clone`,
1839 )

Callers 5

reconcileMarketplacesFunction · 0.85
handleAddFunction · 0.85
checkAndInstallFunction · 0.85
marketplaceAddHandlerFunction · 0.85

Calls 15

isLocalMarketplaceSourceFunction · 0.85
isSourceAllowedByPolicyFunction · 0.85
isSourceInBlocklistFunction · 0.85
formatSourceForDisplayFunction · 0.85
extractHostFromSourceFunction · 0.85
logForDebuggingFunction · 0.85
loadAndCacheMarketplaceFunction · 0.85
seedDirForFunction · 0.85

Tested by

no test coverage detected