cf36780c0f
- AGENT_Context opens with a generated Document Map (section → line ranges) - gen-docs.sh: new gen_docmap block, self-referential (converges to a fixed point so line numbers stay accurate) - new '## 8. Entertainment Module' section (CLI, lib, plugins, config, scheduler, pointers); renumber following sections 8-13 -> 9-14 - AGENTS.md: reference the Document Map; document the make check/gen gate
173 lines
5.6 KiB
Bash
Executable File
173 lines
5.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
set -euo pipefail
|
||
# Regenerate code-derived doc sections between GEN markers.
|
||
#
|
||
# scripts/gen-docs.sh rewrite files in place
|
||
# scripts/gen-docs.sh --check verify only; exit 1 on any drift
|
||
#
|
||
# Sources of truth:
|
||
# - bin/pos-* filenames → category, subcommand
|
||
# - "# POS:" header line → one-line description
|
||
# - "# POS_FLAGS:" line → flag completion list (flag-style tools only)
|
||
|
||
root="$(cd "$(dirname "$0")/.." && pwd)"
|
||
mode="write"
|
||
[ "${1:-}" = "--check" ] && mode="check"
|
||
|
||
ctx="$root/DOC/AGENT_Context_Project.md"
|
||
comp="$root/completions/pos.bash"
|
||
|
||
# ── Collect tools: "cat|sub|desc|flags" ────────────────────────
|
||
tools=()
|
||
for f in "$root"/bin/pos-*; do
|
||
[ -x "$f" ] || continue
|
||
name="${f##*/pos-}"
|
||
cat="${name%%-*}"
|
||
sub="${name#*-}"
|
||
desc="$(sed -n '/^# POS: /{s/^# POS: //;p;q}' "$f")"
|
||
[ -n "$desc" ] || { echo "gen-docs: no '# POS:' header in $f" >&2; exit 1; }
|
||
desc="${desc#*— }"
|
||
flags="$(sed -n '/^# POS_FLAGS: /{s/^# POS_FLAGS: //;p;q}' "$f")"
|
||
tools+=("$cat|$sub|$desc|$flags")
|
||
done
|
||
mapfile -t tools < <(printf '%s\n' "${tools[@]}" | sort)
|
||
|
||
# ── Block generators (emit inner content only, no markers) ──────
|
||
gen_tree() {
|
||
local width=0 cat sub desc flags name t
|
||
for t in "${tools[@]}"; do
|
||
IFS='|' read -r cat sub desc flags <<<"$t"
|
||
name="pos-$cat-$sub"
|
||
[ ${#name} -gt "$width" ] && width=${#name}
|
||
done
|
||
for t in "${tools[@]}"; do
|
||
IFS='|' read -r cat sub desc flags <<<"$t"
|
||
name="pos-$cat-$sub"
|
||
printf '│ ├── %-*s# %s\n' "$((width + 1))" "$name" "$desc"
|
||
done
|
||
}
|
||
|
||
gen_dispatch() {
|
||
local cat sub desc flags t
|
||
for t in "${tools[@]}"; do
|
||
IFS='|' read -r cat sub desc flags <<<"$t"
|
||
printf '| %s | %s | `pos-%s-%s` | %s |\n' "$cat" "$sub" "$cat" "$sub" "$desc"
|
||
done
|
||
}
|
||
|
||
gen_selfcontained() {
|
||
local list=() f base out=""
|
||
for f in "$root"/bin/pos "$root"/bin/pos-*; do
|
||
[ -x "$f" ] || continue
|
||
base="$(basename "$f")"
|
||
grep -q 'common\.sh' "$f" || list+=("$base")
|
||
done
|
||
for b in "${list[@]}"; do
|
||
out+="\`$b\`, "
|
||
done
|
||
echo "${out%, }."
|
||
}
|
||
|
||
gen_filetable() {
|
||
local cat sub desc flags name t
|
||
printf '| `bin/pos` | %s | CLI dispatcher with smart arg matching + logging + category help |\n' "$(wc -l < "$root/bin/pos")"
|
||
for t in "${tools[@]}"; do
|
||
IFS='|' read -r cat sub desc flags <<<"$t"
|
||
name="bin/pos-$cat-$sub"
|
||
printf '| `%s` | %s | %s |\n' "$name" "$(wc -l < "$root/$name")" "$desc"
|
||
done
|
||
printf '| `completions/pos.bash` | %s | Dynamic bash completion |\n' "$(wc -l < "$comp")"
|
||
}
|
||
|
||
gen_posflags() {
|
||
local cat sub desc flags t
|
||
echo "declare -A _pos_flags"
|
||
for t in "${tools[@]}"; do
|
||
IFS='|' read -r cat sub desc flags <<<"$t"
|
||
[ -n "$flags" ] || continue
|
||
printf '_pos_flags[%s-%s]="%s"\n' "$cat" "$sub" "$flags"
|
||
done
|
||
}
|
||
|
||
# Section index of AGENT_Context itself: maps each "## " heading to its
|
||
# line range. Excludes the "Document Map" heading (this block).
|
||
gen_docmap() {
|
||
local file="$ctx" lines=() sections=() line n title i last
|
||
mapfile -t lines < <(grep -nE '^## ' "$file")
|
||
for line in "${lines[@]}"; do
|
||
title="${line#*:}"
|
||
[[ "$title" == "## Document Map" ]] && continue
|
||
sections+=("$line")
|
||
done
|
||
for i in "${!sections[@]}"; do
|
||
n="${sections[$i]%%:*}"
|
||
title="${sections[$i]#*:}"
|
||
if [ "$i" -eq $((${#sections[@]} - 1)) ]; then
|
||
last=$(wc -l < "$file")
|
||
else
|
||
last=$(( ${sections[$((i + 1))]%%:*} - 1 ))
|
||
fi
|
||
printf '| %s | %s–%s |\n' "$title" "$n" "$last"
|
||
done
|
||
}
|
||
|
||
# ── Replace (write) or verify (check) one marker block ──────────
|
||
regen_block() {
|
||
local file="$1" name="$2"
|
||
local start end newfile tmp
|
||
case "$file" in
|
||
*.bash|*.sh) start="# GEN:START $name"; end="# GEN:END $name" ;;
|
||
*) start="<!-- GEN:START $name -->"; end="<!-- GEN:END $name -->" ;;
|
||
esac
|
||
newfile="$(mktemp)"
|
||
"gen_$name" > "$newfile"
|
||
|
||
grep -qF "$start" "$file" || { echo "gen-docs: missing marker '$start' in $file" >&2; rm -f "$newfile"; exit 1; }
|
||
|
||
if [ "$mode" = "check" ]; then
|
||
local cur
|
||
cur="$(sed -n "/^$start$/,/^$end$/p" "$file" | sed '1d;$d')"
|
||
if [ "$cur" != "$(cat "$newfile")" ]; then
|
||
echo "gen-docs: DRIFT in $file ($name block)" >&2
|
||
diff <(printf '%s\n' "$cur") <(cat "$newfile") >&2 || true
|
||
rm -f "$newfile"
|
||
exit 1
|
||
fi
|
||
else
|
||
tmp="$(mktemp)"
|
||
awk -v start="$start" -v end="$end" -v nf="$newfile" '
|
||
$0==start {
|
||
print
|
||
while ((getline line < nf) > 0) print line
|
||
skip=1
|
||
next
|
||
}
|
||
skip && $0==end { skip=0; print; next }
|
||
skip { next }
|
||
{ print }
|
||
' "$file" > "$tmp"
|
||
mv "$tmp" "$file"
|
||
fi
|
||
rm -f "$newfile"
|
||
}
|
||
|
||
regen_block "$ctx" tree
|
||
regen_block "$ctx" dispatch
|
||
regen_block "$ctx" selfcontained
|
||
regen_block "$comp" posflags
|
||
regen_block "$ctx" filetable
|
||
|
||
# docmap is self-referential: its own block size shifts the section line
|
||
# numbers below it — regenerate until stable (converges in 2-3 passes).
|
||
regen_block "$ctx" docmap
|
||
if [ "$mode" = "write" ]; then
|
||
for _ in 1 2 3 4 5; do
|
||
prev="$(sed -n '/<!-- GEN:START docmap -->/,/<!-- GEN:END docmap -->/p' "$ctx")"
|
||
regen_block "$ctx" docmap
|
||
after="$(sed -n '/<!-- GEN:START docmap -->/,/<!-- GEN:END docmap -->/p' "$ctx")"
|
||
[ "$prev" = "$after" ] && break
|
||
done
|
||
fi
|
||
|
||
echo "gen-docs: $mode OK"
|