Files
plan-tools/lib/frontmatter.sh
Taylor Eernisse defb1fb08e Initial plan-tools: plan-refine and plan-status
Semi-automated plan refinement pipeline using Oracle for ChatGPT
browser automation. Includes frontmatter-based tracking and a
dashboard scanner for plan status across projects.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-07 13:03:28 -05:00

104 lines
3.1 KiB
Bash

#!/usr/bin/env bash
# frontmatter.sh — Read/write YAML frontmatter in plan files
# Read a value from YAML frontmatter
# Usage: get_frontmatter <file> <key> [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 <file> <key> <value>
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 <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 <file> [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
}