fix(install): prune old version bundles instead of piling them up (#1074) (#1075)

install.sh kept each release in its own versions/<v> dir (~50 MB with the
vendored Node runtime) and only moved the `current` symlink, so old versions
accumulated forever across upgrades. Keep only the just-installed version and
delete the rest; `codegraph upgrade` re-runs install.sh, so this covers
upgrades too. The npm-shim self-heal cache (~/.codegraph/bundles/) prunes the
same way. Windows installs overwrite a single dir in place and were never
affected.

Validated real-world on macOS, Linux (Docker/dash), and Windows (VM): a
v1.1.2 -> v1.1.4 install leaves only the latest behind.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Colby Mchenry
2026-06-29 23:35:50 -05:00
committed by GitHub
co-authored by Claude Opus 4.8
parent 9684b3b5a5
commit 31a58070c8
5 changed files with 209 additions and 2 deletions
+45
View File
@@ -103,6 +103,33 @@ describe.skipIf(isWindows)('npm-shim launcher', () => {
expect(r.stderr).toBe('');
});
it('prunes older cached bundles for this target, keeping the current one (#1074)', async () => {
const pkg = makePkg('2.0.0-keep');
const cache = mkTmp('cache');
const bundles = path.join(cache, 'bundles');
// current (matches pkg version) + an older bundle for the same target
writeLauncher(path.join(bundles, `${target}-2.0.0-keep`, 'bin'));
writeLauncher(path.join(bundles, `${target}-1.0.0-old`, 'bin'));
// a different platform's bundle and an in-flight staging dir must survive
const otherTarget = target === 'linux-x64' ? 'darwin-arm64' : 'linux-x64';
writeLauncher(path.join(bundles, `${otherTarget}-1.0.0`, 'bin'));
fs.mkdirSync(path.join(bundles, '.dl-inflight'), { recursive: true });
const r = await runShim(pkg, ['--probe-prune'], {
CODEGRAPH_INSTALL_DIR: cache,
CODEGRAPH_NO_DOWNLOAD: '1',
});
expect(r.status).toBe(0);
expect(r.stdout).toContain('FAKE_BUNDLE_RAN');
// older same-target bundle pruned; current kept
expect(fs.existsSync(path.join(bundles, `${target}-1.0.0-old`))).toBe(false);
expect(fs.existsSync(path.join(bundles, `${target}-2.0.0-keep`))).toBe(true);
// unrelated target + staging dir untouched
expect(fs.existsSync(path.join(bundles, `${otherTarget}-1.0.0`))).toBe(true);
expect(fs.existsSync(path.join(bundles, '.dl-inflight'))).toBe(true);
});
it('prints actionable guidance and exits 1 when disabled with no bundle', async () => {
const pkg = makePkg();
const r = await runShim(pkg, ['--version'], {
@@ -182,6 +209,24 @@ describe.skipIf(!CAN_NET)('npm-shim download fallback (local HTTPS)', () => {
expect(fs.existsSync(path.join(cache, 'bundles', `${target}-5.0.0-net`, 'bin', 'codegraph'))).toBe(true);
}, 20000);
it('prunes older cached bundles after downloading a new one (#1074)', async () => {
sumsBody = `${fixtureSha} ${asset}\n`;
const pkg = makePkg('6.0.0-new');
const cache = mkTmp('cache');
const bundles = path.join(cache, 'bundles');
// a stale bundle from a previous version (same target) left by an earlier run
writeLauncher(path.join(bundles, `${target}-5.0.0-stale`, 'bin'));
const r = await runShim(pkg, ['--probe-newdl'], netEnv(cache));
expect(r.status).toBe(0);
expect(r.stderr).toContain('downloading');
expect(r.stdout).toContain('FAKE_BUNDLE_RAN');
// freshly downloaded version present, stale one pruned
expect(fs.existsSync(path.join(bundles, `${target}-6.0.0-new`, 'bin', 'codegraph'))).toBe(true);
expect(fs.existsSync(path.join(bundles, `${target}-5.0.0-stale`))).toBe(false);
}, 20000);
it('aborts (exit 1) on a checksum mismatch and caches nothing', async () => {
sumsBody = `${'0'.repeat(64)} ${asset}\n`;
const pkg = makePkg('5.0.0-bad');