Repository navigation
Expand file tree
/
Copy pathcommand_shared.go
More file actions
130 lines (122 loc) · 2.92 KB
/
Copy pathcommand_shared.go
File metadata and controls
130 lines (122 loc) · 2.92 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package contexting
import (
"fmt"
"net/url"
"os"
"path/filepath"
)
type CommonFlags struct {
OutputPath string
SynonymCache string
Model string
APIKey string
Endpoint string
BatchSize int
SynonymsPerName int
SynonymsMax int
SymbolExtractor string
Verbose bool
ExtraIgnores []string
}
func (c *CommonFlags) normalize() {
// BatchSize 0 means smart batching (up to 1000 names per request)
if c.SynonymsPerName <= 0 {
c.SynonymsPerName = defaultSynonyms
}
// Resolve the synonym output cap.
if c.SynonymsMax <= 0 {
c.SynonymsMax = defaultSynonymsMax
}
if c.SynonymCache == "" {
c.SynonymCache = ".ctxt/ctx_cache.json"
}
}
// resolveStartupConfigPath anchors the default config path to the resolved project
// root so ctxt watch/mcp work regardless of the process working directory. When a
// root argument is given, the default ".ctxt/ctx_config.toml" resolves to that root;
// otherwise it resolves to the working directory as before. An explicitly supplied
// --config keeps its previous behavior: it resolves against the working directory.
func resolveStartupConfigPath(configPath string, rootArg string, configOverridden bool) (string, error) {
if configOverridden {
if configPath == "" {
return "", nil
}
return filepath.Abs(configPath)
}
configRoot := "."
if rootArg != "" {
configRoot = rootArg
}
absRoot, err := filepath.Abs(configRoot)
if err != nil {
return "", fmt.Errorf("resolve config root: %w", err)
}
return resolveProjectPath(absRoot, configPath), nil
}
func resolveLLMConfig(flags CommonFlags, llmCfg LLMConfig) (endpoint, model, apiKey string, temperature float64, maxTokens int, provider string) {
provider = llmCfg.Provider
if provider == "" {
provider = "openrouter"
}
endpoint = flags.Endpoint
if endpoint == "" {
endpoint = llmCfg.Endpoint
}
if endpoint == "" {
endpoint = defaultEndpoint
}
model = flags.Model
if model == "" {
model = llmCfg.Model
}
if model == "" {
model = defaultModel
}
apiKey = flags.APIKey
if apiKey == "" {
apiKey = llmCfg.APIKey
}
if apiKey == "" {
keyEnv := llmCfg.APIKeyEnv
if keyEnv != "" {
apiKey = os.Getenv(keyEnv)
}
}
if apiKey == "" {
apiKey = os.Getenv("LLM_API_KEY")
}
if apiKey == "" {
apiKey = os.Getenv("OPENROUTER_API_KEY")
}
temperature = llmCfg.Temperature
if temperature == 0 {
temperature = 0.9
}
maxTokens = llmCfg.MaxTokens
if offlineMode {
apiKey = ""
}
return
}
func maskAPIKey(key string) string {
if key == "" {
return "[not set]"
}
return "[set]"
}
func endpointForLog(endpoint string) string {
parsed, err := url.Parse(endpoint)
if err != nil || parsed.Scheme == "" || parsed.Host == "" {
return "[invalid]"
}
return parsed.Scheme + "://" + parsed.Host
}
func emitSynonymWarning(err error) {
if err == nil {
return
}
if isCanceledError(err) {
return
}
LogWarnf("synonym generation failed, continuing without synonyms: %v", err)
}