Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions internal/claude/claude.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,18 @@ func BuildEnv(configDir string) []string {
return env
}

// UnsetEnv removes a named environment variable from an env slice. If the key
// is not present, the slice is returned unchanged.
func UnsetEnv(env []string, key string) []string {
prefix := key + "="
for i, e := range env {
if len(e) >= len(prefix) && e[:len(prefix)] == prefix {
return append(env[:i], env[i+1:]...)
}
}
return env
}

// RunDirect executes the claude binary as a child process without a PTY
// wrapper, connecting stdin/stdout/stderr directly. It returns the child's exit
// code and any non-exit error. This is used by subcommands like "auth login"
Expand Down
24 changes: 24 additions & 0 deletions internal/claude/claude_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,30 @@ func TestRunDirect_BinaryNotFound(t *testing.T) {
assert.Error(t, err)
}

func TestUnsetEnv_RemovesKey(t *testing.T) {
env := []string{"FOO=bar", "CLAUDE_CODE_USE_BEDROCK=1", "BAZ=qux"}
result := UnsetEnv(env, "CLAUDE_CODE_USE_BEDROCK")
assert.Equal(t, []string{"FOO=bar", "BAZ=qux"}, result)
}

func TestUnsetEnv_KeyNotPresent(t *testing.T) {
env := []string{"FOO=bar", "BAZ=qux"}
result := UnsetEnv(env, "CLAUDE_CODE_USE_BEDROCK")
assert.Equal(t, []string{"FOO=bar", "BAZ=qux"}, result)
}

func TestUnsetEnv_EmptyEnv(t *testing.T) {
result := UnsetEnv([]string{}, "FOO")
assert.Empty(t, result)
}

func TestUnsetEnv_DoesNotMatchPrefix(t *testing.T) {
env := []string{"CLAUDE_CODE_USE_BEDROCK_EXTRA=1", "FOO=bar"}
result := UnsetEnv(env, "CLAUDE_CODE_USE_BEDROCK")
// Should not remove CLAUDE_CODE_USE_BEDROCK_EXTRA since it's a different key
assert.Equal(t, []string{"CLAUDE_CODE_USE_BEDROCK_EXTRA=1", "FOO=bar"}, result)
}

func TestBuildEnv_PreservesOtherVars(t *testing.T) {
t.Setenv("MY_TEST_VAR_12345", "hello")

Expand Down
16 changes: 15 additions & 1 deletion internal/cli/passthrough.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,14 @@ func runPassthrough(cmd *cobra.Command, _ []string) error {
cfg := p.LoadConfig()

env := claude.BuildEnv(p.ConfigDir)

// When the profile has SSO credentials, strip provider flags that would
// override the auth method. The user's intent is to use the Anthropic API.
if authStatus == "keychain" || authStatus == "file" {
env = claude.UnsetEnv(env, "CLAUDE_CODE_USE_BEDROCK")
env = claude.UnsetEnv(env, "CLAUDE_CODE_USE_VERTEX")
}

env = setEnv(env, "CLAUDE_PROFILE_NAME", name)
env = setEnv(env, "CLAUDE_PROFILE_AUTH", authStatus)
env = setEnv(env, "CLAUDE_PROFILE_SUB", subType)
Expand Down Expand Up @@ -113,7 +121,13 @@ func extractClaudeArgs() []string {

// Version is set at build time via -ldflags (e.g., -ldflags "-X ...cli.Version=1.2.3").
// Falls back to VCS info embedded by Go, or "dev" if neither is available.
var Version = buildVersion()
var Version string

func init() {
if Version == "" {
Version = buildVersion()
}
}

func buildVersion() string {
info, ok := debug.ReadBuildInfo()
Expand Down