Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 41 additions & 2 deletions internal/cmd/formula.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
formulaRunDryRun bool
formulaRunAgent string
formulaRunFiles []string
formulaRunSet []string
formulaCreateType string
)

Expand Down Expand Up @@ -171,6 +172,7 @@
formulaRunCmd.Flags().BoolVar(&formulaRunDryRun, "dry-run", false, "Preview execution without running")
formulaRunCmd.Flags().StringVar(&formulaRunAgent, "agent", "", "Override agent/runtime for all legs (e.g., gemini, codex, claude-haiku)")
formulaRunCmd.Flags().StringSliceVar(&formulaRunFiles, "files", nil, "Files to pass to formula legs (available as {{.files}} in templates)")
formulaRunCmd.Flags().StringSliceVar(&formulaRunSet, "set", nil, "Set input variables as key=value pairs (available as {{.key}} in templates)")

// Create flags
formulaCreateCmd.Flags().StringVar(&formulaCreateType, "type", "task", "Formula type: task, workflow, or patrol")
Expand Down Expand Up @@ -313,10 +315,22 @@
fmt.Printf(" Agent: %s\n", effectiveAgent)
}

// Show --set variables if provided
if len(formulaRunSet) > 0 {
fmt.Printf(" Set:")
for _, s := range formulaRunSet {
fmt.Printf(" %s", s)
}
fmt.Println()
}

if f.Type == formula.TypeConvoy && len(f.Legs) > 0 {
// Generate review ID for dry-run display
reviewID := generateFormulaShortID()

// Parse --set key=value pairs for template rendering
setVars := parseSetVars(formulaRunSet)

// Build target description
var targetDescription string
if formulaRunPR > 0 {
Expand Down Expand Up @@ -345,6 +359,9 @@
"review_id": reviewID,
"formula_name": formulaName,
}
for k, v := range setVars {
dirCtx[k] = v
}
outputDir = renderTemplateOrDefault(f.Output.Directory, dirCtx, ".reviews/"+reviewID)
fmt.Printf("\n Output directory: %s\n", outputDir)
}
Expand All @@ -368,6 +385,9 @@
"changed_files": changedFiles,
"files": formulaRunFiles,
}
for k, v := range setVars {
legCtx[k] = v
}
legPattern := renderTemplateOrDefault(f.Output.LegPattern, legCtx, leg.ID+"-findings.md")
outputPath := filepath.Join(outputDir, legPattern)
agentSuffix := resolveFormulaLegAgent(leg.Agent, formulaRunAgent, f.Agent)
Expand Down Expand Up @@ -402,7 +422,7 @@
fmt.Printf("%s Executing convoy formula: %s\n\n",
style.Bold.Render("🚚"), formulaName)

// Get town beads directory for convoy creation
// Get town root and resolve rig-scoped bead prefix
townRoot, err := workspace.FindFromCwd()
if err != nil {
return fmt.Errorf("finding town root: %w", err)
Expand All @@ -427,7 +447,7 @@
}

// Step 1: Create convoy bead
convoyID := fmt.Sprintf("hq-cv-%s", generateFormulaShortID())
convoyID := fmt.Sprintf("%s-cv-%s", beadPrefix, generateFormulaShortID())

Check failure on line 450 in internal/cmd/formula.go

View workflow job for this annotation

GitHub Actions / Lint

undefined: beadPrefix (typecheck)

Check failure on line 450 in internal/cmd/formula.go

View workflow job for this annotation

GitHub Actions / Test

undefined: beadPrefix

Check failure on line 450 in internal/cmd/formula.go

View workflow job for this annotation

GitHub Actions / Integration Tests

undefined: beadPrefix

Check failure on line 450 in internal/cmd/formula.go

View workflow job for this annotation

GitHub Actions / Windows Build and Unit Tests

undefined: beadPrefix
convoyTitle := fmt.Sprintf("%s: %s", formulaName, f.Description)
if len(convoyTitle) > 80 {
convoyTitle = convoyTitle[:77] + "..."
Expand Down Expand Up @@ -502,6 +522,9 @@
}
}

// Parse --set key=value pairs for template rendering
setVars := parseSetVars(formulaRunSet)

// Step 2: Create leg beads and track them
legBeads := make(map[string]string) // leg.ID -> bead ID
for _, leg := range f.Legs {
Expand All @@ -528,6 +551,11 @@
"files": formulaRunFiles,
}

// Inject --set key=value pairs into template context
for k, v := range setVars {
legCtx[k] = v
}

// Compute output path for this leg
if f.Output != nil {
legPattern := renderTemplateOrDefault(f.Output.LegPattern, legCtx, leg.ID+"-findings.md")
Expand Down Expand Up @@ -691,6 +719,17 @@
return nil
}

// parseSetVars parses --set key=value pairs into a map for template rendering.
func parseSetVars(setArgs []string) map[string]interface{} {
vars := make(map[string]interface{})
for _, arg := range setArgs {
if idx := strings.IndexByte(arg, '='); idx > 0 {
vars[arg[:idx]] = arg[idx+1:]
}
}
return vars
}

// findFormulaFile searches for a formula file by name
func findFormulaFile(name string) (string, error) {
// Search paths in order
Expand Down
Loading