Go · 8576 bytes Raw Blame History
1 package llm
2
3 import (
4 "regexp"
5 "strings"
6 "time"
7 )
8
9 // CommandIntent represents what the user was trying to accomplish
10 type CommandIntent struct {
11 PrimaryIntent string // Main action: push, build, test, deploy, etc.
12 SecondaryIntents []string // Additional actions detected
13 Targets []string // What they were acting on: files, branches, containers
14 Complexity string // simple, moderate, complex
15 RiskLevel string // low, medium, high (based on destructiveness)
16 }
17
18 // IntentParser extracts semantic meaning from commands
19 type IntentParser struct {
20 intentPatterns map[string]*regexp.Regexp
21 complexityIndicators []string
22 highRiskPatterns []*regexp.Regexp
23 }
24
25 // NewIntentParser creates a new intent parser
26 func NewIntentParser() *IntentParser {
27 ip := &IntentParser{
28 intentPatterns: make(map[string]*regexp.Regexp),
29 complexityIndicators: []string{
30 "|", "&&", "||", "xargs", "awk", "sed",
31 },
32 }
33 ip.initializePatterns()
34 return ip
35 }
36
37 func (ip *IntentParser) initializePatterns() {
38 // Intent patterns
39 ip.intentPatterns["push"] = regexp.MustCompile(`(git\s+push|docker\s+push|npm\s+publish)`)
40 ip.intentPatterns["pull"] = regexp.MustCompile(`(git\s+pull|docker\s+pull)`)
41 ip.intentPatterns["commit"] = regexp.MustCompile(`git\s+commit`)
42 ip.intentPatterns["merge"] = regexp.MustCompile(`git\s+(merge|rebase)`)
43 ip.intentPatterns["build"] = regexp.MustCompile(`(make|cargo\s+build|npm\s+run\s+build|go\s+build|mvn\s+compile|gradle\s+build|docker\s+build)`)
44 ip.intentPatterns["test"] = regexp.MustCompile(`(test|jest|pytest|cargo\s+test|go\s+test|npm\s+test|mvn\s+test)`)
45 ip.intentPatterns["deploy"] = regexp.MustCompile(`(deploy|kubectl\s+apply|helm\s+install|terraform\s+apply)`)
46 ip.intentPatterns["install"] = regexp.MustCompile(`(install|npm\s+i|pip\s+install|cargo\s+add|go\s+get|apt\s+install|brew\s+install)`)
47 ip.intentPatterns["configure"] = regexp.MustCompile(`(config|configure|setup|init)`)
48 ip.intentPatterns["debug"] = regexp.MustCompile(`(debug|gdb|lldb|strace|lsof)`)
49 ip.intentPatterns["refactor"] = regexp.MustCompile(`(refactor|rename|move\s+.*\.(js|ts|py|rs|go))`)
50 ip.intentPatterns["lint"] = regexp.MustCompile(`(lint|eslint|pylint|clippy|golint|rubocop|prettier)`)
51 ip.intentPatterns["format"] = regexp.MustCompile(`(format|prettier|black|rustfmt|gofmt)`)
52 ip.intentPatterns["start"] = regexp.MustCompile(`(start|run|serve|up)`)
53 ip.intentPatterns["stop"] = regexp.MustCompile(`(stop|kill|down)`)
54 ip.intentPatterns["clean"] = regexp.MustCompile(`(clean|prune|rm|remove)`)
55 ip.intentPatterns["revert"] = regexp.MustCompile(`git\s+(revert|reset|checkout)`)
56
57 // High risk patterns
58 ip.highRiskPatterns = []*regexp.Regexp{
59 regexp.MustCompile(`--force`),
60 regexp.MustCompile(`-f\s`),
61 regexp.MustCompile(`rm\s+-rf`),
62 regexp.MustCompile(`git\s+reset\s+--hard`),
63 regexp.MustCompile(`drop\s+(database|table)`),
64 regexp.MustCompile(`kubectl\s+delete`),
65 regexp.MustCompile(`terraform\s+destroy`),
66 regexp.MustCompile(`docker\s+system\s+prune`),
67 regexp.MustCompile(`sudo\s+rm`),
68 regexp.MustCompile(`chmod\s+777`),
69 }
70 }
71
72 // ParseIntent analyzes a command to extract intent
73 func (ip *IntentParser) ParseIntent(command string) CommandIntent {
74 intent := CommandIntent{
75 PrimaryIntent: "unknown",
76 SecondaryIntents: []string{},
77 Targets: []string{},
78 Complexity: "simple",
79 RiskLevel: "low",
80 }
81
82 commandLower := strings.ToLower(command)
83
84 // Detect intents
85 intentsFound := make(map[string]bool)
86 for intentName, pattern := range ip.intentPatterns {
87 if pattern.MatchString(commandLower) {
88 intentsFound[intentName] = true
89 }
90 }
91
92 // Set primary and secondary intents
93 if len(intentsFound) > 0 {
94 // Priority order for primary intent
95 priorityOrder := []string{
96 "deploy", "push", "build", "test", "merge",
97 "commit", "install", "configure", "start",
98 "stop", "clean", "revert", "debug",
99 }
100
101 for _, priority := range priorityOrder {
102 if intentsFound[priority] {
103 intent.PrimaryIntent = priority
104 delete(intentsFound, priority)
105 break
106 }
107 }
108
109 // Remaining are secondary
110 for secondary := range intentsFound {
111 intent.SecondaryIntents = append(intent.SecondaryIntents, secondary)
112 }
113 }
114
115 // Extract targets (file names, branch names, etc.)
116 intent.Targets = ip.extractTargets(command)
117
118 // Determine complexity
119 intent.Complexity = ip.assessComplexity(command)
120
121 // Determine risk level
122 intent.RiskLevel = ip.assessRisk(command)
123
124 return intent
125 }
126
127 func (ip *IntentParser) extractTargets(command string) []string {
128 targets := []string{}
129
130 // Extract git branches
131 branchPattern := regexp.MustCompile(`(origin/|refs/heads/)?(main|master|develop|feature/[\w-]+|bugfix/[\w-]+)`)
132 if matches := branchPattern.FindAllString(command, -1); len(matches) > 0 {
133 targets = append(targets, matches...)
134 }
135
136 // Extract file paths
137 filePattern := regexp.MustCompile(`[\w/.-]+\.(js|ts|py|rs|go|java|cpp|c|rb|php|json|yaml|yml|toml|md)`)
138 if matches := filePattern.FindAllString(command, -1); len(matches) > 0 {
139 targets = append(targets, matches...)
140 }
141
142 // Extract container/image names
143 containerPattern := regexp.MustCompile(`[\w.-]+:[\w.-]+`)
144 if matches := containerPattern.FindAllString(command, -1); len(matches) > 0 {
145 targets = append(targets, matches...)
146 }
147
148 return targets
149 }
150
151 func (ip *IntentParser) assessComplexity(command string) string {
152 // Check for complexity indicators
153 complexityScore := 0
154
155 for _, indicator := range ip.complexityIndicators {
156 if strings.Contains(command, indicator) {
157 complexityScore++
158 }
159 }
160
161 // Length also indicates complexity
162 if len(command) > 100 {
163 complexityScore++
164 }
165
166 // Multiple commands
167 if strings.Contains(command, "&&") || strings.Contains(command, ";") {
168 complexityScore++
169 }
170
171 if complexityScore == 0 {
172 return "simple"
173 } else if complexityScore <= 2 {
174 return "moderate"
175 }
176 return "complex"
177 }
178
179 func (ip *IntentParser) assessRisk(command string) string {
180 for _, pattern := range ip.highRiskPatterns {
181 if pattern.MatchString(command) {
182 return "high"
183 }
184 }
185
186 // Moderate risk patterns
187 moderateRiskKeywords := []string{
188 "delete", "remove", "drop", "destroy",
189 "force", "hard", "production", "master", "main",
190 }
191
192 commandLower := strings.ToLower(command)
193 for _, keyword := range moderateRiskKeywords {
194 if strings.Contains(commandLower, keyword) {
195 return "medium"
196 }
197 }
198
199 return "low"
200 }
201
202 // ContextualTags generates semantic tags based on context
203 func ContextualTags(ctx *SmartFallbackContext, intent CommandIntent) []InsultTag {
204 tags := []InsultTag{}
205
206 // Add error-based tags
207 if ctx.ErrorPattern != "" {
208 switch ctx.ErrorPattern {
209 case "permission_denied":
210 tags = append(tags, TagPermission)
211 case "merge_conflict":
212 tags = append(tags, TagMergeConflict)
213 case "syntax_error":
214 tags = append(tags, TagSyntax)
215 case "network_error":
216 tags = append(tags, TagNetwork)
217 case "timeout":
218 tags = append(tags, TagTimeout)
219 }
220 }
221
222 // Add command type tags
223 switch ctx.CommandType {
224 case "git":
225 tags = append(tags, TagGit)
226 case "docker":
227 tags = append(tags, TagDocker)
228 case "kubernetes":
229 tags = append(tags, TagKubernetes)
230 case "nodejs":
231 tags = append(tags, TagNode)
232 case "python":
233 tags = append(tags, TagPython)
234 case "rust":
235 tags = append(tags, TagRust)
236 case "golang":
237 tags = append(tags, TagGolang)
238 }
239
240 // Add intent tags
241 switch intent.PrimaryIntent {
242 case "push":
243 tags = append(tags, TagPush)
244 case "pull":
245 tags = append(tags, TagPull)
246 case "commit":
247 tags = append(tags, TagCommit)
248 case "build":
249 tags = append(tags, TagBuild)
250 case "test":
251 tags = append(tags, TagTest)
252 case "deploy":
253 tags = append(tags, TagDeploy)
254 case "install":
255 tags = append(tags, TagInstall)
256 case "revert":
257 tags = append(tags, TagRevert)
258 }
259
260 // Add time-based tags
261 hour := ctx.TimeOfDay
262 if hour >= 22 || hour <= 4 {
263 tags = append(tags, TagLateNight)
264 } else if hour >= 5 && hour <= 7 {
265 tags = append(tags, TagEarlyMorning)
266 }
267
268 // Weekend check
269 if time.Now().Weekday() == time.Saturday || time.Now().Weekday() == time.Sunday {
270 tags = append(tags, TagWeekend)
271 }
272
273 // Add context tags
274 if ctx.IsCI {
275 tags = append(tags, TagCI)
276 }
277
278 if ctx.GitBranch == "main" || ctx.GitBranch == "master" {
279 tags = append(tags, TagMainBranch)
280 }
281
282 if ctx.IsRepeatedFailure {
283 tags = append(tags, TagRepeated)
284 }
285
286 // Complexity tags
287 switch intent.Complexity {
288 case "simple":
289 tags = append(tags, TagSimple)
290 case "complex":
291 tags = append(tags, TagComplex)
292 }
293
294 // Risk tags
295 if intent.RiskLevel == "high" {
296 tags = append(tags, TagProduction)
297 }
298
299 return tags
300 }
301