mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-08 16:39:42 +02:00
refactor: pass envOverrides via tmux export instead of disk write
CLAUDE_CODE_EFFORT_LEVEL (and any CLAUDE_CODE_* / OPENCODE_* key) now flows:
UI dropdown → POST /api/sessions { envOverrides }
→ new Session({ envOverrides })
→ this._envOverrides
→ tmux-manager.buildEnvExports appends `export KEY=<shellescape(VALUE)>`
Previously the API wrote envOverrides to <case>/.claude/settings.local.json, which
created stale state (UI dropdown disagreeing with disk) and polluted user project
directories. Now envOverrides are ephemeral spawn-time state, preserved across
respawnPane cycles via this._envOverrides and across server restart via
SessionState.envOverrides in state.json.
Also removes the now-unused updateCaseEnvVars import from session-routes.ts.
This commit is contained in:
@@ -1032,6 +1032,10 @@ Object.assign(CodemanApp.prototype, {
|
||||
const enabledItems = config.generatedPlan?.filter(i => i.enabled);
|
||||
|
||||
try {
|
||||
const envOverrides = this.buildEnvOverrides(
|
||||
this.getCaseSettings(config.caseName),
|
||||
this.loadAppSettingsFromStorage()
|
||||
);
|
||||
const res = await fetch('/api/ralph-loop/start', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
@@ -1042,6 +1046,7 @@ Object.assign(CodemanApp.prototype, {
|
||||
maxIterations: config.maxIterations || null,
|
||||
enableRespawn: config.enableRespawn,
|
||||
planItems: enabledItems?.length ? enabledItems : undefined,
|
||||
...(Object.keys(envOverrides).length > 0 ? { envOverrides } : {}),
|
||||
}),
|
||||
});
|
||||
const data = await res.json();
|
||||
|
||||
@@ -12,6 +12,22 @@
|
||||
*/
|
||||
|
||||
Object.assign(CodemanApp.prototype, {
|
||||
/**
|
||||
* Build envOverrides payload from case + global settings.
|
||||
* Single source of truth for the server-side tmux setenv values.
|
||||
* Keys omitted when value is default/falsy — backend treats unset as "no override".
|
||||
*/
|
||||
buildEnvOverrides(caseSettings, globalSettings) {
|
||||
const env = {};
|
||||
if (caseSettings?.agentTeams || globalSettings?.agentTeamsEnabled) {
|
||||
env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS = '1';
|
||||
}
|
||||
if (globalSettings?.thinkingEffort) {
|
||||
env.CLAUDE_CODE_EFFORT_LEVEL = globalSettings.thinkingEffort;
|
||||
}
|
||||
return env;
|
||||
},
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
// Quick Start
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
@@ -319,10 +335,7 @@ Object.assign(CodemanApp.prototype, {
|
||||
// Build env overrides from global + case settings (case overrides global)
|
||||
const caseSettings = this.getCaseSettings(caseName);
|
||||
const globalSettings = this.loadAppSettingsFromStorage();
|
||||
const envOverrides = {};
|
||||
if (caseSettings.agentTeams || globalSettings.agentTeamsEnabled) {
|
||||
envOverrides.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS = '1';
|
||||
}
|
||||
const envOverrides = this.buildEnvOverrides(caseSettings, globalSettings);
|
||||
const hasEnvOverrides = Object.keys(envOverrides).length > 0;
|
||||
const useOpus1m = caseSettings.opusContext1m || globalSettings.opusContext1mEnabled;
|
||||
const modelOverride = useOpus1m ? 'opus[1m]' : '';
|
||||
@@ -526,6 +539,7 @@ Object.assign(CodemanApp.prototype, {
|
||||
}
|
||||
|
||||
// Quick-start with opencode mode (auto-allow tools by default)
|
||||
const envOverrides = this.buildEnvOverrides(this.getCaseSettings(caseName), this.loadAppSettingsFromStorage());
|
||||
const res = await fetch('/api/quick-start', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
@@ -533,6 +547,7 @@ Object.assign(CodemanApp.prototype, {
|
||||
caseName,
|
||||
mode: 'opencode',
|
||||
openCodeConfig: { autoAllowTools: true },
|
||||
...(Object.keys(envOverrides).length > 0 ? { envOverrides } : {}),
|
||||
})
|
||||
});
|
||||
const data = await res.json();
|
||||
|
||||
@@ -953,11 +953,21 @@ Object.assign(CodemanApp.prototype, {
|
||||
}
|
||||
const name = `w${startNumber}-${dirName}`;
|
||||
|
||||
// Create session with resumeSessionId
|
||||
// Create session with resumeSessionId — include envOverrides so resumed
|
||||
// conversations inherit current UI settings (effort, agent teams, etc.).
|
||||
// Match by path (not basename) so linked/renamed cases still resolve correctly.
|
||||
const matchingCase = (this.cases || []).find((c) => c.path === workingDir);
|
||||
const caseName = matchingCase?.name || workingDir.split('/').pop() || '';
|
||||
const envOverrides = this.buildEnvOverrides(this.getCaseSettings(caseName), this.loadAppSettingsFromStorage());
|
||||
const createRes = await fetch('/api/sessions', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ workingDir, name, resumeSessionId: sessionId }),
|
||||
body: JSON.stringify({
|
||||
workingDir,
|
||||
name,
|
||||
resumeSessionId: sessionId,
|
||||
...(Object.keys(envOverrides).length > 0 ? { envOverrides } : {}),
|
||||
}),
|
||||
});
|
||||
const createData = await createRes.json();
|
||||
if (!createData.success) throw new Error(createData.error);
|
||||
|
||||
Reference in New Issue
Block a user