feat(config): add Env field to RuntimeConfig and AgentPresetInfo (#860)

Add support for agent presets to specify environment variables that
get exported when starting sessions. This enables agents to use
environment-based configuration.

Changes:
- Add Env field to RuntimeConfig struct in types.go
- Add Env field to AgentPresetInfo struct in agents.go
- Update RuntimeConfigFromPreset to copy Env from preset
- Update fillRuntimeDefaults to preserve Env field
- Merge agent Env vars in BuildStartupCommand functions
- Add comprehensive tests for Env preservation and copy semantics

This is a prerequisite for the OpenCode agent preset which uses
OPENCODE_PERMISSION='{"*":"allow"}' for auto-approve mode.

Co-authored-by: Avyukth <subhrajit.makur@hotmail.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Steve Yegge
2026-01-21 17:20:09 -08:00
committed by GitHub
parent 9f06eb94c4
commit e12aa45dd6
5 changed files with 145 additions and 1 deletions

View File

@@ -2777,3 +2777,97 @@ func TestBuildStartupCommandWithAgentOverride_NoGTAgentWhenNoOverride(t *testing
t.Errorf("expected no GT_AGENT in command when no override, got: %q", cmd)
}
}
func TestFillRuntimeDefaultsPreservesEnv(t *testing.T) {
t.Parallel()
tests := []struct {
name string
input *RuntimeConfig
wantEnv map[string]string
wantNil bool
}{
{
name: "nil input returns default",
input: nil,
wantNil: false,
},
{
name: "preserves Env map",
input: &RuntimeConfig{
Command: "test-cmd",
Env: map[string]string{
"TEST_VAR": "test-value",
"JSON_VAR": `{"*":"allow"}`,
},
},
wantEnv: map[string]string{
"TEST_VAR": "test-value",
"JSON_VAR": `{"*":"allow"}`,
},
},
{
name: "nil Env stays nil",
input: &RuntimeConfig{
Command: "test-cmd",
Env: nil,
},
wantEnv: nil,
},
{
name: "empty Env stays empty",
input: &RuntimeConfig{
Command: "test-cmd",
Env: map[string]string{},
},
wantEnv: nil, // Empty map is treated as nil (not copied)
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := fillRuntimeDefaults(tt.input)
if result == nil {
if !tt.wantNil {
t.Fatal("fillRuntimeDefaults returned nil unexpectedly")
}
return
}
if tt.wantEnv == nil {
if result.Env != nil && len(result.Env) > 0 {
t.Errorf("expected nil/empty Env, got %v", result.Env)
}
return
}
if len(result.Env) != len(tt.wantEnv) {
t.Errorf("expected %d env vars, got %d", len(tt.wantEnv), len(result.Env))
}
for k, want := range tt.wantEnv {
if got := result.Env[k]; got != want {
t.Errorf("Env[%s] = %q, want %q", k, got, want)
}
}
})
}
}
func TestFillRuntimeDefaultsEnvIsCopy(t *testing.T) {
t.Parallel()
original := &RuntimeConfig{
Command: "test-cmd",
Env: map[string]string{
"ORIGINAL": "value",
},
}
result := fillRuntimeDefaults(original)
// Mutate the result
result.Env["MUTATED"] = "yes"
// Original should be unchanged
if _, exists := original.Env["MUTATED"]; exists {
t.Error("Mutation of result.Env affected original config")
}
}