package cmd import ( "fmt" "os" "path/filepath" "strings" "github.com/fatih/color" "github.com/spf13/cobra" "gmgauthier.com/grokkit/config" "gmgauthier.com/grokkit/internal/grok" "gmgauthier.com/grokkit/internal/logger" ) var editCmd = &cobra.Command{ Use: "edit FILE INSTRUCTION", Short: "Edit a file in-place with Grok (safe preview + backup)", Args: cobra.ExactArgs(2), Run: func(cmd *cobra.Command, args []string) { filePath := args[0] instruction := args[1] modelFlag, _ := cmd.Flags().GetString("model") model := config.GetModel(modelFlag) logger.Info("edit command started", "file", filePath, "instruction", instruction, "model", model) if _, err := os.Stat(filePath); os.IsNotExist(err) { logger.Error("file not found", "file", filePath, "error", err) color.Red("File not found: %s", filePath) os.Exit(1) } original, err := os.ReadFile(filePath) if err != nil { logger.Error("failed to read file", "file", filePath, "error", err) color.Red("Failed to read file: %v", err) os.Exit(1) } logger.Debug("file read successfully", "file", filePath, "size_bytes", len(original)) cleanedOriginal := removeLastModifiedComments(string(original)) backupPath := filePath + ".bak" logger.Debug("creating backup", "backup_path", backupPath) if err := os.WriteFile(backupPath, original, 0644); err != nil { logger.Error("failed to create backup", "backup_path", backupPath, "error", err) color.Red("Failed to create backup: %v", err) os.Exit(1) } logger.Info("backup created", "backup_path", backupPath) client := grok.NewClient() messages := []map[string]string{ {"role": "system", "content": "You are an expert programmer. Remove all unnecessary comments including last modified timestamps and ownership comments. Return only the cleaned code with no explanations, no markdown, no extra text."}, {"role": "user", "content": fmt.Sprintf("File: %s\n\nOriginal content:\n%s\n\nTask: %s", filepath.Base(filePath), cleanedOriginal, instruction)}, } color.Yellow("Asking Grok to %s...\n", instruction) raw := client.StreamSilent(messages, model) newContent := grok.CleanCodeResponse(raw) color.Green("✓ Response received") color.Cyan("\nProposed changes:") fmt.Println("--- a/" + filepath.Base(filePath)) fmt.Println("+++ b/" + filepath.Base(filePath)) fmt.Print(newContent) fmt.Print("\n\nApply these changes? (y/n): ") var confirm string fmt.Scanln(&confirm) if confirm != "y" && confirm != "Y" { color.Yellow("Changes discarded. Backup saved as %s", backupPath) return } logger.Debug("applying changes", "file", filePath, "new_size_bytes", len(newContent)) if err := os.WriteFile(filePath, []byte(newContent), 0644); err != nil { logger.Error("failed to write file", "file", filePath, "error", err) color.Red("Failed to write file: %v", err) os.Exit(1) } logger.Info("changes applied successfully", "file", filePath, "backup", backupPath, "original_size", len(original), "new_size", len(newContent)) color.Green("✅ Applied successfully! Backup: %s", backupPath) }, } func removeLastModifiedComments(content string) string { lines := strings.Split(content, "\n") var cleanedLines []string for _, line := range lines { if strings.Contains(line, "Last modified") { continue } cleanedLines = append(cleanedLines, line) } return strings.Join(cleanedLines, "\n") }