feat: add bootcamp cache list to inspect cache contents#34
Merged
Conversation
Today `bootcamp cache` lets you prune or clear the analysis cache, but there's no way to see what's actually in it. That makes hygiene blind — you can't tell which repos/phases/SHAs are cached, how big the cache is, or whether a stale entry is from your last run or three months ago.
Adds `bootcamp cache list` (alias `ls`):
- Human-readable table: Repository, Phase, SHA (7-char), Age (relative: `2h`, `3d`), Size, Model, Style. Header shows cache dir + schema version; footer shows totals.
- `--json` flag for scripting: stable shape `{ dir, version, entries, totalEntries, totalBytes }`, always valid JSON (even when empty), preserves mtime-desc order with deterministic filename tiebreaker.
Surfaces problem entries instead of hiding them: legacy (older schema version), malformed (parse error or wrong shape), and unreadable (IO error). These are shown with `(legacy) filename.json` rows so users can see disk usage from stray files — the exact case that today causes 'huh, my disk is full' surprises.
Implementation:
- `listCacheEntries()` in src/cache.ts: validates against the same compatibility rules as readPhaseCache (missing `generationOptions` is fine, normalized to empty strings) so readable v2 entries aren't falsely flagged as malformed. Per-file errors are isolated; the listing never fails because of a single bad file.
- Pure renderer in src/commands/cache-list.ts (`buildHumanOutput`/`buildJsonOutput`/`formatAge`/`formatBytes`) so unit tests can pin output without spawning a CLI process.
- `getCacheVersion()` exported to avoid duplicating the CACHE_VERSION constant in tests and CLI.
Tests: 20 new unit tests (in test/cache.test.ts and test/cache-list.test.ts) covering valid/legacy/malformed entries, missing generationOptions, mtime-desc sorting with filename tiebreaker, byte/age formatting, and JSON shape. 2 new e2e tests covering the populated-cache and empty-cache cases through the real CLI process (uses the existing HOME/USERPROFILE redirect from PR #32).
All checks pass on Windows: typecheck, lint, build, 985/985 unit, 11/11 CLI e2e.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Arthur742Ramos
added a commit
that referenced
this pull request
May 15, 2026
The 'By the Numbers' table and three other places quoted the test/source counts from an old snapshot. Bring them in line with the current main branch (post PR #34). - Test suite: 613 -> 985 tests (updated in 'By the Numbers' table, 'What Makes It Different' bullet, the 'Run tests (...)' comment, and the Tech Stack bullet) - Source files: 36 -> 41 TypeScript modules - Test files: 30 -> 60 Vitest files - Lines of code: 10,992 -> 11,627 TypeScript LOC Numbers verified against current main via 'git ls-files' and 'npm test' on the local checkout. The GitHub stars count is left as-is since it's a human-curated value the maintainer updates intentionally. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The gap
Today
bootcamp cachelets youpruneorclearthe analysis cache — but there's no way to see what's actually in it. That makes cache hygiene blind: you can't tell which repos/phases/SHAs are cached, how big the cache is, or whether a stale entry is from your last run or three months ago. The classic "huh, my disk is full" surprise.What this adds
bootcamp cache list(aliasls):Human-readable table:
--jsonfor scripting:{ "dir": "/Users/foo/.cache/repo-bootcamp", "version": 2, "entries": [ { "file": "...", "path": "...", "sizeBytes": 24576, "mtimeMs": 1717248000000, "ageSeconds": 7200, "problem": null, "entry": { "version": 2, "phase": "facts", "repoFullName": "owner/example", "commitSha": "facebead123456789012", ... } } ], "totalEntries": 4, "totalBytes": 186112 }Always valid JSON, even when the cache is empty.
Design notes
(legacy)for older-schema files,(malformed)for parse errors or wrong shape,(unreadable)for IO errors. Hiding stale disk usage was exactly the problem the command exists to solve.readPhaseCache. MissinggenerationOptionsnormalizes to empty strings so readable v2 entries don't get falsely flagged as malformed — the existing reader is lenient here, the lister is too.prunedoes (prune is also mtime-based).createdAtis still exposed in--json.--oneline.src/commands/cache-list.tsand are unit-tested directly without spawning a CLI process.getCacheVersion()to stop tests and the CLI from duplicating theCACHE_VERSION = 2constant.Tests
test/cache.test.ts+test/cache-list.test.ts): empty/missing dir, valid v2 entries with full metadata, JSON parse errors flagged as malformed, valid JSON with wrong shape flagged as malformed, version-mismatch flagged as legacy, missinggenerationOptionsaccepted (mirrorsreadPhaseCache), mtime-desc sort with deterministic filename tiebreaker, byte/age formatters across all ranges, JSON shape stability.test/e2e/cache-command.e2e.test.ts: populated cache with a valid entry + stray blob → assert both human and JSON output; missing cache dir → assert empty-message + empty JSON. Both use the existing tempHOMEredirect that PR fix: make path checks and tool output cross-platform on Windows #32 made work cross-platform.Validation
Process note
I ran the plan past the rubber-duck before implementing. Key adoptions:
writePhaseCachefrom the test process — those don't shareCACHE_DIRafter module load).--jsonalways emits valid JSON, even when empty.getCacheVersion()instead of duplicating2.readPhaseCache's leniency aroundgenerationOptions.createdAt) so age/sort match prune semantics.Not in scope
--sort <field>flag. Default newest-first is the right v1; easy to add later if asked for.