fix(custom-model): give a session its own env values back when the selection goes

Applying a custom model writes the endpoint's values over the keys it
injects, and clearing the model unset those keys. A session that had set
one of them itself lost that value: its own DSH_HOME, CODEX_HOME,
GROK_HOME or GEMINI_API_KEY was gone once the model was cleared, and so
was CLAUDE_CONFIG_DIR, which silently moved a Claude session onto the
default account. Switching endpoints did the same.

setCustomModel() now records what the session held under each injected
key and restores it on clear and on switch. Quick-start passes the
caller's values to the Session constructor so they are seen before the
selection lands.

The selection overwrites the only other copy, tmux's setenv, so the
session's own home directory has to survive a Codeman restart on its
own. __customModel therefore stores that one path, the single exception
to persisting keys only, and recovery runs it through
clampEnvOverridesForOwner() so a revoked grant cannot bring it back. Any
other own value, a credential included, stays in memory only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Codeman maintainer committed 2026-11-05 14:25:49 +01:00
1 parent aa463d9d28
commit 10d43b993e
12 files changed
+335 -43

No files matched your search

+13
View File
@@ -702,6 +702,19 @@ export interface CustomModelBookkeeping extends CustomModelSelection {
configDir?: string;
/** Value forced onto the CLI's `model` launch param (pi/omp `custom/<id>`, grok's block name). */
launchModel?: string;
/**
* The variable that moves the CLI's home, when the recipe redirects one (`DSH_HOME`,
* `CLAUDE_CONFIG_DIR`, `CODEX_HOME`, `GROK_HOME`). Its value is a path, which is what
* lets {@link CustomModelBookkeeping.ownEnv} keep that one entry on disk.
*/
homeEnvVar?: string;
/**
* What the session itself had set under keys the selection replaced, put back when the
* selection goes. In memory this can hold a credential (a session's own `GEMINI_API_KEY`),
* so `Session.getCustomModelForPersist()` writes `homeEnvVar`'s entry and nothing else:
* tmux keeps only the injected value, so state.json is the one copy left after a restart.
*/
ownEnv?: Record<string, string>;
}
/**