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 (
"fmt"
"os"
"path/filepath"
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-03-01 12:35:21 +00:00
"gmgauthier.com/grokkit/internal/logger"
2026-02-28 19:56:23 +00:00
)
2026-02-28 18:28:27 +00:00
var editCmd = & cobra . Command {
Use : "edit FILE INSTRUCTION" ,
2026-02-28 20:17:12 +00:00
Short : "Edit a file in-place with Grok (safe preview + backup)" ,
Args : cobra . ExactArgs ( 2 ) ,
2026-02-28 18:28:27 +00:00
Run : func ( cmd * cobra . Command , args [ ] string ) {
2026-02-28 19:56:23 +00:00
filePath := args [ 0 ]
2026-02-28 20:17:12 +00:00
instruction := args [ 1 ]
2026-02-28 19:56:23 +00:00
2026-02-28 20:52:03 +00:00
modelFlag , _ := cmd . Flags ( ) . GetString ( "model" )
model := config . GetModel ( modelFlag )
2026-03-01 12:35:21 +00:00
logger . Info ( "edit command started" ,
"file" , filePath ,
"instruction" , instruction ,
"model" , model )
2026-02-28 20:17:12 +00:00
if _ , err := os . Stat ( filePath ) ; os . IsNotExist ( err ) {
2026-03-01 12:35:21 +00:00
logger . Error ( "file not found" , "file" , filePath , "error" , err )
2026-02-28 20:17:12 +00:00
color . Red ( "File not found: %s" , filePath )
2026-02-28 19:56:23 +00:00
os . Exit ( 1 )
}
2026-03-01 12:08:49 +00:00
original , err := os . ReadFile ( filePath )
if err != nil {
2026-03-01 12:35:21 +00:00
logger . Error ( "failed to read file" , "file" , filePath , "error" , err )
2026-03-01 12:08:49 +00:00
color . Red ( "Failed to read file: %v" , err )
os . Exit ( 1 )
}
2026-03-01 12:35:21 +00:00
logger . Debug ( "file read successfully" , "file" , filePath , "size_bytes" , len ( original ) )
2026-02-28 22:59:16 +00:00
cleanedOriginal := removeLastModifiedComments ( string ( original ) )
2026-02-28 19:56:23 +00:00
backupPath := filePath + ".bak"
2026-03-01 12:35:21 +00:00
logger . Debug ( "creating backup" , "backup_path" , backupPath )
2026-03-01 12:08:49 +00:00
if err := os . WriteFile ( backupPath , original , 0644 ) ; err != nil {
2026-03-01 12:35:21 +00:00
logger . Error ( "failed to create backup" , "backup_path" , backupPath , "error" , err )
2026-03-01 12:08:49 +00:00
color . Red ( "Failed to create backup: %v" , err )
os . Exit ( 1 )
}
2026-03-01 12:35:21 +00:00
logger . Info ( "backup created" , "backup_path" , backupPath )
2026-02-28 19:56:23 +00:00
client := grok . NewClient ( )
messages := [ ] map [ string ] string {
2026-02-28 22:59:16 +00:00
{ "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 ) } ,
2026-02-28 19:56:23 +00:00
}
feat: add CI/CD workflows, persistent chat, shell completions, and testing
- Add Gitea CI workflow for testing, linting, and building
- Add release workflow for multi-platform builds and GitHub releases
- Implement persistent chat history with JSON storage
- Add shell completion generation for bash, zsh, fish, powershell
- Introduce custom error types and logging system
- Add interfaces for git and AI client for better testability
- Enhance config with temperature and timeout settings
- Add comprehensive unit tests for config, errors, git, grok, and logger
- Update README with installation, features, and development instructions
- Make model flag persistent across commands
- Add context timeouts to API requests
2026-03-01 12:17:22 +00:00
color . Yellow ( "Asking Grok to %s...\n" , instruction )
raw := client . StreamSilent ( messages , model )
2026-02-28 20:31:02 +00:00
newContent := grok . CleanCodeResponse ( raw )
feat: add CI/CD workflows, persistent chat, shell completions, and testing
- Add Gitea CI workflow for testing, linting, and building
- Add release workflow for multi-platform builds and GitHub releases
- Implement persistent chat history with JSON storage
- Add shell completion generation for bash, zsh, fish, powershell
- Introduce custom error types and logging system
- Add interfaces for git and AI client for better testability
- Enhance config with temperature and timeout settings
- Add comprehensive unit tests for config, errors, git, grok, and logger
- Update README with installation, features, and development instructions
- Make model flag persistent across commands
- Add context timeouts to API requests
2026-03-01 12:17:22 +00:00
color . Green ( "✓ Response received" )
2026-02-28 19:56:23 +00:00
2026-02-28 20:31:02 +00:00
color . Cyan ( "\nProposed changes:" )
fmt . Println ( "--- a/" + filepath . Base ( filePath ) )
fmt . Println ( "+++ b/" + filepath . Base ( filePath ) )
fmt . Print ( newContent )
2026-02-28 19:56:23 +00:00
2026-02-28 20:31:02 +00:00
fmt . Print ( "\n\nApply these changes? (y/n): " )
2026-02-28 19:56:23 +00:00
var confirm string
2026-03-01 14:14:55 +00:00
if _ , err := fmt . Scanln ( & confirm ) ; err != nil {
color . Red ( "Failed to read input: %v" , err )
color . Yellow ( "Changes discarded. Backup saved as %s" , backupPath )
return
}
2026-02-28 20:17:12 +00:00
if confirm != "y" && confirm != "Y" {
color . Yellow ( "Changes discarded. Backup saved as %s" , backupPath )
2026-02-28 19:56:23 +00:00
return
}
2026-03-01 12:35:21 +00:00
logger . Debug ( "applying changes" , "file" , filePath , "new_size_bytes" , len ( newContent ) )
2026-03-01 12:08:49 +00:00
if err := os . WriteFile ( filePath , [ ] byte ( newContent ) , 0644 ) ; err != nil {
2026-03-01 12:35:21 +00:00
logger . Error ( "failed to write file" , "file" , filePath , "error" , err )
2026-03-01 12:08:49 +00:00
color . Red ( "Failed to write file: %v" , err )
os . Exit ( 1 )
}
2026-03-01 12:35:21 +00:00
logger . Info ( "changes applied successfully" ,
"file" , filePath ,
"backup" , backupPath ,
"original_size" , len ( original ) ,
"new_size" , len ( newContent ) )
2026-02-28 20:17:12 +00:00
color . Green ( "✅ Applied successfully! Backup: %s" , backupPath )
2026-02-28 18:28:27 +00:00
} ,
2026-02-28 22:59:16 +00:00
}
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" )
}