Files
plan-tools/bin/plan-status
Taylor Eernisse c0409579ac Fix symlink resolution for SCRIPT_DIR in both scripts
Scripts now resolve symlinks before computing SCRIPT_DIR, so
they work correctly when invoked via ~/.local/bin/ symlinks.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-07 14:06:50 -05:00

192 lines
7.0 KiB
Bash
Executable File

#!/usr/bin/env bash
# plan-status — Scan projects for plan files and show pipeline status
# Usage: plan-status [search-root] [options]
set -euo pipefail
# Resolve symlinks to find real script location
SOURCE="${BASH_SOURCE[0]}"
while [[ -L "$SOURCE" ]]; do
DIR="$(cd -P "$(dirname "$SOURCE")" && pwd)"
SOURCE="$(readlink "$SOURCE")"
[[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE"
done
SCRIPT_DIR="$(cd -P "$(dirname "$SOURCE")/.." && pwd)"
source "$SCRIPT_DIR/lib/frontmatter.sh"
SEARCH_ROOT="${HOME}/projects"
JSON_OUTPUT=false
FILTER_STATUS=""
usage() {
cat <<'EOF'
plan-status — Dashboard for plan files across projects
Usage: plan-status [search-root] [options]
Scans for markdown files with plan: true frontmatter and shows
their position in the refinement pipeline.
Pipeline: drafting -> iterating -> splitting -> refining -> ready -> implementing -> completed
Options:
--json Machine-readable JSON output
--status <status> Filter to plans with this status
--root <path> Search root (default: ~/projects)
-h, --help Show this help
EOF
exit 0
}
while [[ $# -gt 0 ]]; do
case "$1" in
--json) JSON_OUTPUT=true; shift ;;
--status) FILTER_STATUS="$2"; shift 2 ;;
--root) SEARCH_ROOT="$2"; shift 2 ;;
-h|--help) usage ;;
-*) echo "Unknown option: $1" >&2; exit 2 ;;
*) SEARCH_ROOT="$1"; shift ;;
esac
done
if [[ ! -d "$SEARCH_ROOT" ]]; then
echo "Error: Search root not found: $SEARCH_ROOT" >&2
exit 1
fi
# Collect plan files
declare -a PLAN_FILES=()
while IFS= read -r -d '' file; do
if is_plan_file "$file"; then
PLAN_FILES+=("$file")
fi
done < <(find "$SEARCH_ROOT" \
-name "*.md" \
-not -path "*/node_modules/*" \
-not -path "*/.git/*" \
-not -path "*/.jj/*" \
-not -path "*/target/*" \
-not -name "*.feedback-*" \
-print0 2>/dev/null)
if [[ ${#PLAN_FILES[@]} -eq 0 ]]; then
if [[ "$JSON_OUTPUT" == "true" ]]; then
echo '{"plans":[],"summary":{"total":0}}'
else
echo "No plan files found under $SEARCH_ROOT"
echo "Initialize a plan: plan-refine <file.md> --init"
fi
exit 0
fi
if [[ "$JSON_OUTPUT" == "true" ]]; then
# JSON output
echo '{"plans":['
first=true
for file in "${PLAN_FILES[@]}"; do
status=$(get_frontmatter "$file" "status" "unknown")
[[ -n "$FILTER_STATUS" && "$status" != "$FILTER_STATUS" ]] && continue
title=$(get_frontmatter "$file" "title" "$(basename "$file" .md)")
iteration=$(get_frontmatter "$file" "iteration" "0")
target=$(get_frontmatter "$file" "target_iterations" "")
beads_rev=$(get_frontmatter "$file" "beads_revision" "0")
updated=$(get_frontmatter "$file" "updated" "")
project=$(echo "$file" | sed "s|${SEARCH_ROOT}/||" | cut -d/ -f1)
# Count feedback files
feedback_count=$(ls "${file%.md}".feedback-*.md 2>/dev/null | wc -l | tr -d ' ')
[[ "$first" != "true" ]] && echo ","
first=false
cat <<ENTRY
{"path":"$file","project":"$project","title":"$title","status":"$status","iteration":$iteration,"target_iterations":${target:-null},"beads_revision":$beads_rev,"feedback_files":$feedback_count,"updated":"$updated"}
ENTRY
done
echo ']}'
else
# Human-readable table
echo ""
echo " Plan Status Dashboard"
echo " $(date '+%Y-%m-%d %H:%M')"
echo " ════════════════════════════════════════════════════════════════════════"
printf " %-18s %-28s %-12s %-14s %s\n" "Project" "Plan" "Status" "Iterations" "Updated"
echo " ────────────────────────────────────────────────────────────────────────"
# Counters
total=0
by_status_drafting=0
by_status_iterating=0
by_status_splitting=0
by_status_refining=0
by_status_ready=0
by_status_implementing=0
by_status_completed=0
for file in "${PLAN_FILES[@]}"; do
status=$(get_frontmatter "$file" "status" "unknown")
[[ -n "$FILTER_STATUS" && "$status" != "$FILTER_STATUS" ]] && continue
title=$(get_frontmatter "$file" "title" "")
iteration=$(get_frontmatter "$file" "iteration" "0")
target=$(get_frontmatter "$file" "target_iterations" "")
beads_rev=$(get_frontmatter "$file" "beads_revision" "0")
updated=$(get_frontmatter "$file" "updated" "")
project=$(echo "$file" | sed "s|${SEARCH_ROOT}/||" | cut -d/ -f1)
plan_name=$(basename "$file" .md)
# Truncate long names
[[ ${#project} -gt 18 ]] && project="${project:0:15}..."
[[ ${#plan_name} -gt 28 ]] && plan_name="${plan_name:0:25}..."
# Format iteration progress
if [[ -n "$target" && "$target" != "0" ]]; then
iter_display="${iteration}/${target}"
else
iter_display="${iteration}"
fi
# Add beads revision if applicable
if [[ "$beads_rev" != "0" ]]; then
iter_display="${iter_display} br:${beads_rev}"
fi
printf " %-18s %-28s %-12s %-14s %s\n" \
"$project" "$plan_name" "$status" "$iter_display" "$updated"
total=$((total + 1))
case "$status" in
drafting) by_status_drafting=$((by_status_drafting + 1)) ;;
iterating) by_status_iterating=$((by_status_iterating + 1)) ;;
splitting) by_status_splitting=$((by_status_splitting + 1)) ;;
refining) by_status_refining=$((by_status_refining + 1)) ;;
ready) by_status_ready=$((by_status_ready + 1)) ;;
implementing) by_status_implementing=$((by_status_implementing + 1)) ;;
completed) by_status_completed=$((by_status_completed + 1)) ;;
esac
done
echo " ════════════════════════════════════════════════════════════════════════"
echo ""
# Summary line
summary_parts=()
[[ $by_status_drafting -gt 0 ]] && summary_parts+=("${by_status_drafting} drafting")
[[ $by_status_iterating -gt 0 ]] && summary_parts+=("${by_status_iterating} iterating")
[[ $by_status_splitting -gt 0 ]] && summary_parts+=("${by_status_splitting} splitting")
[[ $by_status_refining -gt 0 ]] && summary_parts+=("${by_status_refining} refining")
[[ $by_status_ready -gt 0 ]] && summary_parts+=("${by_status_ready} ready")
[[ $by_status_implementing -gt 0 ]] && summary_parts+=("${by_status_implementing} implementing")
[[ $by_status_completed -gt 0 ]] && summary_parts+=("${by_status_completed} completed")
IFS=", "
echo " ${total} plans: ${summary_parts[*]}"
echo ""
# Pipeline visualization
echo " Pipeline: drafting -> iterating -> splitting -> refining -> ready -> implementing -> completed"
echo ""
fi