diff --git a/pkg/cli/workflows.go b/pkg/cli/workflows.go index e4a597cf27..cf5300e70e 100644 --- a/pkg/cli/workflows.go +++ b/pkg/cli/workflows.go @@ -362,17 +362,66 @@ func fastParseTitle(content string) (string, error) { return "", nil } +// fastParseTitleFromReader scans lines from r for the first H1 header, skipping +// an optional frontmatter block, without reading the entire file into memory. +// This is more efficient than fastParseTitle for file-based callers because it +// stops reading as soon as the title is found. +// +// Frontmatter is recognised only when "---" appears on the very first line. +// Returns the H1 title text, or ("", nil) when no H1 header is present. +// Returns an error if frontmatter is opened but never closed. +func fastParseTitleFromReader(r io.Reader) (string, error) { + scanner := bufio.NewScanner(r) + // Increase the max token size beyond the default 64 KB to handle files with + // large frontmatter values or long base64-encoded lines. + scanner.Buffer(make([]byte, 64*1024), 1024*1024) + firstLine := true + inFrontmatter := false + for scanner.Scan() { + trimmed := strings.TrimSpace(scanner.Text()) + if firstLine { + firstLine = false + if trimmed == "---" { + inFrontmatter = true + continue + } + } else if inFrontmatter { + if trimmed == "---" { + inFrontmatter = false + } + continue + } + if strings.HasPrefix(trimmed, "# ") { + return strings.TrimSpace(trimmed[2:]), nil + } + } + if err := scanner.Err(); err != nil { + return "", err + } + + // Unclosed frontmatter is an error (consistent with ExtractFrontmatterFromContent). + if inFrontmatter { + return "", errors.New("frontmatter not properly closed") + } + + return "", nil +} + // extractWorkflowNameFromFile extracts the workflow name from a file's H1 header func extractWorkflowNameFromFile(filePath string) (string, error) { - content, err := os.ReadFile(filePath) + fd, err := os.Open(filePath) if err != nil { return "", err } - title, err := fastParseTitle(string(content)) + title, err := fastParseTitleFromReader(fd) + closeErr := fd.Close() if err != nil { return "", err } + if closeErr != nil { + return "", fmt.Errorf("failed to close workflow file %s: %w", filePath, closeErr) + } if title != "" { return title, nil }