Skip to content

feat: add bootcamp cache list to inspect cache contents#34

Merged
Arthur742Ramos merged 1 commit into
mainfrom
arthur742ramos/feature-improvements
May 15, 2026
Merged

feat: add bootcamp cache list to inspect cache contents#34
Arthur742Ramos merged 1 commit into
mainfrom
arthur742ramos/feature-improvements

Conversation

@Arthur742Ramos

Copy link
Copy Markdown
Owner

The gap

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 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 (alias ls):

Human-readable table:

Cache directory: /Users/foo/.cache/repo-bootcamp
Cache version:   2

REPOSITORY                PHASE     SHA      AGE   SIZE    MODEL              STYLE
owner/example             facts     facebea  2h    24 kB   claude-opus-4-5    oss
owner/example             deps      facebea  2h    8.0 kB  claude-opus-4-5    oss
facebook/react            facts     def5678  1d    150 kB  claude-opus-4-5    corporate
(malformed) stray.json    -         -        3d    128 B   -                  -

Total: 4 entries, 182 kB

--json for 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

  • Problem entries are surfaced, not hidden. (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.
  • Shape validation matches readPhaseCache. Missing generationOptions normalizes to empty strings so readable v2 entries don't get falsely flagged as malformed — the existing reader is lenient here, the lister is too.
  • Per-file errors are isolated. One bad file can't fail the listing; each file is summarized independently.
  • mtime, not createdAt. Age and sort use filesystem mtime so the table aligns with what prune does (prune is also mtime-based). createdAt is still exposed in --json.
  • SHA truncated to 7 chars in the table, full SHA in JSON. Same convention as git's --oneline.
  • Pure renderer module. All formatting helpers live in src/commands/cache-list.ts and are unit-tested directly without spawning a CLI process.
  • Exports getCacheVersion() to stop tests and the CLI from duplicating the CACHE_VERSION = 2 constant.

Tests

  • 20 new unit 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, missing generationOptions accepted (mirrors readPhaseCache), mtime-desc sort with deterministic filename tiebreaker, byte/age formatters across all ranges, JSON shape stability.
  • 2 new e2e tests in 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 temp HOME redirect that PR fix: make path checks and tool output cross-platform on Windows #32 made work cross-platform.

Validation

Check Before After
typecheck
lint
unit tests 965/965 985/985
CLI e2e 9/9 11/11
build

Process note

I ran the plan past the rubber-duck before implementing. Key adoptions:

  • E2E writes raw JSON into the temp home cache dir (not via writePhaseCache from the test process — those don't share CACHE_DIR after module load).
  • --json always emits valid JSON, even when empty.
  • Exported getCacheVersion() instead of duplicating 2.
  • Aligned shape validation with readPhaseCache's leniency around generationOptions.
  • Used mtime (not 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.
  • Hard upper bound on file size during parsing. Cache files are KB each; not worth the complexity unless something concrete points the other way.

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 Arthur742Ramos merged commit 6fc5546 into main May 15, 2026
13 checks passed
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant