diff --git a/internal/agent/main_test.go b/internal/agent/main_test.go index 5aca1147..bc855b8f 100644 --- a/internal/agent/main_test.go +++ b/internal/agent/main_test.go @@ -4,6 +4,8 @@ import ( "os" "path/filepath" "testing" + + "github.com/yetone/magpie/internal/agentenv" ) // TestMain gives the package a home of its own. A home an agent is found @@ -24,13 +26,7 @@ func TestMain(m *testing.M) { } { os.Setenv(k, v) } - for _, k := range []string{ - "CLAUDE_CONFIG_DIR", "CODEX_HOME", "COPILOT_HOME", "GROK_HOME", "DSH_HOME", - "PI_CODING_AGENT_DIR", "PI_CODING_AGENT_SESSION_DIR", "PI_CONFIG_DIR", - "OMP_PROFILE", "PI_PROFILE", "OPENCODE_DB", "CLINE_DIR", "CLINE_DATA_DIR", - "CLINE_SESSION_DATA_DIR", "WORKBUDDY_CONFIG_DIR", - "QODER_CONFIG_DIR", "QODERCN_CONFIG_DIR", - } { + for _, k := range agentenv.Vars { os.Unsetenv(k) } // whether Codex's ChatGPT account is out of its allowance is asked of diff --git a/internal/agentenv/agentenv.go b/internal/agentenv/agentenv.go new file mode 100644 index 00000000..bc443b40 --- /dev/null +++ b/internal/agentenv/agentenv.go @@ -0,0 +1,54 @@ +// Package agentenv names the environment variables through which an agent +// really installed on this machine reaches magpie: the one list a test +// sandbox clears, so that a test meets only the agents it put there itself. +// +// A sandbox fakes magpie's own folders through HOME, USERPROFILE and the XDG +// variables (appdir decides those), and an agent's folder through the +// variable that agent's own CLI reads before it falls back to its folder in +// the home: CLAUDE_CONFIG_DIR, CODEX_HOME, QODER_CONFIG_DIR and the rest. +// Any one of them left over from the developer's shell points magpie at a +// real agent, whose sessions and settings a test then reads — and, where +// magpie writes what it wires, writes into (#522). Qoder's CLI sets both of +// its variables for every child it starts, and magpie manages Qoder, so +// writing magpie from inside Qoder was one way to meet this. +// +// Each package keeps its own sandbox, because a test in internal/sessions +// cannot import internal/agent, which imports it, to ask which variables +// there are; this is the list they all clear. A name here is one magpie +// reads, and VarsTest says so, so a variable magpie stopped reading does not +// linger — that is how GEMINI_CLI_HOME and OPENCODE_CONFIG came to be +// cleared by a sandbox while OPENCODE_CONFIG_DIR, the one magpie reads, was +// not. What is deliberately not here: APPDATA and LOCALAPPDATA, Windows' +// folders rather than an agent's, which a sandbox sets to a folder of its +// own instead of clearing; and CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC, a +// behaviour flag whose one test sets it on purpose to read what magpie then +// does. +package agentenv + +// Vars are the variables, by the agent they belong to. A sandbox clears all +// of them, and sets back the ones its own fixtures need. +var Vars = []string{ + // Claude Code, Codex and Copilot CLI + "CLAUDE_CONFIG_DIR", "CODEX_HOME", "COPILOT_HOME", + // Cline: its folder, its data, its sessions and its MCP settings file + "CLINE_DIR", "CLINE_DATA_DIR", "CLINE_SESSION_DATA_DIR", "CLINE_MCP_SETTINGS_PATH", + // Pi and its forks (OmO, Senpi), whose profile and config are apart + "PI_CODING_AGENT_DIR", "PI_CODING_AGENT_SESSION_DIR", "PI_CONFIG_DIR", "PI_PROFILE", + "OMO_CODING_AGENT_DIR", "SENPI_CODING_AGENT_DIR", + // omp + "OMP_PROFILE", + // Qoder's two builds, the global site's and China's + "QODER_CONFIG_DIR", "QODERCN_CONFIG_DIR", + // Grok: its home, and where its CLI is installed + "GROK_HOME", "GROK_BIN_DIR", + // Kimi Code and its shared folder + "KIMI_CODE_HOME", "KIMI_SHARE_DIR", + // MiMo Code, MiniMax Code, OpenHanako, Hermes, dsh, WorkBuddy + "MIMOCODE_HOME", "MINIMAX_DATA_DIR", "HANA_HOME", "HERMES_HOME", "DSH_HOME", + "WORKBUDDY_CONFIG_DIR", + // OpenCode and OpenChamber + "OPENCODE_CONFIG_DIR", "OPENCODE_DB", "OPENCHAMBER_DATA_DIR", + // Droid's home, Windsurf's API server, ZCode's credential seed: what + // makes an account or an installation visible that the test didn't make + "FACTORY_HOME_OVERRIDE", "WINDSURF_API_SERVER_URL", "ZCODE_CREDENTIAL_SECRET", +} diff --git a/internal/agentenv/agentenv_test.go b/internal/agentenv/agentenv_test.go new file mode 100644 index 00000000..9c41389b --- /dev/null +++ b/internal/agentenv/agentenv_test.go @@ -0,0 +1,67 @@ +package agentenv + +import ( + "io/fs" + "os" + "path/filepath" + "strings" + "testing" +) + +// Every name in Vars is one magpie reads somewhere outside this package. A +// name it stopped reading, or one a sandbox invented, is a hole that every +// sandbox clearing this list believes is covered: internal/backup's cleared +// GEMINI_CLI_HOME and OPENCODE_CONFIG, which nothing reads, and not +// OPENCODE_CONFIG_DIR, which internal/agent does. This reads the sources +// rather than the agents' table, since the table is in internal/agent, which +// internal/sessions' tests cannot import; it looks for a quoted name, so a +// name only a comment mentions still counts, and a variable magpie reads +// through a name it builds at runtime would not. +func TestVarsAreRead(t *testing.T) { + found := make(map[string]bool, len(Vars)) + err := filepath.WalkDir(filepath.Join("..", ".."), func(p string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + if d.IsDir() { + switch d.Name() { + case ".git", "dist", "node_modules", "agentenv": + return fs.SkipDir + } + return nil + } + if !strings.HasSuffix(p, ".go") || strings.HasSuffix(p, "_test.go") { + return nil + } + b, err := os.ReadFile(p) + if err != nil { + return err + } + for _, v := range Vars { + if !found[v] && strings.Contains(string(b), `"`+v+`"`) { + found[v] = true + } + } + return nil + }) + if err != nil { + t.Fatal(err) + } + for _, v := range Vars { + if !found[v] { + t.Errorf("%s is in Vars, but nothing outside this package reads it: magpie stopped reading it, or the name was never the one magpie reads", v) + } + } +} + +// A name twice is a name a sandbox clears twice, which says the list was +// pasted together rather than kept. +func TestVarsAreApart(t *testing.T) { + seen := make(map[string]bool, len(Vars)) + for _, v := range Vars { + if seen[v] { + t.Errorf("%s is in Vars twice", v) + } + seen[v] = true + } +} diff --git a/internal/backup/backup_test.go b/internal/backup/backup_test.go index f166ec98..0aba9868 100644 --- a/internal/backup/backup_test.go +++ b/internal/backup/backup_test.go @@ -9,6 +9,7 @@ import ( "strings" "testing" + "github.com/yetone/magpie/internal/agentenv" "github.com/yetone/magpie/internal/library" "github.com/yetone/magpie/internal/profile" "github.com/yetone/magpie/internal/provider" @@ -24,10 +25,11 @@ func home(t *testing.T) { t.Setenv("XDG_CONFIG_HOME", filepath.Join(h, ".config")) t.Setenv("XDG_CACHE_HOME", filepath.Join(h, ".cache")) t.Setenv("PATH", h) - for _, v := range []string{"CLAUDE_CONFIG_DIR", "CODEX_HOME", "DSH_HOME", "GEMINI_CLI_HOME", "OPENCODE_CONFIG", - "PI_CODING_AGENT_DIR", "OMO_CODING_AGENT_DIR", "SENPI_CODING_AGENT_DIR", "COPILOT_HOME", "CLINE_DIR", "GROK_HOME", "HERMES_HOME", "HANA_HOME", "APPDATA", "LOCALAPPDATA"} { + for _, v := range agentenv.Vars { t.Setenv(v, "") } + t.Setenv("APPDATA", "") + t.Setenv("LOCALAPPDATA", "") } func setUp(t *testing.T) { diff --git a/internal/davsync/davsync_test.go b/internal/davsync/davsync_test.go index fb695a23..dd927b03 100644 --- a/internal/davsync/davsync_test.go +++ b/internal/davsync/davsync_test.go @@ -15,6 +15,7 @@ import ( "testing" "time" + "github.com/yetone/magpie/internal/agentenv" "github.com/yetone/magpie/internal/backup" "github.com/yetone/magpie/internal/library" "github.com/yetone/magpie/internal/profile" @@ -141,12 +142,14 @@ func (c computer) use(t *testing.T) { t.Setenv("USERPROFILE", string(c)) t.Setenv("XDG_CONFIG_HOME", filepath.Join(string(c), ".config")) t.Setenv("XDG_CACHE_HOME", filepath.Join(string(c), ".cache")) - t.Setenv("CLAUDE_CONFIG_DIR", filepath.Join(string(c), ".claude")) - t.Setenv("CODEX_HOME", filepath.Join(string(c), ".codex")) t.Setenv("PATH", "") - for _, v := range []string{"DSH_HOME", "PI_CODING_AGENT_DIR", "OMO_CODING_AGENT_DIR", "SENPI_CODING_AGENT_DIR", "COPILOT_HOME", "CLINE_DIR", "GROK_HOME", "HERMES_HOME", "HANA_HOME", "APPDATA", "LOCALAPPDATA"} { + for _, v := range agentenv.Vars { t.Setenv(v, "") } + t.Setenv("APPDATA", "") + t.Setenv("LOCALAPPDATA", "") + t.Setenv("CLAUDE_CONFIG_DIR", filepath.Join(string(c), ".claude")) + t.Setenv("CODEX_HOME", filepath.Join(string(c), ".codex")) } func ids() []string { diff --git a/internal/gateway/main_test.go b/internal/gateway/main_test.go index ff0a2712..fc39234f 100644 --- a/internal/gateway/main_test.go +++ b/internal/gateway/main_test.go @@ -5,6 +5,8 @@ import ( "os" "path/filepath" "testing" + + "github.com/yetone/magpie/internal/agentenv" ) func TestMain(m *testing.M) { @@ -37,7 +39,7 @@ func isolatedTests(m *testing.M) (int, error) { return 1, err } } - for _, name := range []string{"CLAUDE_CONFIG_DIR", "CODEX_HOME", "COPILOT_HOME", "GROK_HOME", "DSH_HOME"} { + for _, name := range agentenv.Vars { if err := os.Unsetenv(name); err != nil { return 1, err } diff --git a/internal/gui/backup_test.go b/internal/gui/backup_test.go index f264be77..8c1e026c 100644 --- a/internal/gui/backup_test.go +++ b/internal/gui/backup_test.go @@ -10,6 +10,7 @@ import ( "strings" "testing" + "github.com/yetone/magpie/internal/agentenv" "github.com/yetone/magpie/internal/library" ) @@ -27,10 +28,11 @@ func sandboxHome(t *testing.T) string { t.Setenv("XDG_CONFIG_HOME", filepath.Join(h, ".config")) t.Setenv("XDG_CACHE_HOME", filepath.Join(h, ".cache")) t.Setenv("PATH", "") - for _, v := range []string{"CLAUDE_CONFIG_DIR", "CODEX_HOME", "DSH_HOME", "PI_CODING_AGENT_DIR", "OMO_CODING_AGENT_DIR", "SENPI_CODING_AGENT_DIR", "COPILOT_HOME", - "CLINE_DIR", "GROK_HOME", "HERMES_HOME", "HANA_HOME", "APPDATA", "LOCALAPPDATA"} { + for _, v := range agentenv.Vars { t.Setenv(v, "") } + t.Setenv("APPDATA", "") + t.Setenv("LOCALAPPDATA", "") return h } diff --git a/internal/library/library_test.go b/internal/library/library_test.go index 92f3a3f9..005d1719 100644 --- a/internal/library/library_test.go +++ b/internal/library/library_test.go @@ -18,6 +18,8 @@ import ( "github.com/pelletier/go-toml/v2" "github.com/tidwall/jsonc" + + "github.com/yetone/magpie/internal/agentenv" ) // sandbox is a home with every agent magpie can give the library to, and @@ -38,9 +40,11 @@ func sandbox(t *testing.T) string { roots := piGlobalRoots piGlobalRoots = func() []string { return nil } t.Cleanup(func() { piGlobalRoots = roots }) - for _, k := range []string{"CLAUDE_CONFIG_DIR", "CODEX_HOME", "PI_CODING_AGENT_DIR", "OMO_CODING_AGENT_DIR", "SENPI_CODING_AGENT_DIR", "PI_CONFIG_DIR", "OMP_PROFILE", "PI_PROFILE", "COPILOT_HOME", "APPDATA", "LOCALAPPDATA", "DSH_HOME", "HERMES_HOME", "KIMI_CODE_HOME", "KIMI_SHARE_DIR", "GROK_HOME", "FACTORY_HOME_OVERRIDE", "CLINE_DIR", "CLINE_DATA_DIR", "CLINE_MCP_SETTINGS_PATH", "QODER_CONFIG_DIR", "QODERCN_CONFIG_DIR"} { + for _, k := range agentenv.Vars { t.Setenv(k, "") } + t.Setenv("APPDATA", "") + t.Setenv("LOCALAPPDATA", "") for _, f := range []string{ ".claude/settings.json", ".codex/config.toml", ".gemini/settings.json", ".config/opencode/opencode.json", ".config/mimocode/mimocode.json", ".pi/agent/settings.json", ".config/goose/config.yaml", diff --git a/internal/profile/profile_test.go b/internal/profile/profile_test.go index 0d8e63cc..f57837eb 100644 --- a/internal/profile/profile_test.go +++ b/internal/profile/profile_test.go @@ -8,6 +8,7 @@ import ( "strings" "testing" + "github.com/yetone/magpie/internal/agentenv" "github.com/yetone/magpie/internal/library" ) @@ -19,9 +20,11 @@ func sandbox(t *testing.T) string { t.Setenv("USERPROFILE", h) t.Setenv("XDG_CONFIG_HOME", filepath.Join(h, ".config")) t.Setenv("PATH", "") - for _, k := range []string{"CLAUDE_CONFIG_DIR", "CODEX_HOME", "PI_CODING_AGENT_DIR", "OMO_CODING_AGENT_DIR", "SENPI_CODING_AGENT_DIR", "COPILOT_HOME", "APPDATA", "LOCALAPPDATA", "DSH_HOME"} { + for _, k := range agentenv.Vars { t.Setenv(k, "") } + t.Setenv("APPDATA", "") + t.Setenv("LOCALAPPDATA", "") for _, f := range []string{".claude/settings.json", ".codex/config.toml"} { write(t, filepath.Join(h, f), "") } diff --git a/internal/provider/azure_test.go b/internal/provider/azure_test.go index 806a87ca..2c1deb51 100644 --- a/internal/provider/azure_test.go +++ b/internal/provider/azure_test.go @@ -9,6 +9,8 @@ import ( "strings" "sync" "testing" + + "github.com/yetone/magpie/internal/agentenv" ) func azureHome(t *testing.T) { @@ -21,7 +23,7 @@ func azureHome(t *testing.T) { t.Setenv("XDG_CONFIG_HOME", filepath.Join(h, ".config")) t.Setenv("XDG_CACHE_HOME", filepath.Join(h, ".cache")) t.Setenv("PATH", h) - for _, v := range []string{"CLAUDE_CONFIG_DIR", "CODEX_HOME"} { + for _, v := range agentenv.Vars { t.Setenv(v, "") } } diff --git a/internal/provider/balance_parts_test.go b/internal/provider/balance_parts_test.go index 39db6925..6e174be8 100644 --- a/internal/provider/balance_parts_test.go +++ b/internal/provider/balance_parts_test.go @@ -8,6 +8,8 @@ import ( "path/filepath" "testing" "time" + + "github.com/yetone/magpie/internal/agentenv" ) // A balance field with several amounts, or a percent, comes to the card @@ -21,7 +23,7 @@ func TestBalanceParts(t *testing.T) { t.Setenv("XDG_CONFIG_HOME", filepath.Join(h, ".config")) t.Setenv("XDG_CACHE_HOME", filepath.Join(h, ".cache")) t.Setenv("PATH", h) - for _, v := range []string{"CLAUDE_CONFIG_DIR", "CODEX_HOME"} { + for _, v := range agentenv.Vars { t.Setenv(v, "") } keyBalanceCache.data = nil diff --git a/internal/provider/balance_test.go b/internal/provider/balance_test.go index 53fb02fa..58ab5f0c 100644 --- a/internal/provider/balance_test.go +++ b/internal/provider/balance_test.go @@ -7,6 +7,8 @@ import ( "path/filepath" "strings" "testing" + + "github.com/yetone/magpie/internal/agentenv" ) func TestBalanceReaders(t *testing.T) { @@ -109,7 +111,7 @@ func TestKeyBalances(t *testing.T) { t.Setenv("XDG_CONFIG_HOME", filepath.Join(h, ".config")) t.Setenv("XDG_CACHE_HOME", filepath.Join(h, ".cache")) t.Setenv("PATH", h) - for _, v := range []string{"CLAUDE_CONFIG_DIR", "CODEX_HOME"} { + for _, v := range agentenv.Vars { t.Setenv(v, "") } keyBalanceCache.data = nil @@ -325,7 +327,7 @@ func TestBalanceURLNamesTheKey(t *testing.T) { t.Setenv("XDG_CONFIG_HOME", filepath.Join(h, ".config")) t.Setenv("XDG_CACHE_HOME", filepath.Join(h, ".cache")) t.Setenv("PATH", h) - for _, v := range []string{"CLAUDE_CONFIG_DIR", "CODEX_HOME"} { + for _, v := range agentenv.Vars { t.Setenv(v, "") } keyBalanceCache.data = nil diff --git a/internal/provider/fixv1_test.go b/internal/provider/fixv1_test.go index 2e40e58d..0236dfb2 100644 --- a/internal/provider/fixv1_test.go +++ b/internal/provider/fixv1_test.go @@ -7,6 +7,8 @@ import ( "path/filepath" "strings" "testing" + + "github.com/yetone/magpie/internal/agentenv" ) // A relay given without its /v1 lists its models under /v1 only; fetching @@ -20,7 +22,7 @@ func TestFetchAddsMissingV1(t *testing.T) { t.Setenv("XDG_CONFIG_HOME", filepath.Join(h, ".config")) t.Setenv("XDG_CACHE_HOME", filepath.Join(h, ".cache")) t.Setenv("PATH", h) - for _, v := range []string{"CLAUDE_CONFIG_DIR", "CODEX_HOME"} { + for _, v := range agentenv.Vars { t.Setenv(v, "") } @@ -79,7 +81,7 @@ func TestArkBaseKeepsItsPath(t *testing.T) { t.Setenv("XDG_CONFIG_HOME", filepath.Join(h, ".config")) t.Setenv("XDG_CACHE_HOME", filepath.Join(h, ".cache")) t.Setenv("PATH", h) - for _, v := range []string{"CLAUDE_CONFIG_DIR", "CODEX_HOME"} { + for _, v := range agentenv.Vars { t.Setenv(v, "") } var asked []string diff --git a/internal/provider/key_quota_last_test.go b/internal/provider/key_quota_last_test.go index d8761cff..21c5fcab 100644 --- a/internal/provider/key_quota_last_test.go +++ b/internal/provider/key_quota_last_test.go @@ -7,6 +7,8 @@ import ( "path/filepath" "sync/atomic" "testing" + + "github.com/yetone/magpie/internal/agentenv" ) // A Command Code key's plan and balance, read once, still show when @@ -22,7 +24,7 @@ func TestKeyQuotasKeepLast(t *testing.T) { t.Setenv("XDG_CONFIG_HOME", filepath.Join(h, ".config")) t.Setenv("XDG_CACHE_HOME", filepath.Join(h, ".cache")) t.Setenv("PATH", h) - for _, v := range []string{"CLAUDE_CONFIG_DIR", "CODEX_HOME"} { + for _, v := range agentenv.Vars { t.Setenv(v, "") } restart := func() { diff --git a/internal/provider/models_test.go b/internal/provider/models_test.go index bc59f230..0888a713 100644 --- a/internal/provider/models_test.go +++ b/internal/provider/models_test.go @@ -8,6 +8,7 @@ import ( "path/filepath" "testing" + "github.com/yetone/magpie/internal/agentenv" "github.com/yetone/magpie/internal/catalog" ) @@ -119,7 +120,7 @@ func TestOffKeyIsNotFetched(t *testing.T) { t.Setenv("XDG_CONFIG_HOME", filepath.Join(h, ".config")) t.Setenv("XDG_CACHE_HOME", filepath.Join(h, ".cache")) t.Setenv("PATH", h) - for _, v := range []string{"CLAUDE_CONFIG_DIR", "CODEX_HOME"} { + for _, v := range agentenv.Vars { t.Setenv(v, "") } diff --git a/internal/provider/modelsurl_test.go b/internal/provider/modelsurl_test.go index 6516ae2a..ff239f38 100644 --- a/internal/provider/modelsurl_test.go +++ b/internal/provider/modelsurl_test.go @@ -6,6 +6,8 @@ import ( "net/http/httptest" "path/filepath" "testing" + + "github.com/yetone/magpie/internal/agentenv" ) // A vendor that lists its models away from the base URL requests go to @@ -19,7 +21,7 @@ func TestFetchFromModelsURL(t *testing.T) { t.Setenv("XDG_CONFIG_HOME", filepath.Join(h, ".config")) t.Setenv("XDG_CACHE_HOME", filepath.Join(h, ".cache")) t.Setenv("PATH", h) - for _, v := range []string{"CLAUDE_CONFIG_DIR", "CODEX_HOME"} { + for _, v := range agentenv.Vars { t.Setenv(v, "") } plan := httptest.NewServer(http.NotFoundHandler()) // serves chat, lists nothing diff --git a/internal/provider/planquota_test.go b/internal/provider/planquota_test.go index 587f3448..ab8161d9 100644 --- a/internal/provider/planquota_test.go +++ b/internal/provider/planquota_test.go @@ -10,6 +10,8 @@ import ( "strings" "testing" "time" + + "github.com/yetone/magpie/internal/agentenv" ) func TestPlanQuotaSource(t *testing.T) { @@ -221,7 +223,7 @@ func TestPlanQuotas(t *testing.T) { t.Setenv("XDG_CONFIG_HOME", filepath.Join(h, ".config")) t.Setenv("XDG_CACHE_HOME", filepath.Join(h, ".cache")) t.Setenv("PATH", h) - for _, v := range []string{"CLAUDE_CONFIG_DIR", "CODEX_HOME"} { + for _, v := range agentenv.Vars { t.Setenv(v, "") } srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { diff --git a/internal/provider/zhipu_team_key_test.go b/internal/provider/zhipu_team_key_test.go index a3759d77..d5a7d838 100644 --- a/internal/provider/zhipu_team_key_test.go +++ b/internal/provider/zhipu_team_key_test.go @@ -9,6 +9,8 @@ import ( "sync" "testing" "time" + + "github.com/yetone/magpie/internal/agentenv" ) // #236: a Zhipu key on a team's GLM Coding Plan, added as a key and not @@ -23,7 +25,7 @@ func TestZhipuKeyTeamFields(t *testing.T) { t.Setenv("XDG_CONFIG_HOME", filepath.Join(h, ".config")) t.Setenv("XDG_CACHE_HOME", filepath.Join(h, ".cache")) t.Setenv("PATH", h) - for _, v := range []string{"CLAUDE_CONFIG_DIR", "CODEX_HOME"} { + for _, v := range agentenv.Vars { t.Setenv(v, "") } asked := map[string]http.Header{} diff --git a/internal/sessions/calls_test.go b/internal/sessions/calls_test.go index 6e75926a..066718b8 100644 --- a/internal/sessions/calls_test.go +++ b/internal/sessions/calls_test.go @@ -7,6 +7,8 @@ import ( "strings" "testing" "time" + + "github.com/yetone/magpie/internal/agentenv" ) var callT0 = time.Date(2026, 9, 20, 10, 0, 0, 0, time.UTC) @@ -18,13 +20,13 @@ func setupCalls(t *testing.T) callDirs { t.Helper() dir := t.TempDir() d := callDirs{filepath.Join(dir, "claude"), filepath.Join(dir, "codex"), filepath.Join(dir, "desktop")} + for _, k := range agentenv.Vars { + t.Setenv(k, "") + } t.Setenv("XDG_CACHE_HOME", filepath.Join(dir, "cache")) t.Setenv("XDG_DATA_HOME", filepath.Join(dir, "data")) t.Setenv("CLAUDE_CONFIG_DIR", d.claude) t.Setenv("CODEX_HOME", d.codex) - t.Setenv("DSH_HOME", "") - t.Setenv("QODER_CONFIG_DIR", "") - t.Setenv("QODERCN_CONFIG_DIR", "") t.Setenv("HOME", filepath.Join(dir, "home")) t.Setenv("USERPROFILE", filepath.Join(dir, "home")) callDesktopDirs = func() []string { return []string{d.desktop} } diff --git a/internal/sessions/sessions_test.go b/internal/sessions/sessions_test.go index 38167aba..32383710 100644 --- a/internal/sessions/sessions_test.go +++ b/internal/sessions/sessions_test.go @@ -9,6 +9,7 @@ import ( "testing" "time" + "github.com/yetone/magpie/internal/agentenv" "github.com/yetone/magpie/internal/catalog" "github.com/yetone/magpie/internal/settings" ) @@ -40,22 +41,19 @@ func setup(t *testing.T) (claude, codex string) { claude, codex = filepath.Join(dir, "claude"), filepath.Join(dir, "codex") copyTree(t, "testdata/claude", claude) copyTree(t, "testdata/codex", codex) + for _, env := range agentenv.Vars { + t.Setenv(env, "") + } t.Setenv("CLAUDE_CONFIG_DIR", claude) t.Setenv("CODEX_HOME", codex) t.Setenv("XDG_CACHE_HOME", filepath.Join(dir, "cache")) // OpenCode and Pi keep nothing here unless a test puts it there t.Setenv("XDG_DATA_HOME", filepath.Join(dir, "data")) t.Setenv("PI_CODING_AGENT_DIR", filepath.Join(dir, "pi")) - t.Setenv("OPENCODE_DB", "") - t.Setenv("PI_CODING_AGENT_SESSION_DIR", "") // ZCode, dsh, Cline, Qoder, Grok Build, WorkBuddy and omp keep theirs in // the home folder: never the real one's t.Setenv("HOME", filepath.Join(dir, "home")) t.Setenv("USERPROFILE", filepath.Join(dir, "home")) - for _, env := range []string{"DSH_HOME", "CLINE_DIR", "CLINE_DATA_DIR", "CLINE_SESSION_DATA_DIR", "QODER_CONFIG_DIR", "QODERCN_CONFIG_DIR", - "GROK_HOME", "WORKBUDDY_CONFIG_DIR"} { - t.Setenv(env, "") - } PriceOf = func(_ settings.Settings, m string) (catalog.Price, bool) { switch m { case "claude-opus-5-5": diff --git a/internal/tui/tui_test.go b/internal/tui/tui_test.go index 63d12898..9756800c 100644 --- a/internal/tui/tui_test.go +++ b/internal/tui/tui_test.go @@ -9,6 +9,7 @@ import ( tea "github.com/charmbracelet/bubbletea" + "github.com/yetone/magpie/internal/agentenv" "github.com/yetone/magpie/internal/library" "github.com/yetone/magpie/internal/provider" ) @@ -24,9 +25,12 @@ func home(t *testing.T) string { t.Setenv("XDG_CACHE_HOME", filepath.Join(h, ".cache")) t.Setenv("PATH", "") t.Setenv("XDG_DATA_HOME", filepath.Join(h, ".local", "share")) - for _, k := range []string{"CLAUDE_CONFIG_DIR", "CODEX_HOME", "APPDATA", "VISUAL", "EDITOR", "OPENCODE_DB", "PI_CODING_AGENT_DIR", "OMO_CODING_AGENT_DIR", "SENPI_CODING_AGENT_DIR", "PI_CODING_AGENT_SESSION_DIR", "DSH_HOME", "QODER_CONFIG_DIR", "QODERCN_CONFIG_DIR"} { + for _, k := range agentenv.Vars { t.Setenv(k, "") } + t.Setenv("APPDATA", "") + t.Setenv("VISUAL", "") + t.Setenv("EDITOR", "") for _, f := range []string{".claude/settings.json", ".codex/config.toml"} { write(t, filepath.Join(h, f), "") } diff --git a/sessions_cli_test.go b/sessions_cli_test.go index c23f14ac..e1f5510d 100644 --- a/sessions_cli_test.go +++ b/sessions_cli_test.go @@ -9,6 +9,7 @@ import ( "testing" "time" + "github.com/yetone/magpie/internal/agentenv" "github.com/yetone/magpie/internal/catalog" "github.com/yetone/magpie/internal/sessions" "github.com/yetone/magpie/internal/settings" @@ -26,12 +27,10 @@ func sessionsHome(t *testing.T) time.Time { // OpenCode's and Pi's folders in the sandbox too (HOME isn't the home // on Windows) t.Setenv("XDG_DATA_HOME", filepath.Join(h, ".local", "share")) + for _, k := range agentenv.Vars { + t.Setenv(k, "") + } t.Setenv("PI_CODING_AGENT_DIR", filepath.Join(h, ".pi", "agent")) - t.Setenv("OPENCODE_DB", "") - t.Setenv("PI_CODING_AGENT_SESSION_DIR", "") - t.Setenv("DSH_HOME", "") - t.Setenv("QODER_CONFIG_DIR", "") - t.Setenv("QODERCN_CONFIG_DIR", "") for from, env := range map[string]string{"claude": "CLAUDE_CONFIG_DIR", "codex": "CODEX_HOME"} { dir := filepath.Join(h, "."+from) if err := os.CopyFS(dir, os.DirFS(filepath.Join("internal", "sessions", "testdata", from))); err != nil { diff --git a/webdav_cli_test.go b/webdav_cli_test.go index 37660b5a..dd553601 100644 --- a/webdav_cli_test.go +++ b/webdav_cli_test.go @@ -12,6 +12,7 @@ import ( "sync" "testing" + "github.com/yetone/magpie/internal/agentenv" "github.com/yetone/magpie/internal/davsync" "github.com/yetone/magpie/internal/provider" ) @@ -25,12 +26,14 @@ func webdavHome(t *testing.T) { t.Setenv("USERPROFILE", home) t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config")) t.Setenv("XDG_CACHE_HOME", filepath.Join(home, ".cache")) - t.Setenv("CLAUDE_CONFIG_DIR", filepath.Join(home, ".claude")) - t.Setenv("CODEX_HOME", filepath.Join(home, ".codex")) t.Setenv("PATH", "") - for _, v := range []string{"DSH_HOME", "PI_CODING_AGENT_DIR", "COPILOT_HOME", "CLINE_DIR", "GROK_HOME", "HERMES_HOME", "HANA_HOME", "APPDATA", "LOCALAPPDATA"} { + for _, v := range agentenv.Vars { t.Setenv(v, "") } + t.Setenv("APPDATA", "") + t.Setenv("LOCALAPPDATA", "") + t.Setenv("CLAUDE_CONFIG_DIR", filepath.Join(home, ".claude")) + t.Setenv("CODEX_HOME", filepath.Join(home, ".codex")) t.Setenv("MAGPIE_ADDR", "127.0.0.1:1") piped(t) }