Files
skills/phase-authoring/scripts/phase-status.sh
T
ducoterra e505df62e8 refactor(skills): use .agents/ instead of .agent/ for phased execution
Standardize on the .agents/ directory across all phased-execution
skills (phase state, reports, sessions, validate.sh, PLAN.md, and
per-story/feature/workflow trees). Legacy dot-less agent/ fallbacks
in migration scripts are untouched.
2026-09-05 10:52:37 -04:00

127 lines
4.3 KiB
Bash
Executable File

#!/usr/bin/env bash
# phase-status.sh — phase/task pipeline state for the Phase Architect.
#
# Finds the project root (nearest ancestor with .agents/phases/todo), prints
# the todo/ and complete/ phase listings with per-task state, the next free
# phase number NN (counting both directories together, zero-padded to 2
# digits), and the next pending unit in pipeline order.
#
# Phase layout: todo/NN_name/ holds 00_phase.md (overview) + NN_task.md task
# files; a legacy flat todo/NN_name.md is a single-unit phase.
#
# Usage: bash phase-status.sh # from anywhere in the project tree
set -euo pipefail
root="$(pwd)"
while :; do
if [[ -d "$root/.agents/phases/todo" ]]; then break; fi
[[ "$root" == "/" ]] && { echo "✗ ERROR: no .agents/phases/todo found at or above $(pwd)" >&2; exit 1; }
root="$(dirname "$root")"
done
phases="$root/.agents/phases"
# --- todo: per-task state ------------------------------------------------------
echo "todo:"
found=0
for entry in "$phases/todo/"*; do
[[ -e "$entry" ]] || continue
name="$(basename "$entry")"
[[ "$name" =~ ^[0-9] ]] || continue
found=1
if [[ -d "$entry" ]]; then
# union of this phase's files across todo/ and complete/ (completed units
# move to complete/, so pending = present in todo/, done = in complete/)
comp_dir="$phases/complete/$name"
comp_files=""
if [[ -d "$comp_dir" ]]; then comp_files="$(ls -1 "$comp_dir" 2>/dev/null || true)"; fi
names="$( { ls -1 "$entry" 2>/dev/null || true; printf '%s\n' "$comp_files"; } | grep -E '\.md$' | sort -u || true)"
total=0 done_n=0
while IFS= read -r t; do
[[ -n "$t" ]] || continue
total=$((total + 1))
[[ -f "$phases/complete/$name/$t" ]] && done_n=$((done_n + 1))
done <<< "$names"
printf ' %s/ (%s of %s done)\n' "$name" "$done_n" "$total"
# tasks first (sorted), then 00_phase.md as the final pass
while IFS= read -r t; do
[[ -n "$t" ]] || continue
[[ "$t" == 00_phase.md ]] && continue
if [[ -f "$phases/complete/$name/$t" ]]; then
printf ' [x] %s\n' "$t"
else
printf ' [ ] %s\n' "$t"
fi
done <<< "$names"
if grep -qxF '00_phase.md' <<< "$names"; then
if [[ -f "$phases/complete/$name/00_phase.md" ]]; then
printf ' [x] 00_phase.md (final pass)\n'
else
printf ' [ ] 00_phase.md (final pass)\n'
fi
fi
else
printf ' %s (legacy single-file phase)\n' "$name"
fi
done
(( found )) || echo " (empty)"
# --- complete -------------------------------------------------------------------
echo "complete:"
found=0
for entry in "$phases/complete/"*; do
[[ -e "$entry" ]] || continue
name="$(basename "$entry")"
[[ "$name" =~ ^[0-9] ]] || continue
found=1
if [[ -d "$entry" ]]; then
n=0
for f in "$entry"/*.md; do [[ -e "$f" ]] && n=$((n + 1)); done
printf ' %s/ (%s files)\n' "$name" "$n"
else
printf ' %s (legacy single-file phase)\n' "$name"
fi
done
(( found )) || echo " (empty)"
# --- next free phase number -----------------------------------------------------
max=0
for d in todo complete; do
for entry in "$phases/$d/"*; do
[[ -e "$entry" ]] || continue
name="$(basename "$entry" .md)"
if [[ "$name" =~ ^([0-9]+) ]]; then
n=$((10#${BASH_REMATCH[1]}))
(( n > max )) && max=$n
fi
done
done
echo "next phase number: $(printf '%02d' $((max + 1)))"
# --- next pending unit -----------------------------------------------------------
next=""
for entry in "$phases/todo/"*; do
[[ -e "$entry" ]] || continue
name="$(basename "$entry")"
[[ "$name" =~ ^[0-9] ]] || continue
if [[ -d "$entry" ]]; then
# first task present in todo/ and not yet in complete/ (mirrors the harness)
t=""
while IFS= read -r f; do
[[ -n "$f" ]] || continue
[[ "$f" =~ ^[0-9] && "$f" == *.md ]] || continue
[[ "$f" == 00_phase.md ]] && continue
[[ -f "$phases/complete/$name/$f" ]] && continue
t="$f"; break
done < <(ls -1 "$entry" 2>/dev/null || true)
if [[ -n "$t" ]]; then next="$name/$t"; break; fi
if [[ -f "$entry/00_phase.md" && ! -f "$phases/complete/$name/00_phase.md" ]]; then
next="$name/00_phase.md"; break
fi
elif [[ -f "$entry" ]]; then
next="$name"; break
fi
done
echo "next unit: ${next:-(none — pipeline complete)}"