#!/usr/bin/env bash # frontmatter.sh — Read/write YAML frontmatter in plan files # Read a value from YAML frontmatter # Usage: get_frontmatter [default] get_frontmatter() { local file="$1" local key="$2" local default="${3:-}" if ! head -1 "$file" | grep -q '^---$'; then echo "$default" return fi local value value=$(awk '/^---$/{n++; next} n==1{print}' "$file" \ | grep "^${key}:" \ | head -1 \ | sed "s/^${key}: *//; s/^ *//; s/ *$//; s/^[\"']//; s/[\"']$//") echo "${value:-$default}" } # Set a value in YAML frontmatter (adds frontmatter if missing) # Usage: set_frontmatter set_frontmatter() { local file="$1" local key="$2" local value="$3" # If file has no frontmatter, add it if ! head -1 "$file" | grep -q '^---$'; then local tmp tmp=$(mktemp) { echo "---" echo "${key}: ${value}" echo "---" cat "$file" } > "$tmp" mv "$tmp" "$file" return fi if grep -q "^${key}:" "$file"; then # Replace existing key (using | as delimiter to avoid path issues) sed -i '' "s|^${key}:.*|${key}: ${value}|" "$file" else # Insert before closing --- (second occurrence) awk -v key="$key" -v val="$value" ' BEGIN { count=0; inserted=0 } /^---$/ { count++ } count == 2 && !inserted { print key ": " val; inserted=1 } { print } ' "$file" > "${file}.tmp" && mv "${file}.tmp" "$file" fi } # Check if a file has plan frontmatter # Usage: is_plan_file is_plan_file() { local file="$1" [[ -f "$file" ]] && head -20 "$file" | grep -q "^plan: true" } # Initialize frontmatter on a plan file that doesn't have it # Usage: init_frontmatter [title] init_frontmatter() { local file="$1" local title="${2:-$(basename "$file" .md)}" local today today=$(date +%Y-%m-%d) if head -1 "$file" | grep -q '^---$'; then # Has frontmatter, just ensure plan fields exist set_frontmatter "$file" "plan" "true" [[ -z "$(get_frontmatter "$file" "status")" ]] && set_frontmatter "$file" "status" "drafting" [[ -z "$(get_frontmatter "$file" "iteration")" ]] && set_frontmatter "$file" "iteration" "0" [[ -z "$(get_frontmatter "$file" "target_iterations")" ]] && set_frontmatter "$file" "target_iterations" "8" [[ -z "$(get_frontmatter "$file" "created")" ]] && set_frontmatter "$file" "created" "$today" set_frontmatter "$file" "updated" "$today" else # No frontmatter, add full block local tmp tmp=$(mktemp) { echo "---" echo "plan: true" echo "title: \"${title}\"" echo "status: drafting" echo "iteration: 0" echo "target_iterations: 8" echo "beads_revision: 0" echo "related_plans: []" echo "created: ${today}" echo "updated: ${today}" echo "---" echo "" cat "$file" } > "$tmp" mv "$tmp" "$file" fi }