feat: phases + tasks — per-task execution with phase directories
- A phase is now a directory: 00_phase.md (overview + task index) plus small, quick NN_task.md task files; complete/ mirrors todo/ - Task is the unit of execution: run-task.sh (one unit), run-phase.sh (phase to completion incl. 00_phase.md final pass), auto-phase.sh (all units in order); validate.sh gate runs after every task - PHASE_COMMIT commits at phase boundaries (00_phase.md / legacy file moves) - Legacy flat todo/NN_name.md files still execute as a single unit; new migrate-phases-to-tasks.sh converts them to the directory layout - phase-status.sh reports per-task state and the next unit - New task-template.md; phase templates now carry a Tasks index
This commit is contained in:
@@ -1,9 +1,13 @@
|
||||
#!/usr/bin/env bash
|
||||
# phase-status.sh — phase pipeline state for the Phase Architect.
|
||||
# phase-status.sh — phase/task pipeline state for the Phase Architect.
|
||||
#
|
||||
# Finds the project root (nearest ancestor with .agent/phases/todo), prints
|
||||
# the todo/ and complete/ phase listings, and computes the next free phase
|
||||
# number NN (counting both directories together, zero-padded to 2 digits).
|
||||
# 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
|
||||
|
||||
@@ -16,31 +20,107 @@ while :; do
|
||||
root="$(dirname "$root")"
|
||||
done
|
||||
|
||||
list() {
|
||||
local d="$root/.agent/phases/$1" f found=0
|
||||
for f in "$d"/*.md; do
|
||||
[[ -e "$f" ]] || continue
|
||||
found=1
|
||||
printf ' %s\n' "$(basename "$f")"
|
||||
done
|
||||
if (( ! found )); then printf ' (empty)\n'; fi
|
||||
}
|
||||
phases="$root/.agent/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 f in "$root/.agent/phases/$d"/*.md; do
|
||||
[[ -e "$f" ]] || continue
|
||||
n="$(basename "$f" .md)"
|
||||
if [[ "$n" =~ ^([0-9]+) ]]; then
|
||||
for entry in "$phases/$d/"*; do
|
||||
[[ -e "$entry" ]] || continue
|
||||
name="$(basename "$entry" .md)"
|
||||
if [[ "$name" =~ ^([0-9]+) ]]; then
|
||||
n=$((10#${BASH_REMATCH[1]}))
|
||||
if (( n > max )); then max=$n; fi
|
||||
(( n > max )) && max=$n
|
||||
fi
|
||||
done
|
||||
done
|
||||
echo "next phase number: $(printf '%02d' $((max + 1)))"
|
||||
|
||||
echo "project root: $root"
|
||||
echo "todo:"
|
||||
list todo
|
||||
echo "complete:"
|
||||
list complete
|
||||
echo "next 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)}"
|
||||
|
||||
Reference in New Issue
Block a user