mirror of
https://github.com/Yeachan-Heo/oh-my-claudecode.git
synced 2026-09-03 06:25:33 +08:00
fix(hooks): symlink old plugin cache versions instead of deleting them
Stop hooks fail with "Cannot find module" when a plugin is updated mid-session because session-start.mjs aggressively deletes old cache directories while running sessions still reference them via the resolved CLAUDE_PLUGIN_ROOT environment variable. Changes: - session-start.mjs: Replace rmSync with symlinkSync for old versions (beyond latest 2), so stale CLAUDE_PLUGIN_ROOT paths follow the symlink to the current version's scripts - paths.ts: Increase purgeStalePluginCacheVersions grace period from 1 hour to 24 hours to avoid premature deletion during long sessions - Add integration tests for the symlink cleanup behavior - Update existing purge-stale-cache test staleStats default to match the new 24-hour threshold Closes #970
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
* Cross-platform: Windows, macOS, Linux
|
||||
*/
|
||||
|
||||
import { existsSync, readFileSync, readdirSync, rmSync, mkdirSync, writeFileSync } from 'fs';
|
||||
import { existsSync, readFileSync, readdirSync, rmSync, mkdirSync, writeFileSync, symlinkSync, lstatSync, readlinkSync, unlinkSync } from 'fs';
|
||||
import { join, dirname } from 'path';
|
||||
import { homedir } from 'os';
|
||||
import { fileURLToPath, pathToFileURL } from 'url';
|
||||
@@ -414,7 +414,10 @@ ${cleanContent}
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup old plugin cache versions (keep latest 2)
|
||||
// Cleanup old plugin cache versions (keep latest 2, symlink the rest)
|
||||
// Instead of deleting old versions, replace them with symlinks to the latest.
|
||||
// This prevents "Cannot find module" errors for sessions started before a
|
||||
// plugin update whose CLAUDE_PLUGIN_ROOT still points to the old version.
|
||||
try {
|
||||
const cacheBase = join(configDir, 'plugins', 'cache', 'omc', 'oh-my-claudecode');
|
||||
if (existsSync(cacheBase)) {
|
||||
@@ -422,11 +425,31 @@ ${cleanContent}
|
||||
.filter(v => /^\d+\.\d+\.\d+/.test(v))
|
||||
.sort(semverCompare)
|
||||
.reverse();
|
||||
const toRemove = versions.slice(2);
|
||||
for (const version of toRemove) {
|
||||
try {
|
||||
rmSync(join(cacheBase, version), { recursive: true, force: true });
|
||||
} catch {}
|
||||
|
||||
if (versions.length > 2) {
|
||||
const latest = versions[0];
|
||||
const toSymlink = versions.slice(2);
|
||||
for (const version of toSymlink) {
|
||||
try {
|
||||
const versionPath = join(cacheBase, version);
|
||||
const stat = lstatSync(versionPath);
|
||||
|
||||
if (stat.isSymbolicLink()) {
|
||||
// Already a symlink — update only if pointing to wrong target
|
||||
const target = readlinkSync(versionPath);
|
||||
if (target === latest) continue;
|
||||
unlinkSync(versionPath);
|
||||
} else if (stat.isDirectory()) {
|
||||
rmSync(versionPath, { recursive: true, force: true });
|
||||
}
|
||||
|
||||
// Create relative symlink: e.g. 4.4.1 -> 4.4.3
|
||||
symlinkSync(latest, versionPath);
|
||||
} catch {
|
||||
// If symlink creation fails (e.g. Windows without dev mode),
|
||||
// leave the old directory in place — safer than deleting it.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {}
|
||||
|
||||
Reference in New Issue
Block a user