Connects to user's running Brave via Chrome DevTools Protocol to automate ChatGPT interaction. Uses puppeteer-core to open a tab, send the prompt, wait for response, and extract the result. No cookies, no separate profiles, no copy/paste. Just connects to the browser where the user is already logged in. One-time setup: relaunch Brave with --remote-debugging-port=9222 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
258 lines
8.5 KiB
Bash
Executable File
258 lines
8.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# plan-refine — Fully automated plan iteration: ChatGPT review + Claude integration
|
|
# Usage: plan-refine <plan-file> [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 <plan-file> [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 <m> Claude model for integration (default: your default)
|
|
--timeout <seconds> ChatGPT response timeout (default: 600)
|
|
--cdp-port <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 <plan-file>" >&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 <prompt-file> $FEEDBACK_FILE --timeout $CHATGPT_TIMEOUT"
|
|
echo ""
|
|
if [[ "$NO_INTEGRATE" != "true" ]]; then
|
|
echo "Step 2: Claude CLI integration"
|
|
echo " claude -p <integration-prompt> --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
|