refactor(recipe): add ResolvedParams for better param handling

Introduce ResolvedParams field to Recipe struct for storing resolved
parameter values from defaults and user overrides. Update loader to
populate and use it for template rendering. Adjust runner to use
ResolvedParams for root path and generalize file discovery.
This commit is contained in:
Greg Gauthier 2026-03-07 00:07:21 +00:00
parent 1c79abce8d
commit f5c73ab291
3 changed files with 18 additions and 16 deletions

View File

@ -32,26 +32,26 @@ func Load(path string, userParams map[string]any) (*Recipe, error) {
return nil, fmt.Errorf("yaml parse: %w", err)
}
// Apply defaults
// Apply defaults + user --param overrides
if r.Parameters == nil {
r.Parameters = make(map[string]Parameter)
}
params := make(map[string]any)
r.ResolvedParams = make(map[string]any)
for name, p := range r.Parameters {
if v, ok := userParams[name]; ok {
params[name] = v
r.ResolvedParams[name] = v
} else if p.Default != nil {
params[name] = p.Default
r.ResolvedParams[name] = p.Default
}
}
// Render templates (so {{.package_path}} becomes "internal")
// Render templates with resolved values
tpl, err := template.New("recipe").Parse(string(parts[2]))
if err != nil {
return nil, err
}
var rendered bytes.Buffer
if err := tpl.Execute(&rendered, params); err != nil {
if err := tpl.Execute(&rendered, r.ResolvedParams); err != nil {
return nil, err
}
body := rendered.String()

View File

@ -85,15 +85,15 @@ Execute this step now. Respond ONLY with the expected output format — no expla
func (r *Runner) discoverFiles() []string {
var files []string
// Get root from parameter or default
root := "internal"
if p, ok := r.Recipe.Parameters["package_path"]; ok {
if def, ok := p.Default.(string); ok && def != "" {
root = def
// Get root from --param or default
root := "."
if v, ok := r.Recipe.ResolvedParams["package_path"]; ok {
if s, ok := v.(string); ok && s != "" {
root = s
}
}
// Build set of allowed extensions from recipe frontmatter
// Build allowed extensions from recipe frontmatter
allowedExt := make(map[string]bool)
for _, lang := range r.Recipe.ProjectLanguages {
if exts, ok := r.Recipe.Extensions[lang]; ok {
@ -107,10 +107,9 @@ func (r *Runner) discoverFiles() []string {
if err != nil || d.IsDir() {
return nil
}
ext := filepath.Ext(path)
if allowedExt[ext] {
if allowedExt[filepath.Ext(path)] {
b, _ := os.ReadFile(path)
if strings.Contains(string(b), "if err != nil") { // this is still Go-specific for now; we can generalize later
if strings.Contains(string(b), "if err != nil") {
files = append(files, path)
}
}

View File

@ -7,10 +7,13 @@ type Recipe struct {
Parameters map[string]Parameter `yaml:"parameters"`
AllowedShellCommands []string `yaml:"allowed_shell_commands"`
// New fields for generic file discovery (option 2)
// Generic discovery support (option 2)
ProjectLanguages []string `yaml:"project_languages"`
Extensions map[string][]string `yaml:"extensions"`
// Resolved runtime values from --param flags
ResolvedParams map[string]any `yaml:"-"`
// Internal fields populated by loader
Overview string `yaml:"-"`
Steps []Step `yaml:"-"`