feature/recipe_implementation #5

Merged
gmgauthier merged 54 commits from feature/recipe_implementation into master 2026-03-07 23:17:54 +00:00
Showing only changes of commit 685b0f40d7 - Show all commits

View File

@ -6,6 +6,7 @@ import (
"os"
"os/exec"
"path/filepath"
"strconv"
"strings"
"gmgauthier.com/grokkit/internal/grok"
@ -49,9 +50,8 @@ func (r *Runner) Run() error {
r.handleApplyStep(refactorJSONs)
continue
// Explicit trigger for read-only shell commands
case strings.Contains(titleLower, "read-only shell") ||
strings.Contains(titleLower, "shell read-only"):
// Explicit trigger for read-only shell
case strings.Contains(titleLower, "read-only shell") || strings.Contains(titleLower, "shell read-only"):
r.executeReadOnlyShell(step, previousResults)
continue
@ -258,7 +258,7 @@ func createUnifiedPatch(changes []FileChange, patchPath string) error {
return nil
}
// executeReadOnlyShell — safe, whitelisted, read-only shell execution with user confirmation
// executeReadOnlyShell — now handles numbers in args (like tree -L 3)
func (r *Runner) executeReadOnlyShell(step Step, previousResults []string) {
prompt := fmt.Sprintf(`You need additional context from the filesystem for this step.
@ -281,7 +281,7 @@ Return ONLY a JSON array of read-only commands. Example:
},
{
"command": "tree",
"args": ["."]
"args": [".", "-L", 3]
}
]
@ -308,11 +308,11 @@ Only use safe read-only commands from the allowed list.`,
}
jsonStr := response[start:end]
jsonStr = strings.ReplaceAll(jsonStr, "\\\"", "\"") // fix escaped quotes
jsonStr = strings.ReplaceAll(jsonStr, "\\\"", "\"")
type ShellCommand struct {
Command string `json:"command"`
Args []string `json:"args"`
Command string `json:"command"`
Args []interface{} `json:"args"` // allows strings and numbers
}
var cmds []ShellCommand
@ -322,9 +322,24 @@ Only use safe read-only commands from the allowed list.`,
}
for _, cmd := range cmds {
// Build argument list, converting numbers to strings
args := make([]string, len(cmd.Args))
for i, arg := range cmd.Args {
switch v := arg.(type) {
case string:
args[i] = v
case float64:
args[i] = strconv.FormatFloat(v, 'f', -1, 64)
case int, int64:
args[i] = fmt.Sprintf("%v", v)
default:
args[i] = fmt.Sprintf("%v", v)
}
}
fullCmd := cmd.Command
if len(cmd.Args) > 0 {
fullCmd += " " + strings.Join(cmd.Args, " ")
if len(args) > 0 {
fullCmd += " " + strings.Join(args, " ")
}
fmt.Printf(" Grok wants to run: %s\n Allow this command? [y/N] ", fullCmd)
@ -353,7 +368,7 @@ Only use safe read-only commands from the allowed list.`,
}
// Run with strict cwd
execCmd := exec.Command(cmd.Command, cmd.Args...)
execCmd := exec.Command(cmd.Command, args...)
execCmd.Dir = r.resolveWorkDir()
output, err := execCmd.CombinedOutput()