ResolveWorkflowName converts an agentic workflow ID to the GitHub Actions workflow name. It normalizes the input by removing .md and .lock.yml extensions, then finds the corresponding workflow files and extracts the actual workflow name from the lock.yml file. The agentic workflow ID is the basenam
(workflowInput string)
| 28 | // - "weekly-research.md" -> "Weekly Research" (from weekly-research.lock.yml name field) |
| 29 | // - "weekly-research.lock.yml" -> "Weekly Research" (from weekly-research.lock.yml name field) |
| 30 | func ResolveWorkflowName(workflowInput string) (string, error) { |
| 31 | if workflowInput == "" { |
| 32 | return "", nil |
| 33 | } |
| 34 | |
| 35 | resolveLog.Printf("Resolving workflow name for input: %s", workflowInput) |
| 36 | |
| 37 | // Normalize the workflow name by removing extensions |
| 38 | normalizedName := stringutil.NormalizeWorkflowName(workflowInput) |
| 39 | resolveLog.Printf("Normalized workflow name: %s", normalizedName) |
| 40 | |
| 41 | // Get the workflows directory |
| 42 | workflowsDir := constants.GetWorkflowDir() |
| 43 | |
| 44 | // Check if the agentic workflow markdown file exists |
| 45 | mdFile := filepath.Join(workflowsDir, normalizedName+".md") |
| 46 | if _, err := os.Stat(mdFile); err != nil { |
| 47 | resolveLog.Printf("Markdown file not found: %s", mdFile) |
| 48 | suggestions := []string{ |
| 49 | fmt.Sprintf("Run '%s status' to see all available workflows", constants.CLIExtensionPrefix), |
| 50 | fmt.Sprintf("Create a new workflow with '%s new %s'", constants.CLIExtensionPrefix, normalizedName), |
| 51 | "Check for typos in the workflow name", |
| 52 | } |
| 53 | return "", errors.New(console.FormatErrorWithSuggestions( |
| 54 | fmt.Sprintf("agentic workflow '%s' not found (expected file: %s)", normalizedName, mdFile), |
| 55 | suggestions, |
| 56 | )) |
| 57 | } |
| 58 | |
| 59 | // The corresponding lock file name is what GitHub Actions uses as the workflow name |
| 60 | lockFileName := normalizedName + ".lock.yml" |
| 61 | lockFile := filepath.Join(workflowsDir, lockFileName) |
| 62 | |
| 63 | // Check if the lock file exists (should be generated by compile) |
| 64 | if _, err := os.Stat(lockFile); err != nil { |
| 65 | suggestions := []string{ |
| 66 | fmt.Sprintf("Run '%s compile' to compile the workflow", constants.CLIExtensionPrefix), |
| 67 | fmt.Sprintf("Run '%s compile %s' to compile this specific workflow", constants.CLIExtensionPrefix, normalizedName), |
| 68 | } |
| 69 | return "", errors.New(console.FormatErrorWithSuggestions( |
| 70 | fmt.Sprintf("compiled workflow '%s' not found (expected file: %s)", normalizedName, lockFile), |
| 71 | suggestions, |
| 72 | )) |
| 73 | } |
| 74 | |
| 75 | // Read and parse the lock file to extract the workflow name |
| 76 | content, err := os.ReadFile(lockFile) |
| 77 | if err != nil { |
| 78 | return "", fmt.Errorf("failed to read lock file '%s': %w", lockFile, err) |
| 79 | } |
| 80 | |
| 81 | // Parse YAML to extract the name field |
| 82 | var workflow struct { |
| 83 | Name string `yaml:"name"` |
| 84 | } |
| 85 | |
| 86 | if err := yaml.Unmarshal(content, &workflow); err != nil { |
| 87 | return "", fmt.Errorf("failed to parse YAML from lock file '%s': %w", lockFile, err) |