#!/usr/bin/env bash # Generate a review package: commit list, stat summary, and the net # diff with extended context, written to a file the reviewer reads in one # call. Using the recorded per-task BASE (not HEAD~1) keeps multi-commit # tasks intact. # # Usage: review-package [--role task-review|fix-review|final-review] PLAN_FILE BASE HEAD [OUTFILE] # Default OUTFILE: /.superpowers/sdd//review-...diff # (named per range, so a fix review after fixes gets a distinct fresh file). # # The trailing dispatch hint rides this output because the controller reads it # immediately before spawning the reviewer; skill text loaded at session start # does not survive context compaction, but this line is reprinted every round. set -euo pipefail script_dir=$(cd "$(dirname "$0")" && pwd) role=task-review if [ "${1:-}" = "--role" ]; then [ $# -ge 2 ] || { echo "usage: review-package [--role task-review|fix-review|final-review] PLAN_FILE BASE HEAD [OUTFILE]" >&2; exit 2; } role=$2 shift 2 fi case "$role" in task-review|fix-review|final-review) hint_key=$role ;; *) echo "bad --role: ${role} (task-review|fix-review|final-review)" >&2; exit 2 ;; esac if [ $# -lt 3 ] || [ $# -gt 4 ]; then echo "usage: review-package [--role task-review|fix-review|final-review] PLAN_FILE BASE HEAD [OUTFILE]" >&2 exit 2 fi plan=$1 base=$2 head=$3 [ -f "$plan" ] || { echo "no such plan file: $plan" >&2; exit 2; } git rev-parse --verify --quiet "$base" >/dev/null || { echo "bad BASE: $base" >&2; exit 2; } git rev-parse --verify --quiet "$head" >/dev/null || { echo "bad HEAD: $head" >&2; exit 2; } if [ $# -eq 4 ]; then out=$4 else dir=$("$script_dir/sdd-workspace" "$plan") out="$dir/review-$(git rev-parse --short "$base")..$(git rev-parse --short "$head").diff" fi { echo "# Review package: ${base}..${head}" echo echo "## Commits" git log --oneline "${base}..${head}" echo echo "## Files changed" git diff --stat "${base}..${head}" echo echo "## Diff" git diff -U10 "${base}..${head}" } > "$out" commits=$(git rev-list --count "${base}..${head}") echo "wrote ${out}: ${commits} commit(s), $(wc -c < "$out" | tr -d ' ') bytes" # Platform dispatch hints ride this output because the controller reads it # immediately before spawning; the lines themselves are owned by the platform # reference layer (using-superpowers/references/*-dispatch.hints), not this # script. Claude Code's dispatch templates carry model selection already, so # the relay is suppressed there and on any harness without a hints file. hints_file="$script_dir/../../using-superpowers/references/codex-dispatch.hints" if [ -z "${CLAUDECODE:-}" ] && [ -f "$hints_file" ]; then hint_line=$(grep "^${hint_key}:" "$hints_file" | head -1 | cut -d: -f2- | sed 's/^ *//') || true if [ -n "$hint_line" ]; then echo "$hint_line" fi fi