#!/usr/bin/env bash # plan-refine — Fully automated plan iteration: ChatGPT review + Claude integration # Usage: plan-refine [options] # # Connects to your running Brave browser via CDP, sends the plan to ChatGPT, # captures the response, then runs Claude CLI to integrate the feedback. # Zero copy/paste required. set -euo pipefail # Resolve symlinks to find real script location SOURCE="${BASH_SOURCE[0]}" while [[ -L "$SOURCE" ]]; do DIR="$(cd -P "$(dirname "$SOURCE")" && pwd)" SOURCE="$(readlink "$SOURCE")" [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" done SCRIPT_DIR="$(cd -P "$(dirname "$SOURCE")/.." && pwd)" PROMPTS_DIR="$SCRIPT_DIR/prompts" LIB_DIR="$SCRIPT_DIR/lib" source "$SCRIPT_DIR/lib/frontmatter.sh" # Defaults CLAUDE_MODEL="" DRY_RUN=false NO_INTEGRATE=false PLAN_FILE="" INIT_ONLY=false CDP_PORT="${CHATGPT_CDP_PORT:-9222}" CHATGPT_TIMEOUT=600 usage() { cat <<'EOF' plan-refine — Fully automated plan iteration via Brave + Claude CLI Usage: plan-refine [options] Runs the full cycle automatically: 1. Sends plan to ChatGPT via your running Brave browser (CDP) 2. Captures ChatGPT's response 3. Claude CLI integrates feedback back into the plan file Requires: Brave running with --remote-debugging-port=9222 Relaunch: open -a "Brave Browser" --args --remote-debugging-port=9222 Options: --dry-run Preview what would happen --no-integrate Get ChatGPT feedback only, skip Claude integration --claude-model Claude model for integration (default: your default) --timeout ChatGPT response timeout (default: 600) --cdp-port Brave CDP port (default: 9222, or CHATGPT_CDP_PORT env) --init Add plan frontmatter to file without running anything -h, --help Show this help EOF exit 0 } while [[ $# -gt 0 ]]; do case "$1" in --dry-run) DRY_RUN=true; shift ;; --no-integrate) NO_INTEGRATE=true; shift ;; --claude-model) CLAUDE_MODEL="$2"; shift 2 ;; --timeout) CHATGPT_TIMEOUT="$2"; shift 2 ;; --cdp-port) CDP_PORT="$2"; shift 2 ;; --init) INIT_ONLY=true; shift ;; -h|--help) usage ;; -*) echo "Unknown option: $1" >&2; exit 2 ;; *) PLAN_FILE="$1"; shift ;; esac done if [[ -z "$PLAN_FILE" ]]; then echo "Error: No plan file specified" >&2 echo "Usage: plan-refine " >&2 exit 2 fi # Resolve to absolute path PLAN_FILE="$(cd "$(dirname "$PLAN_FILE")" && pwd)/$(basename "$PLAN_FILE")" if [[ ! -f "$PLAN_FILE" ]]; then echo "Error: Plan file not found: $PLAN_FILE" >&2 exit 1 fi # Ensure frontmatter exists if ! head -1 "$PLAN_FILE" | grep -q '^---$'; then echo "No frontmatter found. Initializing..." init_frontmatter "$PLAN_FILE" fi if ! is_plan_file "$PLAN_FILE"; then set_frontmatter "$PLAN_FILE" "plan" "true" fi if [[ "$INIT_ONLY" == "true" ]]; then init_frontmatter "$PLAN_FILE" echo "Frontmatter initialized for: $PLAN_FILE" exit 0 fi # Read current state ITERATION=$(get_frontmatter "$PLAN_FILE" "iteration" "0") TARGET=$(get_frontmatter "$PLAN_FILE" "target_iterations" "8") STATUS=$(get_frontmatter "$PLAN_FILE" "status" "drafting") NEXT_ITERATION=$((ITERATION + 1)) PLAN_DIR=$(dirname "$PLAN_FILE") # Build paths FEEDBACK_FILE="${PLAN_FILE%.md}.feedback-${NEXT_ITERATION}.md" # Read prompts EVAL_PROMPT=$(cat "$PROMPTS_DIR/chatgpt-eval.md") INTEGRATE_PROMPT=$(cat "$PROMPTS_DIR/claude-integrate.md") # Status check if [[ "$STATUS" == "ready" || "$STATUS" == "implementing" || "$STATUS" == "completed" ]]; then echo "Warning: Plan status is '$STATUS' -- already past iteration phase." echo "Continue anyway? (y/N)" read -r confirm [[ "$confirm" != "y" && "$confirm" != "Y" ]] && exit 0 fi echo "=== plan-refine ===" echo " Plan: $(basename "$PLAN_FILE")" echo " Status: $STATUS" echo " Iteration: $ITERATION -> $NEXT_ITERATION (target: $TARGET)" echo " Feedback: $(basename "$FEEDBACK_FILE")" if [[ "$NO_INTEGRATE" == "true" ]]; then echo " Mode: ChatGPT review only" else echo " Mode: Full cycle (ChatGPT + Claude integration)" fi echo "" if [[ "$DRY_RUN" == "true" ]]; then echo "=== DRY RUN ===" echo "" echo "Step 1: ChatGPT via Brave CDP (port $CDP_PORT)" echo " node $LIB_DIR/chatgpt-send.mjs $FEEDBACK_FILE --timeout $CHATGPT_TIMEOUT" echo "" if [[ "$NO_INTEGRATE" != "true" ]]; then echo "Step 2: Claude CLI integration" echo " claude -p --allowedTools Read,Edit,Write --permission-mode acceptEdits" fi exit 0 fi # ────────────────────────────────────────────── # Check Brave CDP connectivity # ────────────────────────────────────────────── if ! curl -s "http://127.0.0.1:${CDP_PORT}/json/version" >/dev/null 2>&1; then echo "Error: Cannot connect to Brave on port $CDP_PORT" >&2 echo "" >&2 echo "Brave needs to be running with CDP enabled. Do this once:" >&2 echo " 1. Quit Brave (Cmd+Q)" >&2 echo " 2. open -a \"Brave Browser\" --args --remote-debugging-port=$CDP_PORT" >&2 echo "" >&2 echo "Or set CHATGPT_CDP_PORT if using a different port." >&2 exit 1 fi # ────────────────────────────────────────────── # Step 1: Send to ChatGPT via Brave # ────────────────────────────────────────────── echo "[Step 1] Sending plan to ChatGPT via Brave..." # Build the full prompt file (eval prompt + plan content) PROMPT_TMPFILE=$(mktemp /tmp/plan-refine-prompt-XXXXXX.md) { echo "$EVAL_PROMPT" echo "" echo "---" echo "" cat "$PLAN_FILE" } > "$PROMPT_TMPFILE" CHATGPT_CDP_PORT="$CDP_PORT" node "$LIB_DIR/chatgpt-send.mjs" \ "$PROMPT_TMPFILE" \ "$FEEDBACK_FILE" \ --timeout "$CHATGPT_TIMEOUT" CHATGPT_EXIT=$? rm -f "$PROMPT_TMPFILE" if [[ $CHATGPT_EXIT -ne 0 ]]; then echo "Error: ChatGPT send failed (exit $CHATGPT_EXIT)" >&2 exit $CHATGPT_EXIT fi echo "ChatGPT feedback saved to: $FEEDBACK_FILE" # ────────────────────────────────────────────── # Step 2: Claude integration # ────────────────────────────────────────────── if [[ "$NO_INTEGRATE" == "true" ]]; then echo "" echo "Skipping integration (--no-integrate)." echo "Run manually: plan-refine $(basename "$PLAN_FILE") --integrate-only" else echo "" echo "[Step 2] Claude integrating feedback into plan..." CLAUDE_PROMPT="Read the original plan at: ${PLAN_FILE} Read ChatGPT's feedback at: ${FEEDBACK_FILE} ${INTEGRATE_PROMPT} Important instructions: - Write the updated plan back to: ${PLAN_FILE} - Preserve the YAML frontmatter block (between the --- delimiters) at the top unchanged. - Only modify the content below the frontmatter. - Do NOT output the plan to stdout. Write it directly to the file." CLAUDE_MODEL_ARGS=() if [[ -n "$CLAUDE_MODEL" ]]; then CLAUDE_MODEL_ARGS+=(--model "$CLAUDE_MODEL") fi claude -p "$CLAUDE_PROMPT" \ --allowedTools "Read,Edit,Write" \ --permission-mode acceptEdits \ --add-dir "$PLAN_DIR" \ "${CLAUDE_MODEL_ARGS[@]}" CLAUDE_EXIT=$? if [[ $CLAUDE_EXIT -ne 0 ]]; then echo "Error: Claude integration failed (exit $CLAUDE_EXIT)" >&2 echo "Feedback still available at: $FEEDBACK_FILE" >&2 exit $CLAUDE_EXIT fi echo "Integration complete. Plan updated." fi # ────────────────────────────────────────────── # Update frontmatter # ────────────────────────────────────────────── set_frontmatter "$PLAN_FILE" "iteration" "$NEXT_ITERATION" set_frontmatter "$PLAN_FILE" "updated" "$(date +%Y-%m-%d)" if [[ "$STATUS" == "drafting" ]]; then set_frontmatter "$PLAN_FILE" "status" "iterating" fi echo "" echo "=== Iteration $NEXT_ITERATION/$TARGET complete ===" if [[ $NEXT_ITERATION -ge $TARGET ]]; then echo "" echo "Target iterations reached. Plan may be ready for bead splitting." fi