refactor: better project structure (#35)
This project is starting to grow, and I've seen flaws in the initial project structure design I think I'll restructure the entire project directory for better scalability and also cleaner
This commit is contained in:
@@ -0,0 +1,167 @@
|
||||
package ai
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/versenilvis/iris/spec"
|
||||
)
|
||||
|
||||
func CleanSuggestion(raw string) string {
|
||||
s := strings.TrimSpace(raw)
|
||||
if strings.HasPrefix(s, "```") {
|
||||
lines := strings.Split(s, "\n")
|
||||
if len(lines) > 1 {
|
||||
endIdx := len(lines)
|
||||
if strings.HasPrefix(strings.TrimSpace(lines[len(lines)-1]), "```") {
|
||||
endIdx = len(lines) - 1
|
||||
}
|
||||
s = strings.TrimSpace(strings.Join(lines[1:endIdx], "\n"))
|
||||
}
|
||||
}
|
||||
if len(s) >= 2 && strings.HasPrefix(s, "`") && strings.HasSuffix(s, "`") && !strings.HasPrefix(s, "``") {
|
||||
s = s[1 : len(s)-1]
|
||||
}
|
||||
if len(s) >= 2 && ((strings.HasPrefix(s, "\"") && strings.HasSuffix(s, "\"")) || (strings.HasPrefix(s, "'") && strings.HasSuffix(s, "'"))) {
|
||||
inner := s[1 : len(s)-1]
|
||||
if !strings.ContainsAny(inner, "\"'") {
|
||||
s = inner
|
||||
}
|
||||
}
|
||||
return strings.TrimSpace(s)
|
||||
}
|
||||
|
||||
func NormalizeSuggestion(buf string, suggCmd string) string {
|
||||
suggCmd = CleanSuggestion(suggCmd)
|
||||
|
||||
if strings.Contains(buf, "-m \"") || strings.Contains(buf, "-am \"") || strings.Contains(buf, "--message \"") {
|
||||
if !strings.HasPrefix(strings.ToLower(suggCmd), strings.ToLower(buf)) {
|
||||
for _, flag := range []string{"-m ", "-am ", "--message "} {
|
||||
idx := strings.Index(suggCmd, flag)
|
||||
if idx != -1 {
|
||||
afterFlag := suggCmd[idx+len(flag):]
|
||||
if !strings.HasPrefix(afterFlag, "\"") && !strings.HasPrefix(afterFlag, "'") {
|
||||
suggCmd = suggCmd[:idx+len(flag)] + "\"" + afterFlag + "\""
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return suggCmd
|
||||
}
|
||||
|
||||
func ShouldOverwrite(originalBuf string, currentBuf string, newSugg *spec.Suggestion, currentConfidence int) bool {
|
||||
if newSugg == nil {
|
||||
return false
|
||||
}
|
||||
if !strings.HasPrefix(currentBuf, originalBuf) {
|
||||
return false
|
||||
}
|
||||
if !strings.HasPrefix(strings.ToLower(newSugg.Cmd), strings.ToLower(currentBuf)) {
|
||||
return false
|
||||
}
|
||||
return newSugg.Confidence > currentConfidence
|
||||
}
|
||||
|
||||
func ExtractScriptsAndTargets(sb *strings.Builder, dir string, prefix string) {
|
||||
if data, err := os.ReadFile(filepath.Join(dir, "package.json")); err == nil {
|
||||
var pkg struct {
|
||||
Scripts map[string]string `json:"scripts"`
|
||||
}
|
||||
if err := json.Unmarshal(data, &pkg); err == nil && len(pkg.Scripts) > 0 {
|
||||
var scriptNames []string
|
||||
for name, cmd := range pkg.Scripts {
|
||||
scriptNames = append(scriptNames, fmt.Sprintf("%s: %s", name, cmd))
|
||||
}
|
||||
sort.Strings(scriptNames)
|
||||
if len(scriptNames) > 20 {
|
||||
scriptNames = append(scriptNames[:20], "... (truncated)")
|
||||
}
|
||||
label := "package.json"
|
||||
if prefix != "" {
|
||||
label = prefix + "/package.json"
|
||||
}
|
||||
fmt.Fprintf(sb, "Available %s scripts:\n%s\n\n", label, strings.Join(scriptNames, "\n"))
|
||||
}
|
||||
}
|
||||
if file, err := os.Open(filepath.Join(dir, "Makefile")); err == nil {
|
||||
defer func() { _ = file.Close() }()
|
||||
var targets []string
|
||||
seen := make(map[string]bool)
|
||||
scanner := bufio.NewScanner(file)
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
// Skip variable assignments because operators like := or colons in values trick the colon parser into misclassifying variables as build targets
|
||||
if strings.Contains(line, "=") {
|
||||
continue
|
||||
}
|
||||
if idx := strings.Index(line, ":"); idx > 0 && !strings.HasPrefix(line, "\t") && !strings.HasPrefix(line, " ") {
|
||||
target := strings.TrimSpace(line[:idx])
|
||||
if target != "" && target != ".PHONY" && !strings.Contains(target, " ") && !seen[target] && !strings.HasPrefix(target, ".") {
|
||||
seen[target] = true
|
||||
targets = append(targets, target)
|
||||
}
|
||||
}
|
||||
}
|
||||
_ = scanner.Err()
|
||||
if len(targets) > 0 {
|
||||
sort.Strings(targets)
|
||||
// Cap at 10 targets to keep AI prompt short and avoid exceeding 6000 TPM limit (basedd on Groq api docs because Im using it now)
|
||||
if len(targets) > 10 {
|
||||
targets = append(targets[:10], "... (truncated)")
|
||||
}
|
||||
label := "Makefile"
|
||||
if prefix != "" {
|
||||
label = prefix + "/Makefile"
|
||||
}
|
||||
fmt.Fprintf(sb, "Available %s targets:\n%s\n\n", label, strings.Join(targets, ", "))
|
||||
}
|
||||
}
|
||||
openJustfile := func() (*os.File, error) {
|
||||
if f, err := os.Open(filepath.Join(dir, "justfile")); err == nil {
|
||||
return f, nil
|
||||
}
|
||||
return os.Open(filepath.Join(dir, "Justfile"))
|
||||
}
|
||||
if file, err := openJustfile(); err == nil {
|
||||
defer func() { _ = file.Close() }()
|
||||
var recipes []string
|
||||
seen := make(map[string]bool)
|
||||
scanner := bufio.NewScanner(file)
|
||||
recipeRegex := regexp.MustCompile(`^([a-zA-Z0-9_-]+):`)
|
||||
for scanner.Scan() {
|
||||
line := strings.TrimSpace(scanner.Text())
|
||||
if line == "" || strings.HasPrefix(line, "#") || strings.HasPrefix(line, "[") {
|
||||
continue
|
||||
}
|
||||
if matches := recipeRegex.FindStringSubmatch(line); len(matches) > 1 {
|
||||
recipe := matches[1]
|
||||
if !seen[recipe] {
|
||||
seen[recipe] = true
|
||||
recipes = append(recipes, recipe)
|
||||
}
|
||||
}
|
||||
}
|
||||
_ = scanner.Err()
|
||||
if len(recipes) > 0 {
|
||||
sort.Strings(recipes)
|
||||
// Cap at 10 recipes to keep AI prompt short and avoid exceeding 6000 TPM limit
|
||||
if len(recipes) > 10 {
|
||||
recipes = append(recipes[:10], "... (truncated)")
|
||||
}
|
||||
label := "justfile"
|
||||
if prefix != "" {
|
||||
label = prefix + "/justfile"
|
||||
}
|
||||
fmt.Fprintf(sb, "Available %s recipes:\n%s\n\n", label, strings.Join(recipes, ", "))
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user