feat(config): E2E_CACHE_DIR and --cache-dir override cache.dir
Merged
OK
13d ago+288+288+012345678901234567890123456789-87-87-01234567890123456789
Closes #1117
E2E_CACHE_DIRand--cache-dir <dir>replacecache.dir, so worktrees and checkouts of one project can share a replay cache without editing the config.- Precedence:
--cache-dir>E2E_CACHE_DIR>cache.dir>.e2e/cache. The mode is untouched and--no-cachestill wins. - Both resolve from the project root, like
cache.dirand--output, and go through the same output-overlap checks. Error messages name the source (would hold --cache-dir .e2e/results/c under results/). - Read once in
resolveConfig(packages/e2e/src/config/resolve.ts,cacheDirOverride), so workers, watch mode, ande2e cacheall get the same directory. A blankE2E_CACHE_DIRcounts as unset, the same rule as otherE2E_*variables. - The flag is on
runandcache ls|stats|clear.exploreandmcpdon't use the cache, so they only get the variable through the output-overlap check. --cache-dirtogether with a customcache.storeisINVALID_CONFIG, because the flag would name a directory nothing reads. The ambient variable is ignored there.REPLAY_STALEadvice no longer says "commit" for a cache directory outside the project.- Vitest blanks
E2E_CACHE_DIRandscripts/bench-ab.tsdrops it, so a developer's shared cache never leaks into fixture projects or A/B runs. - Docs:
cache.mdxgets a "Share the cache across checkouts" section (with the note that checkouts need the sameprojectIdor packagename), plusreference/cli,reference/config,reference/environment, andskills/e2e/references/running.md.
E2E_CACHE_DIR=~/.cache/my-app/e2e npx e2e run
npx e2e run --cache-dir ../shared-cache
Verified
Ran it locally: yes
- The built CLI on a scratch project in
/tmp, copied into two separate checkouts (checkout-a,checkout-b). It has a web target, oneagent.actstep, and a scripted model that logs each call, so a replay is visible as zero model calls.
checkout-a, E2E_CACHE_DIR=/tmp/verify-1117/shared e2e run records:
✓ target "web" command ready 89ms
[scripted model] call 1
[scripted model] call 2
✓ increments the counter > agent.act "increment the counter once" 399ms · 2 model calls
Test Files 1 passed (1)
AI 4 tokens · 2 model calls · scripted/scripted-counter
Cache 1 missed
checkout-b, same variable, replays from the shared directory with no model call. Its own .e2e/ has no cache/:
✓ target "web" command ready 94ms
✓ increments the counter > agent.act "increment the counter once" 172ms
Test Files 1 passed (1)
Cache 1 replayed
Other checks in checkout-b:
$ E2E_CACHE_DIR=../shared e2e cache ls
TEST TARGET INSTRUCTION AGE ACTIONS
tests/counter.e2e.ts::increments%20the%20counter web bc8b5c526994 <1m 1
$ e2e run --cache-dir ../shared -> Cache 1 replayed
$ E2E_CACHE_DIR=/tmp/nowhere e2e run --cache-dir /tmp/.../shared -> Cache 1 replayed (flag wins)
$ e2e run -> Cache 1 missed (default .e2e/cache)
$ E2E_CACHE_DIR=/tmp/.../shared e2e run --no-cache -> 2 model calls, no Cache line
$ E2E_CACHE_DIR=.e2e e2e run
output ".e2e" (the default) is the cache directory .e2e or inside it; keep results and the replay cache apart
$ e2e run --cache-dir .e2e/results/c
output ".e2e" (the default) would hold --cache-dir .e2e/results/c under results/, which the run owns; move --cache-dir or the output