MCPcopy Create free account
hub / github.com/codeaashu/claude-code / cleanupNpmCacheForAnthropicPackages

Function cleanupNpmCacheForAnthropicPackages

src/utils/cleanup.ts:438–535  ·  view source on GitHub ↗
()

Source from the content-addressed store, hash-verified

436 * Only runs once per day for Ant users.
437 */
438export async function cleanupNpmCacheForAnthropicPackages(): Promise<void> {
439 const markerPath = join(getClaudeConfigHomeDir(), '.npm-cache-cleanup')
440
441 try {
442 const stat = await fs.stat(markerPath)
443 if (Date.now() - stat.mtimeMs < ONE_DAY_MS) {
444 logForDebugging('npm cache cleanup: skipping, ran recently')
445 return
446 }
447 } catch {
448 // File doesn't exist, proceed with cleanup
449 }
450
451 try {
452 await lockfile.lock(markerPath, { retries: 0, realpath: false })
453 } catch {
454 logForDebugging('npm cache cleanup: skipping, lock held')
455 return
456 }
457
458 logForDebugging('npm cache cleanup: starting')
459
460 const npmCachePath = join(homedir(), '.npm', '_cacache')
461
462 const NPM_CACHE_RETENTION_COUNT = 5
463
464 const startTime = Date.now()
465 try {
466 const cacache = await import('cacache')
467 const cutoff = startTime - ONE_DAY_MS
468
469 // Stream index entries and collect all Anthropic package entries.
470 // Previous implementation used cacache.verify() which does a full
471 // integrity check + GC of the ENTIRE cache — O(all content blobs).
472 // On large caches this took 60+ seconds and blocked the event loop.
473 const stream = cacache.ls.stream(npmCachePath)
474 const anthropicEntries: { key: string; time: number }[] = []
475 for await (const entry of stream as AsyncIterable<{
476 key: string
477 time: number
478 }>) {
479 if (entry.key.includes('@anthropic-ai/claude-')) {
480 anthropicEntries.push({ key: entry.key, time: entry.time })
481 }
482 }
483
484 // Group by package name (everything before the last @version separator)
485 const byPackage = new Map<string, { key: string; time: number }[]>()
486 for (const entry of anthropicEntries) {
487 const atVersionIdx = entry.key.lastIndexOf('@')
488 const pkgName =
489 atVersionIdx > 0 ? entry.key.slice(0, atVersionIdx) : entry.key
490 const existing = byPackage.get(pkgName) ?? []
491 existing.push(entry)
492 byPackage.set(pkgName, existing)
493 }
494
495 // Remove entries older than 1 day OR beyond the top N most recent per package

Callers 2

Calls 6

logForDebuggingFunction · 0.85
logEventFunction · 0.85
logErrorFunction · 0.70
getMethod · 0.65
pushMethod · 0.45
setMethod · 0.45

Tested by

no test coverage detected