2026-03-03 14:18:05 +00:00
package cmd
import (
2026-03-04 14:04:29 +00:00
"bufio"
2026-03-03 14:18:05 +00:00
"fmt"
"os"
"strings"
"github.com/fatih/color"
"github.com/spf13/cobra"
"gmgauthier.com/grokkit/config"
"gmgauthier.com/grokkit/internal/grok"
)
var scaffoldCmd = & cobra . Command {
2026-03-04 14:04:29 +00:00
Use : "scaffold [path]" ,
2026-03-03 14:18:05 +00:00
Short : "Scaffold a new file with Grok (safe preview + confirmation)" ,
2026-03-04 14:04:29 +00:00
Long : ` Generate a new file from a description. Shows preview and requires explicit confirmation before writing. ` ,
Run : runScaffold ,
}
2026-03-03 14:18:05 +00:00
2026-03-04 14:04:29 +00:00
func init ( ) {
scaffoldCmd . Flags ( ) . String ( "description" , "" , "Scaffold description (used internally by agent mode)" )
rootCmd . AddCommand ( scaffoldCmd )
}
2026-03-03 14:18:05 +00:00
2026-03-04 14:04:29 +00:00
func runScaffold ( cmd * cobra . Command , args [ ] string ) {
if len ( args ) == 0 {
color . Red ( "Usage: grokkit scaffold <path>" )
return
}
path := args [ 0 ]
// If agent mode passed a description, use it directly
var description string
if scaffoldDescription != "" {
description = scaffoldDescription
color . Cyan ( "Agent description: %s" , description )
} else {
// Normal interactive mode
color . Yellow ( "Enter description for %s: " , path )
scanner := bufio . NewScanner ( os . Stdin )
if scanner . Scan ( ) {
description = strings . TrimSpace ( scanner . Text ( ) )
2026-03-03 14:18:05 +00:00
}
2026-03-04 14:04:29 +00:00
if description == "" {
color . Yellow ( "No description provided." )
2026-03-03 14:18:05 +00:00
return
}
2026-03-04 14:04:29 +00:00
}
2026-03-03 14:18:05 +00:00
2026-03-04 14:04:29 +00:00
client := grok . NewClient ( )
messages := buildScaffoldMessages ( path , description )
2026-03-03 14:18:05 +00:00
2026-03-04 14:04:29 +00:00
color . Yellow ( "Asking Grok to scaffold %s..." , path )
scaffolded := client . Stream ( messages , config . GetModel ( "scaffold" , "" ) )
2026-03-03 14:18:05 +00:00
2026-03-04 14:04:29 +00:00
// Show preview
color . Cyan ( "\n--- Proposed content for %s ---\n%s\n--------------------------------" , path , scaffolded )
2026-03-03 14:18:05 +00:00
2026-03-04 14:04:29 +00:00
var confirm string
color . Yellow ( "Create %s with this content? (y/n): " , path )
fmt . Scanln ( & confirm )
2026-03-03 14:18:05 +00:00
2026-03-04 14:04:29 +00:00
if confirm != "y" && confirm != "Y" {
color . Yellow ( "Aborted." )
return
2026-03-03 14:18:05 +00:00
}
2026-03-04 14:04:29 +00:00
if err := os . WriteFile ( path , [ ] byte ( scaffolded ) , 0644 ) ; err != nil {
color . Red ( "Failed to write file: %v" , err )
return
2026-03-03 14:18:05 +00:00
}
2026-03-04 14:04:29 +00:00
color . Green ( "✅ Successfully scaffolded %s" , path )
2026-03-03 14:18:05 +00:00
}
2026-03-04 14:04:29 +00:00
// buildScaffoldMessages is kept unchanged from original
func buildScaffoldMessages ( path , description string ) [ ] map [ string ] string {
return [ ] map [ string ] string {
{
"role" : "system" ,
"content" : "You are an expert programmer. Generate a complete, well-structured file based on the user's description. Return ONLY the full file content. Do not include any explanations or markdown fences." ,
} ,
{
"role" : "user" ,
"content" : fmt . Sprintf ( "Path: %s\n\nDescription: %s" , path , description ) ,
} ,
}
2026-03-03 14:18:05 +00:00
}