← back to Cli Printing Press
fix(cli): scope HTTP cache to <api>/http so invalidateCache spares siblings (#1166)
36976106f4357fb3dba3242a85ba66b9eb677bc3 · 2026-05-12 00:41:46 -0700 · Trevin Chow
invalidateCache() runs os.RemoveAll(cacheDir) after every mutation. With
cacheDir set to ~/.cache/<api>/, any sibling state (SQLite mirrors, FTS5
stores, watchlists) an agent or future scaffold places in the same
parent directory gets nuked alongside the HTTP cache.
Point cacheDir at ~/.cache/<api>/http/ so the wipe stays scoped to HTTP
responses. Add a guard test asserting the http subdir shape; refresh the
three affected golden client.go fixtures.
Fixes #1126
Files touched
M internal/generator/client_invalidate_cache_test.goM internal/generator/templates/client.go.tmplM testdata/golden/expected/generate-golden-api-oauth2-cc/printing-press-oauth2-cc/internal/client/client.goM testdata/golden/expected/generate-golden-api/printing-press-golden/internal/client/client.goM testdata/golden/expected/generate-tier-routing-api/tier-routing-golden/internal/client/client.go
Diff
commit 36976106f4357fb3dba3242a85ba66b9eb677bc3
Author: Trevin Chow <trevin@trevinchow.com>
Date: Tue May 12 00:41:46 2026 -0700
fix(cli): scope HTTP cache to <api>/http so invalidateCache spares siblings (#1166)
invalidateCache() runs os.RemoveAll(cacheDir) after every mutation. With
cacheDir set to ~/.cache/<api>/, any sibling state (SQLite mirrors, FTS5
stores, watchlists) an agent or future scaffold places in the same
parent directory gets nuked alongside the HTTP cache.
Point cacheDir at ~/.cache/<api>/http/ so the wipe stays scoped to HTTP
responses. Add a guard test asserting the http subdir shape; refresh the
three affected golden client.go fixtures.
Fixes #1126
---
internal/generator/client_invalidate_cache_test.go | 28 ++++++++++++++++++++++
internal/generator/templates/client.go.tmpl | 2 +-
.../internal/client/client.go | 2 +-
.../internal/client/client.go | 2 +-
.../tier-routing-golden/internal/client/client.go | 2 +-
5 files changed, 32 insertions(+), 4 deletions(-)
diff --git a/internal/generator/client_invalidate_cache_test.go b/internal/generator/client_invalidate_cache_test.go
index f855b640..9caffa03 100644
--- a/internal/generator/client_invalidate_cache_test.go
+++ b/internal/generator/client_invalidate_cache_test.go
@@ -61,3 +61,31 @@ func TestGenerateEmitsInvalidateCacheSymmetry(t *testing.T) {
assert.Contains(t, clientGo, "func (c *Client) writeCache(",
"client.go must still define writeCache; symmetry presupposes both")
}
+
+// TestGenerateCacheDirIsHTTPSubdir guards #1126: cacheDir must point at
+// ~/.cache/<api>/http (not ~/.cache/<api>) so that invalidateCache's
+// os.RemoveAll only wipes the HTTP cache and leaves sibling state files
+// (SQLite mirrors, FTS5 stores, watchlists) intact.
+func TestGenerateCacheDirIsHTTPSubdir(t *testing.T) {
+ t.Parallel()
+
+ apiSpec, err := spec.Parse(filepath.Join("..", "..", "testdata", "stytch.yaml"))
+ require.NoError(t, err)
+
+ outputDir := filepath.Join(t.TempDir(), naming.CLI(apiSpec.Name))
+ gen := New(apiSpec, outputDir)
+ require.NoError(t, gen.Generate())
+
+ clientGoBytes, err := os.ReadFile(filepath.Join(outputDir, "internal", "client", "client.go"))
+ require.NoError(t, err)
+ clientGo := string(clientGoBytes)
+
+ cliName := naming.CLI(apiSpec.Name)
+ wantSubdir := `filepath.Join(homeDir, ".cache", "` + cliName + `", "http")`
+ wantOldShape := `filepath.Join(homeDir, ".cache", "` + cliName + `")`
+
+ assert.Contains(t, clientGo, wantSubdir,
+ "client.go must place cacheDir under <api>/http so invalidateCache spares siblings (#1126)")
+ assert.NotContains(t, clientGo, wantOldShape,
+ "client.go must not point cacheDir at the bare ~/.cache/<api>/ root (#1126)")
+}
diff --git a/internal/generator/templates/client.go.tmpl b/internal/generator/templates/client.go.tmpl
index 78d632f3..6aa2c7d8 100644
--- a/internal/generator/templates/client.go.tmpl
+++ b/internal/generator/templates/client.go.tmpl
@@ -300,7 +300,7 @@ func newHTTPClient(timeout time.Duration, jar http.CookieJar) *http.Client {
func New(cfg *config.Config, timeout time.Duration, rateLimit float64) *Client {
homeDir, _ := os.UserHomeDir()
- cacheDir := filepath.Join(homeDir, ".cache", "{{.Name}}-pp-cli")
+ cacheDir := filepath.Join(homeDir, ".cache", "{{.Name}}-pp-cli", "http")
{{- if eq .Auth.Type "session_handshake"}}
sess := newSessionManager(timeout)
httpClient := newHTTPClient(timeout, sess.CookieJar())
diff --git a/testdata/golden/expected/generate-golden-api-oauth2-cc/printing-press-oauth2-cc/internal/client/client.go b/testdata/golden/expected/generate-golden-api-oauth2-cc/printing-press-oauth2-cc/internal/client/client.go
index 496b28e3..4bdda627 100644
--- a/testdata/golden/expected/generate-golden-api-oauth2-cc/printing-press-oauth2-cc/internal/client/client.go
+++ b/testdata/golden/expected/generate-golden-api-oauth2-cc/printing-press-oauth2-cc/internal/client/client.go
@@ -55,7 +55,7 @@ func newHTTPClient(timeout time.Duration, jar http.CookieJar) *http.Client {
func New(cfg *config.Config, timeout time.Duration, rateLimit float64) *Client {
homeDir, _ := os.UserHomeDir()
- cacheDir := filepath.Join(homeDir, ".cache", "printing-press-oauth2-pp-cli")
+ cacheDir := filepath.Join(homeDir, ".cache", "printing-press-oauth2-pp-cli", "http")
httpClient := newHTTPClient(timeout, nil)
return &Client{
BaseURL: strings.TrimRight(cfg.BaseURL, "/"),
diff --git a/testdata/golden/expected/generate-golden-api/printing-press-golden/internal/client/client.go b/testdata/golden/expected/generate-golden-api/printing-press-golden/internal/client/client.go
index dffda2dc..d3c44d73 100644
--- a/testdata/golden/expected/generate-golden-api/printing-press-golden/internal/client/client.go
+++ b/testdata/golden/expected/generate-golden-api/printing-press-golden/internal/client/client.go
@@ -49,7 +49,7 @@ func newHTTPClient(timeout time.Duration, jar http.CookieJar) *http.Client {
func New(cfg *config.Config, timeout time.Duration, rateLimit float64) *Client {
homeDir, _ := os.UserHomeDir()
- cacheDir := filepath.Join(homeDir, ".cache", "printing-press-golden-pp-cli")
+ cacheDir := filepath.Join(homeDir, ".cache", "printing-press-golden-pp-cli", "http")
httpClient := newHTTPClient(timeout, nil)
return &Client{
BaseURL: strings.TrimRight(cfg.BaseURL, "/"),
diff --git a/testdata/golden/expected/generate-tier-routing-api/tier-routing-golden/internal/client/client.go b/testdata/golden/expected/generate-tier-routing-api/tier-routing-golden/internal/client/client.go
index c855a5d1..ad913d8a 100644
--- a/testdata/golden/expected/generate-tier-routing-api/tier-routing-golden/internal/client/client.go
+++ b/testdata/golden/expected/generate-tier-routing-api/tier-routing-golden/internal/client/client.go
@@ -143,7 +143,7 @@ func newHTTPClient(timeout time.Duration, jar http.CookieJar) *http.Client {
func New(cfg *config.Config, timeout time.Duration, rateLimit float64) *Client {
homeDir, _ := os.UserHomeDir()
- cacheDir := filepath.Join(homeDir, ".cache", "tier-routing-golden-pp-cli")
+ cacheDir := filepath.Join(homeDir, ".cache", "tier-routing-golden-pp-cli", "http")
httpClient := newHTTPClient(timeout, nil)
return &Client{
BaseURL: strings.TrimRight(cfg.BaseURL, "/"),
← 12964486 chore(main): release 4.5.0 (#1134)
·
back to Cli Printing Press
·
fix(cli): preserve novel-command keys in --compact partial-s f88a10b3 →