// Last modified: 2026-02-28 22:43:17 GMT package cmd import ( "fmt" "os" "path/filepath" "strings" "time" "github.com/fatih/color" "github.com/spf13/cobra" "gmgauthier.com/grokkit/config" "gmgauthier.com/grokkit/internal/grok" ) var agentCmd = &cobra.Command{ Use: "agent INSTRUCTION", Short: "Multi-file agent — Grok intelligently edits multiple files with preview", Args: cobra.ExactArgs(1), Run: func(cmd *cobra.Command, args []string) { instruction := args[0] modelFlag, _ := cmd.Flags().GetString("model") model := config.GetModel(modelFlag) client := grok.NewClient() color.Yellow("šŸ” Agent mode activated. Scanning project...") var files []string filepath.Walk(".", func(path string, info os.FileInfo, err error) error { if err != nil || info.IsDir() { return err } if strings.HasSuffix(path, ".go") { files = append(files, path) } return nil }) if len(files) == 0 { color.Yellow("No .go files found.") return } color.Yellow("šŸ“„ Found %d files. Asking Grok for a plan...", len(files)) planMessages := []map[string]string{ {"role": "system", "content": "You are an expert software engineer. Given an instruction and list of files, return a clear plan: which files to change and a brief description of what to do in each. List files one per line."}, {"role": "user", "content": fmt.Sprintf("Instruction: %s\n\nFiles:\n%s", instruction, strings.Join(files, "\n"))}, } plan := client.Stream(planMessages, model) color.Cyan("\nGrok's Plan:\n%s", plan) fmt.Print("\nProceed with changes? (y/n): ") var confirm string fmt.Scanln(&confirm) if confirm != "y" && confirm != "Y" { color.Yellow("Aborted.") return } color.Yellow("Applying changes file by file...\n") applyAll := false for i, file := range files { color.Yellow("[%d/%d] → %s", i+1, len(files), file) original, err := os.ReadFile(file) if err != nil { color.Red("Could not read %s", file) continue } backupPath := file + ".bak" _ = os.WriteFile(backupPath, original, 0644) currentTime := time.Now().Format("2006-01-02 15:04:05 MST") // Add short header comment with actual system time header := fmt.Sprintf("// Last modified: %s\n\n", time.Now().Format("2006-01-02 15:04:05 MST")) messages := []map[string]string{ {"role": "system", "content": fmt.Sprintf("You are an expert programmer. The VERY FIRST LINE of the returned file MUST be a header comment in this exact format: '// Last modified: %s'. Then return the complete updated file content. No explanations, no markdown, no diffs, no extra text.", currentTime)}, {"role": "user", "content": fmt.Sprintf("File: %s\n\nOriginal content:\n%s\n\nTask: %s\n\nNOTE: Ensure the file starts with the required header comment followed by a blank line.", filepath.Base(file), original, instruction)}, } raw := client.StreamSilent(messages, "grok-4-1-fast-non-reasoning") newContent := grok.CleanCodeResponse(raw) // Ensure header is present - prepend if missing if !strings.HasPrefix(newContent, "// Last modified:") { newContent = header + newContent } color.Cyan("Proposed changes for %s:", filepath.Base(file)) fmt.Println("--- a/" + filepath.Base(file)) fmt.Println("+++ b/" + filepath.Base(file)) fmt.Print(newContent) if !applyAll { fmt.Print("\nApply this file? (y/n/a = all remaining): ") var answer string fmt.Scanln(&answer) answer = strings.ToLower(strings.TrimSpace(answer)) if answer == "a" { applyAll = true } else if answer != "y" { color.Yellow("Skipped %s (backup kept)", file) continue } } _ = os.WriteFile(file, []byte(newContent), 0644) color.Green("āœ… Applied %s", file) } color.Green("\nšŸŽ‰ Agent mode complete! All changes applied.") }, }