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

Function copyPluginToVersionedCache

src/utils/plugins/pluginLoader.ts:365–465  ·  view source on GitHub ↗
(
  sourcePath: string,
  pluginId: string,
  version: string,
  entry?: PluginMarketplaceEntry,
  marketplaceDir?: string,
)

Source from the content-addressed store, hash-verified

363 * @throws Error if the destination directory is empty after copy
364 */
365export async function copyPluginToVersionedCache(
366 sourcePath: string,
367 pluginId: string,
368 version: string,
369 entry?: PluginMarketplaceEntry,
370 marketplaceDir?: string,
371): Promise<string> {
372 // When zip cache is enabled, the canonical format is a ZIP file
373 const zipCacheMode = isPluginZipCacheEnabled()
374 const cachePath = getVersionedCachePath(pluginId, version)
375 const zipPath = getVersionedZipCachePath(pluginId, version)
376
377 // If cache already exists (directory or ZIP), return it
378 if (zipCacheMode) {
379 if (await pathExists(zipPath)) {
380 logForDebugging(
381 `Plugin ${pluginId} version ${version} already cached at ${zipPath}`,
382 )
383 return zipPath
384 }
385 } else if (await pathExists(cachePath)) {
386 const entries = await readdir(cachePath)
387 if (entries.length > 0) {
388 logForDebugging(
389 `Plugin ${pluginId} version ${version} already cached at ${cachePath}`,
390 )
391 return cachePath
392 }
393 // Directory exists but is empty, remove it so we can recreate with content
394 logForDebugging(
395 `Removing empty cache directory for ${pluginId} at ${cachePath}`,
396 )
397 await rmdir(cachePath)
398 }
399
400 // Seed cache hit — return seed path in place (read-only, no copy).
401 // Callers handle both directory and .zip paths; this returns a directory.
402 const seedPath = await probeSeedCache(pluginId, version)
403 if (seedPath) {
404 logForDebugging(
405 `Using seed cache for ${pluginId}@${version} at ${seedPath}`,
406 )
407 return seedPath
408 }
409
410 // Create parent directories
411 await getFsImplementation().mkdir(dirname(cachePath))
412
413 // For local plugins: copy entry.source directory (the single source of truth)
414 // For remote plugins: marketplaceDir is undefined, fall back to copying sourcePath
415 if (entry && typeof entry.source === 'string' && marketplaceDir) {
416 const sourceDir = validatePathWithinBase(marketplaceDir, entry.source)
417
418 logForDebugging(
419 `Copying source directory ${entry.source} for plugin ${pluginId}`,
420 )
421 try {
422 await copyDir(sourceDir, cachePath)

Callers 2

performPluginUpdateFunction · 0.85

Calls 15

isPluginZipCacheEnabledFunction · 0.85
getVersionedCachePathFunction · 0.85
getVersionedZipCachePathFunction · 0.85
pathExistsFunction · 0.85
logForDebuggingFunction · 0.85
readdirFunction · 0.85
rmdirFunction · 0.85
probeSeedCacheFunction · 0.85
getFsImplementationFunction · 0.85
validatePathWithinBaseFunction · 0.85
copyDirFunction · 0.85
isENOENTFunction · 0.85

Tested by

no test coverage detected