Date: 2025-01-21 Purpose: Research NPX cache management for implementing non-blocking auto-updates in vibe-log-cli
- Unix/Linux/macOS:
~/.npm/_npx/ - Windows:
%AppData%/npm-cache/_npx/
- Packages stored in subdirectories named with first 16 characters of SHA512 hash
- Example:
prettier→~/.npm/_npx/b388654678d519d9 - Newer NPX versions incorporate version number into hash calculation
- Full package structure:
~/.npm/_npx/{hash}/node_modules/{package-name}/
- Cache persists forever - NOT automatically cleared
- NPX checks cache AFTER local/global installations
- Cache is NOT updated when NPX utility itself is updated
- Without
@latest, NPX uses cached version indefinitely
Source: Stack Overflow, npm documentation, GitHub issues
When multiple npx processes execute simultaneously for the same non-local package:
- They install atop each other in the same npx cache directory
- Causes silent failures or errors:
TAR_ENTRY_ERROR,ENOTEMPTY,EJSONPARSE,MODULE_NOT_FOUND
- Multiple concurrent npm installations interfere with each other
- npm tries to replace directory with file, but directory not empty
- npm cache corruption during concurrent writes
GitHub PR #8512 (npm/cli): "fix: allow concurrent non-local npx calls"
- Introduces file-based lock around reading/reifying tree in npx cache
- Allows concurrent npx executions for same package to succeed
- This validates our file-based locking approach!
Source: GitHub npm/cli issues and PRs
npm cache clean --force # Does NOT clear npx cache!- GitHub Issue #6664: "npm cache clear --force does not clear npx cache"
- User confirmed this returns "npm warn cache Not Found: vibe-log-cli"
- This is not a valid approach
# Manual deletion (surgical approach)
rm -rf ~/.npm/_npx/
# Or delete specific package
find ~/.npm/_npx -name "vibe-log-cli" -type d -exec rm -rf {} +- Manual deletion of
~/.npm/_npx/directory is the correct approach - There's even an npm package
clear-npx-cachethat does this programmatically - Clearing cache is good practice to prevent version conflicts
- Particularly useful when encountering installation errors
Source: Stack Overflow, GitHub issues, npm documentation
- Once package is cached, subsequent uses use cache (never updates)
- Packages stored in cache forever
- When NPX utility updates, cache does NOT update
- This is intentional behavior per npm team
- Forces download of latest version
- Checks registry every time
- Updates the package you're directly running
- Does NOT update dependencies
- Widely considered problematic by developers
- Many expect npx to always fetch latest (but it doesn't)
- npm team doesn't want "use latest" as default behavior
Source: GitHub npm/rfcs issues, Stack Overflow
- Remove @latest from hooks: Let hooks use cached version (fast, reliable)
- Control updates ourselves: Our code decides when to update
- File-based locking: Prevents concurrent update conflicts (npm is doing this too!)
- Manual cache clearing: Use programmatic
rm -rfon~/.npm/_npx/
- Does NOT work for npx cachenpm cache clean --forceAssume @latest is safe- Causes concurrent execution problems
// Fast, uses cache, no concurrent issues
const command = 'npx vibe-log-cli send --silent --hook-trigger=sessionstart';// In send.ts - after processing sessions
if (versionCheck.isOutdated && !isUpdating) {
// 1. Acquire file lock (update-lock.ts)
// 2. Clear NPX cache (npx-cache.ts)
// - Delete ~/.npm/_npx/*/node_modules/vibe-log-cli
// 3. Run: npx vibe-log-cli@latest --version (in background)
// 4. Release lock
// 5. Next hook execution uses new cached version
}// src/utils/npx-cache.ts
import { rm } from 'fs/promises';
import { exec } from 'child_process';
import { promisify } from 'util';
const execAsync = promisify(exec);
export async function clearVibeLogFromNpxCache(): Promise<void> {
const cacheDir = path.join(os.homedir(), '.npm', '_npx');
// Find and delete vibe-log-cli from cache
const { stdout } = await execAsync(
`find "${cacheDir}" -name "vibe-log-cli" -type d`
);
const dirs = stdout.trim().split('\n').filter(Boolean);
for (const dir of dirs) {
await rm(dir, { recursive: true, force: true });
}
}# 1. Find NPX cache
ls -la ~/.npm/_npx/
# 2. Find vibe-log-cli in cache
find ~/.npm/_npx -name "vibe-log-cli" -type d
# 3. Check cached version
find ~/.npm/_npx -name "vibe-log-cli" -type d -exec cat {}/package.json \; | grep '"version"'
# 4. Delete vibe-log-cli from cache (surgical)
find ~/.npm/_npx -name "vibe-log-cli" -type d -exec rm -rf {} +
# 5. Verify deletion
find ~/.npm/_npx -name "vibe-log-cli" -type d
# 6. Verify NPX re-downloads
npx vibe-log-cli --version
# 7. Confirm new cache entry
find ~/.npm/_npx -name "vibe-log-cli" -type d- Step 2: Should find 1+ directories
- Step 3: Should show current cached version
- Step 5: Should return empty (no results)
- Step 6: Should download and show version
- Step 7: Should find newly cached directory
- npm/cli#8512 - Fix concurrent npx calls
- npm/cli#6664 - npm cache clean doesn't clear npx
- npm/cli#4108 - npx not using latest version
- npm/rfcs#700 - npx not getting latest version
- ✅ Concurrent
npx @latestexecutions cause ENOTEMPTY errors (confirmed) - ✅ Manual deletion of
~/.npm/_npx/is the correct cache clearing method - ✅ File-based locking is the right approach (npm is implementing this too)
- ✅ Using
npx vibe-log-cli(no @latest) with our own update mechanism is optimal - ❌
npm cache clean --forcedoes NOT work for npx cache
High - All findings corroborated by:
- Official npm documentation
- GitHub issues/PRs from npm maintainers
- Multiple Stack Overflow answers
- Community articles and packages
- ✅ Research complete - documented findings
- ⏭️ Phase 2: Verify cache clearing on user's machine
- ⏭️ Phase 3: Create automated test script
- ⏭️ Phase 4: Update implementation plan
- ⏭️ Phase 5: Implement verified solution