| 570 | } |
| 571 | |
| 572 | func parseShellRC(path, modelOverride string) (ResolvedEndpoint, bool, error) { |
| 573 | data, err := os.ReadFile(path) |
| 574 | if err != nil { |
| 575 | return ResolvedEndpoint{}, false, nil |
| 576 | } |
| 577 | |
| 578 | var baseURL, token, model string |
| 579 | for _, line := range strings.Split(string(data), "\n") { |
| 580 | line = strings.TrimSpace(line) |
| 581 | matches := exportRe.FindStringSubmatch(line) |
| 582 | if matches == nil { |
| 583 | continue |
| 584 | } |
| 585 | key := matches[1] |
| 586 | value := matches[2] |
| 587 | if value == "" { |
| 588 | value = matches[3] |
| 589 | } |
| 590 | if value == "" { |
| 591 | value = matches[4] |
| 592 | } |
| 593 | value = strings.TrimSpace(value) |
| 594 | |
| 595 | switch key { |
| 596 | case "ANTHROPIC_BASE_URL": |
| 597 | baseURL = value |
| 598 | case "ANTHROPIC_AUTH_TOKEN": |
| 599 | token = value |
| 600 | case "ANTHROPIC_MODEL": |
| 601 | model = value |
| 602 | } |
| 603 | } |
| 604 | if modelOverride != "" { |
| 605 | model = modelOverride |
| 606 | } |
| 607 | |
| 608 | if baseURL == "" || token == "" || model == "" { |
| 609 | return ResolvedEndpoint{}, false, nil |
| 610 | } |
| 611 | |
| 612 | url := ensureMessagesSuffix(baseURL) |
| 613 | |
| 614 | // Claude Code shell rc tokens are OAuth/Bearer-style credentials. |
| 615 | return ResolvedEndpoint{URL: url, Token: token, Model: model, Protocol: ProtocolAnthropic, AuthHeader: "authorization", Source: "Shell rc file"}, true, nil |
| 616 | } |
| 617 | |
| 618 | func defaultAuthHeader(protocol string) string { |
| 619 | // auth_header is Anthropic-only; OpenAI-compatible clients keep API key auth. |