返回 DeepSeek-Reasonix
setup_key_env.go
根目录 / internal / cli / setup_key_env.go
1 package cli
2
3 import (
4 "bufio"
5 "errors"
6 "fmt"
7 "io"
8 "os"
9
10 "reasonix/internal/config"
11 "reasonix/internal/i18n"
12 )
13
14 func (s *providerSetupSession) addPrompted(in *bufio.Scanner, w io.Writer, result providerPromptResult) bool {
15 if result.keyEnvTyped && len(result.credentials) > 0 && len(result.entries) > 0 {
16 names := make([]string, 0, len(result.entries))
17 for _, entry := range result.entries {
18 names = append(names, entry.Name)
19 }
20 from := result.entries[0].APIKeyEnv
21 to, typed := s.settleTypedKeyEnv(in, w, keyEnvPromptLabel(result.entries[0].Kind), names, from, result.keyEnvDraft)
22 result.renameKeyEnv(from, to)
23 result.keyEnvTyped = typed
24 }
25 for _, entry := range result.entries {
26 if !confirmSharedCredential(s.cfg, entry, "") {
27 return false
28 }
29 }
30 if err := s.add(result.entries); err != nil {
31 fmt.Fprintln(os.Stderr, err)
32 return false
33 }
34 s.addProviderAccess(result.entries)
35 for key, value := range result.credentials {
36 var names []string
37 for _, entry := range result.entries {
38 if entry.APIKeyEnv == key {
39 names = append(names, entry.Name)
40 }
41 }
42 if err := s.setCredentialForProviders(names, key, value); err != nil {
43 fmt.Fprintln(os.Stderr, err)
44 return false
45 }
46 if result.keyEnvTyped {
47 for _, name := range names {
48 s.typedKeyEnv[name] = key
49 }
50 }
51 }
52 // After the new keys are staged, so usability sees them.
53 s.promoteDefaultToNewProviders(result.entries)
54 return true
55 }
56
57 func (r *providerPromptResult) renameKeyEnv(from, to string) {
58 if from == to {
59 return
60 }
61 for i := range r.entries {
62 if r.entries[i].APIKeyEnv == from {
63 r.entries[i].APIKeyEnv = to
64 }
65 }
66 if value, ok := r.credentials[from]; ok {
67 delete(r.credentials, from)
68 r.credentials[to] = value
69 }
70 }
71
72 // settleTypedKeyEnv asks again while providers may not claim key, saying who
73 // holds it. Pressing Enter returns draft with typed=false: a private slot.
74 func (s *providerSetupSession) settleTypedKeyEnv(in *bufio.Scanner, w io.Writer, label string, providers []string, key, draft string) (string, bool) {
75 for {
76 var held error
77 for _, name := range providers {
78 if held = s.cfg.CredentialKeyClaimable(key, name); held != nil {
79 break
80 }
81 }
82 if held == nil {
83 return key, true
84 }
85 fmt.Fprintln(w, keyEnvInUseText(held))
86 fmt.Fprintln(w, i18n.M.SetupKeyEnvRetry)
87 var typed bool
88 if key, typed = promptAPIKeyEnvName(in, w, label, draft); !typed {
89 return key, false
90 }
91 }
92 }
93
94 func keyEnvPromptLabel(kind string) string {
95 if kind == "anthropic" {
96 return i18n.M.AnthropicPromptKeyEnv
97 }
98 return i18n.M.CustomPromptKeyEnv
99 }
100
101 func keyEnvInUseText(err error) string {
102 var inUse *config.CredentialKeyInUseError
103 if !errors.As(err, &inUse) {
104 return err.Error()
105 }
106 switch inUse.Holder {
107 case config.CredentialKeyHeldByProvider:
108 return fmt.Sprintf(i18n.M.SetupKeyEnvTakenFmt, inUse.Key, inUse.Provider)
109 case config.CredentialKeyHeldBySetting:
110 return fmt.Sprintf(i18n.M.SetupKeyEnvSettingFmt, inUse.Key)
111 case config.CredentialKeyHeldByEnvironment:
112 return fmt.Sprintf(i18n.M.SetupKeyEnvShellFmt, inUse.Key)
113 default:
114 return fmt.Sprintf(i18n.M.SetupKeyEnvStoredFmt, inUse.Key)
115 }
116 }
117
117 lines GO