84 lines
3.0 KiB
Bash
Executable File
84 lines
3.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# ArcKit Stale Artifact Scanner
|
|
#
|
|
# One-shot scan wired into the plugin's `monitors` manifest key. Fires at
|
|
# session start (when the plugin is enabled in an ArcKit repo), emits one
|
|
# stdout line per stale artifact, and exits.
|
|
#
|
|
# Stale criteria:
|
|
# 1. Document Control "Next Review Date" is in the past
|
|
# 2. Status is DRAFT and the file hasn't been touched in >30 days
|
|
#
|
|
# Output format is a single notification line per artifact, readable as
|
|
# an additionalContext signal by Claude Code. Silent exit if the cwd is
|
|
# not an ArcKit project (no projects/ directory).
|
|
#
|
|
# Thresholds match the STALE-DRAFT / REVIEW-OVERDUE rules in
|
|
# /arckit:health (graph-inject.mjs formatHealth) so the monitor is a
|
|
# real-time push of the same signal the slash command reports on demand.
|
|
|
|
set -u
|
|
|
|
cwd="$(pwd)"
|
|
if [[ ! -d "$cwd/projects" ]]; then
|
|
exit 0
|
|
fi
|
|
|
|
today="$(date +%Y-%m-%d)"
|
|
stale_count=0
|
|
max_report=10
|
|
|
|
# Resolve a GNU-style date threshold for draft staleness (30 days ago).
|
|
# Falls back silently if `date -d` unsupported.
|
|
draft_threshold=""
|
|
if date -d "30 days ago" +%Y-%m-%d >/dev/null 2>&1; then
|
|
draft_threshold="$(date -d "30 days ago" +%Y-%m-%d)"
|
|
fi
|
|
|
|
# Iterate ARC-*.md files under projects/, ignoring symlinks and node_modules
|
|
while IFS= read -r -d '' file; do
|
|
[[ $stale_count -ge $max_report ]] && break
|
|
|
|
# Pull Document Control table fields. Anchor Status to a row whose label is
|
|
# exactly "Status" (with optional **markdown bold**) so we don't match
|
|
# entity-attribute tables further down the file.
|
|
next_review="$(grep -m1 -i "Next Review Date" "$file" 2>/dev/null \
|
|
| sed -E 's/.*\| *([0-9]{4}-[0-9]{2}-[0-9]{2}).*/\1/')"
|
|
status="$(grep -m1 -iE '^\| *\*{0,2} *Status *\*{0,2} *\|' "$file" 2>/dev/null \
|
|
| grep -oiE '(DRAFT|IN_REVIEW|APPROVED|PUBLISHED|SUPERSEDED|ARCHIVED)' \
|
|
| head -1 \
|
|
| tr '[:lower:]' '[:upper:]')"
|
|
last_modified="$(grep -m1 -i "Last Modified" "$file" 2>/dev/null \
|
|
| sed -E 's/.*\| *([0-9]{4}-[0-9]{2}-[0-9]{2}).*/\1/')"
|
|
|
|
rel="${file#$cwd/}"
|
|
|
|
# Overdue review
|
|
if [[ -n "$next_review" && "$next_review" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ ]]; then
|
|
if [[ "$next_review" < "$today" ]]; then
|
|
echo "[ArcKit monitor] STALE: $rel — review overdue since $next_review"
|
|
stale_count=$((stale_count + 1))
|
|
continue
|
|
fi
|
|
fi
|
|
|
|
# Long-running draft
|
|
if [[ "$status" == "DRAFT" && -n "$draft_threshold" \
|
|
&& -n "$last_modified" && "$last_modified" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ ]]; then
|
|
if [[ "$last_modified" < "$draft_threshold" ]]; then
|
|
echo "[ArcKit monitor] STALE: $rel — DRAFT unchanged since $last_modified"
|
|
stale_count=$((stale_count + 1))
|
|
fi
|
|
fi
|
|
done < <(find "$cwd/projects" -type f -name "ARC-*.md" -not -path "*/node_modules/*" -print0 2>/dev/null)
|
|
|
|
if [[ $stale_count -eq 0 ]]; then
|
|
exit 0
|
|
fi
|
|
|
|
if [[ $stale_count -ge $max_report ]]; then
|
|
echo "[ArcKit monitor] (reporting first $max_report; run /arckit:health for the full list)"
|
|
else
|
|
echo "[ArcKit monitor] Found $stale_count stale artifact(s). Run /arckit:health for details."
|
|
fi
|