2026-02-28 18:03:12 +00:00
package cmd
2026-02-28 18:28:27 +00:00
2026-02-28 19:56:23 +00:00
import (
2026-03-04 14:04:29 +00:00
"bufio"
2026-02-28 19:56:23 +00:00
"fmt"
"os"
2026-02-28 22:59:16 +00:00
"strings"
2026-02-28 19:56:23 +00:00
"github.com/fatih/color"
"github.com/spf13/cobra"
2026-02-28 20:52:03 +00:00
"gmgauthier.com/grokkit/config"
2026-02-28 19:56:23 +00:00
"gmgauthier.com/grokkit/internal/grok"
)
2026-02-28 18:28:27 +00:00
var editCmd = & cobra . Command {
2026-03-04 14:04:29 +00:00
Use : "edit [file]" ,
2026-03-03 20:44:39 +00:00
Short : "Edit a file in-place with Grok (safe preview)" ,
2026-03-04 14:04:29 +00:00
Long : ` Ask Grok to edit a file. Shows a preview diff and requires explicit confirmation before writing. ` ,
Run : runEdit ,
}
2026-02-28 19:56:23 +00:00
2026-03-04 14:04:29 +00:00
func init ( ) {
editCmd . Flags ( ) . String ( "instruction" , "" , "Edit instruction (used internally by agent mode)" )
rootCmd . AddCommand ( editCmd )
}
2026-03-01 12:35:21 +00:00
2026-03-04 14:04:29 +00:00
func runEdit ( cmd * cobra . Command , args [ ] string ) {
if len ( args ) == 0 {
color . Red ( "Usage: grokkit edit <file>" )
return
}
file := args [ 0 ]
2026-02-28 19:56:23 +00:00
2026-03-04 14:04:29 +00:00
// If agent mode passed an instruction, use it directly (no prompt)
var instruction string
if editInstruction != "" {
instruction = editInstruction
color . Cyan ( "Agent instruction: %s" , instruction )
} else {
// Normal interactive mode
color . Yellow ( "Enter edit instruction for %s: " , file )
scanner := bufio . NewScanner ( os . Stdin )
if scanner . Scan ( ) {
instruction = strings . TrimSpace ( scanner . Text ( ) )
2026-03-01 12:08:49 +00:00
}
2026-03-04 14:04:29 +00:00
if instruction == "" {
color . Yellow ( "No instruction provided." )
return
2026-02-28 19:56:23 +00:00
}
2026-03-04 14:04:29 +00:00
}
2026-02-28 19:56:23 +00:00
2026-03-04 14:04:29 +00:00
client := grok . NewClient ( )
messages := buildEditMessages ( file , instruction )
2026-02-28 19:56:23 +00:00
2026-03-04 14:04:29 +00:00
color . Yellow ( "Asking Grok to edit %s..." , file )
edited := client . Stream ( messages , config . GetModel ( "edit" , "" ) )
2026-02-28 19:56:23 +00:00
2026-03-04 14:04:29 +00:00
// Show preview
color . Cyan ( "\n--- Proposed changes to %s ---\n%s\n--------------------------------" , file , edited )
2026-02-28 19:56:23 +00:00
2026-03-04 14:04:29 +00:00
var confirm string
color . Yellow ( "Apply these changes to %s? (y/n): " , file )
2026-03-04 14:18:23 +00:00
_ , _ = fmt . Scanln ( & confirm )
2026-02-28 22:59:16 +00:00
2026-03-04 14:04:29 +00:00
if confirm != "y" && confirm != "Y" {
color . Yellow ( "Aborted." )
return
}
2026-02-28 22:59:16 +00:00
2026-03-04 14:04:29 +00:00
if err := os . WriteFile ( file , [ ] byte ( edited ) , 0644 ) ; err != nil {
color . Red ( "Failed to write file: %v" , err )
return
2026-02-28 22:59:16 +00:00
}
2026-03-04 14:04:29 +00:00
color . Green ( "✅ Successfully edited %s" , file )
}
// buildEditMessages is kept unchanged from original
func buildEditMessages ( file , instruction string ) [ ] map [ string ] string {
content , _ := os . ReadFile ( file )
return [ ] map [ string ] string {
{
"role" : "system" ,
"content" : "You are an expert programmer. Edit the following file according to the user's instruction. Return ONLY the full new file content. Do not include any explanations." ,
} ,
{
"role" : "user" ,
"content" : fmt . Sprintf ( "File: %s\n\nCurrent content:\n%s\n\nInstruction: %s" , file , string ( content ) , instruction ) ,
} ,
}
2026-02-28 22:59:16 +00:00
}