Generator-evaluator architecture with iterative context-reset for long-running coding tasks. Ships as a Claude Code plugin — install with /plugin and use /agent-loop:init, /agent-loop:plan, /agent-loop:run.
84 lines
3.5 KiB
Bash
84 lines
3.5 KiB
Bash
#!/bin/bash
|
|
# Branch archiving — archives previous run artifacts when the branch changes.
|
|
# Preserves prd.json, progress.md, and contracts from the previous feature.
|
|
#
|
|
# Design: At the end of each run, snapshot_for_archive saves current artifacts
|
|
# to .archive-staging/. On the next run, if the branch changed, check_archive
|
|
# moves the snapshot to archive/ and cleans up. This avoids archiving the
|
|
# WRONG artifacts (the new feature's) when prd.json has already been overwritten.
|
|
|
|
LAST_BRANCH_FILE="$LOOP_DIR/.last-branch"
|
|
STAGING_DIR="$LOOP_DIR/.archive-staging"
|
|
|
|
# Snapshot current artifacts so they can be archived later if the branch changes.
|
|
# Call this at the END of a successful run or before exit.
|
|
snapshot_for_archive() {
|
|
rm -rf "$STAGING_DIR"
|
|
mkdir -p "$STAGING_DIR"
|
|
|
|
[ -f "$LOOP_DIR/prd.json" ] && cp "$LOOP_DIR/prd.json" "$STAGING_DIR/"
|
|
[ -f "$LOOP_DIR/progress.md" ] && cp "$LOOP_DIR/progress.md" "$STAGING_DIR/"
|
|
[ -d "$LOOP_DIR/contracts" ] && cp -r "$LOOP_DIR/contracts" "$STAGING_DIR/"
|
|
}
|
|
|
|
# Check if we need to archive and do so if branch changed.
|
|
# Reads the NEW branch from live prd.json and the OLD branch from the staging
|
|
# snapshot (which was saved at the end of the previous run). This avoids the
|
|
# bug where both branches read from the same (already-overwritten) prd.json.
|
|
check_archive() {
|
|
local current_branch
|
|
current_branch=$(prd_branch_name 2>/dev/null)
|
|
[ -z "$current_branch" ] && return
|
|
|
|
# Determine the previous branch from the staging snapshot (most reliable)
|
|
# or fall back to .last-branch file
|
|
local last_branch=""
|
|
if [ -f "$STAGING_DIR/prd.json" ]; then
|
|
if command -v jq &>/dev/null; then
|
|
last_branch=$(jq -r '.branchName // empty' "$STAGING_DIR/prd.json" 2>/dev/null)
|
|
else
|
|
last_branch=$(LOOP_PRD="$STAGING_DIR/prd.json" python3 -c "
|
|
import json, os
|
|
print(json.load(open(os.environ['LOOP_PRD'])).get('branchName', ''), end='')
|
|
" 2>/dev/null)
|
|
fi
|
|
fi
|
|
[ -z "$last_branch" ] && [ -f "$LAST_BRANCH_FILE" ] && last_branch=$(cat "$LAST_BRANCH_FILE")
|
|
|
|
if [ -n "$last_branch" ] && [ "$last_branch" != "$current_branch" ]; then
|
|
archive_run "$last_branch"
|
|
fi
|
|
|
|
echo "$current_branch" > "$LAST_BRANCH_FILE"
|
|
}
|
|
|
|
# Archive the previous run's staged artifacts (NOT current prd.json)
|
|
archive_run() {
|
|
local branch_name="$1"
|
|
local feature_name
|
|
feature_name=$(echo "$branch_name" | sed 's|.*/||')
|
|
|
|
local archive_dir="$LOOP_DIR/archive/$(date +%Y-%m-%d)-${feature_name}"
|
|
mkdir -p "$archive_dir"
|
|
|
|
if [ -d "$STAGING_DIR" ]; then
|
|
# Use the staged snapshot (correct artifacts from the previous run)
|
|
cp -r "$STAGING_DIR"/* "$archive_dir/" 2>/dev/null || true
|
|
rm -rf "$STAGING_DIR"
|
|
else
|
|
# Fallback: no snapshot exists (first run or upgrade from old version).
|
|
# Current artifacts may belong to the new feature — archive what we have
|
|
# but warn the user.
|
|
log "WARNING: No archive snapshot found. Archiving current artifacts (may be from new feature)."
|
|
[ -f "$LOOP_DIR/prd.json" ] && cp "$LOOP_DIR/prd.json" "$archive_dir/"
|
|
[ -f "$LOOP_DIR/progress.md" ] && cp "$LOOP_DIR/progress.md" "$archive_dir/"
|
|
[ -d "$LOOP_DIR/contracts" ] && cp -r "$LOOP_DIR/contracts" "$archive_dir/"
|
|
fi
|
|
|
|
# Clean up old run's artifacts (progress.md, contracts — NOT prd.json which belongs to new feature)
|
|
rm -f "$LOOP_DIR/progress.md"
|
|
rm -rf "$LOOP_DIR/contracts"
|
|
|
|
log "Archived previous run to $archive_dir"
|
|
}
|