Add Brave CDP automation, replace Oracle browser mode

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>
This commit is contained in:
Taylor Eernisse
2026-02-07 16:16:41 -05:00
parent d776a266a8
commit e7882b917b
4163 changed files with 782828 additions and 148 deletions

View File

@@ -1,10 +1,10 @@
#!/usr/bin/env bash
# plan-refine — One-command plan iteration: ChatGPT review + Claude integration
# plan-refine — Fully automated plan iteration: ChatGPT review + Claude integration
# Usage: plan-refine <plan-file> [options]
#
# Step 1: Assembles evaluation prompt + plan content, copies to clipboard.
# User pastes into ChatGPT, copies response, saves to feedback file.
# Step 2: Claude CLI integrates feedback back into the plan file.
# 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
@@ -17,6 +17,7 @@ while [[ -L "$SOURCE" ]]; do
done
SCRIPT_DIR="$(cd -P "$(dirname "$SOURCE")/.." && pwd)"
PROMPTS_DIR="$SCRIPT_DIR/prompts"
LIB_DIR="$SCRIPT_DIR/lib"
source "$SCRIPT_DIR/lib/frontmatter.sh"
@@ -26,24 +27,29 @@ DRY_RUN=false
NO_INTEGRATE=false
PLAN_FILE=""
INIT_ONLY=false
STEP=""
CDP_PORT="${CHATGPT_CDP_PORT:-9222}"
CHATGPT_TIMEOUT=600
usage() {
cat <<'EOF'
plan-refine — Semi-automated plan iteration: ChatGPT review + Claude integration
plan-refine — Fully automated plan iteration via Brave + Claude CLI
Usage: plan-refine <plan-file> [options]
Workflow per iteration:
1. plan-refine <file> Copies ChatGPT prompt to clipboard
2. Paste into ChatGPT, copy response, save to <file>.feedback-N.md
3. plan-refine <file> --integrate Claude integrates feedback into plan
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:
--integrate Run Claude integration (Step 2)
--no-integrate Skip Claude integration, just update frontmatter
--claude-model <m> Claude model for integration (default: your default)
--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
@@ -52,10 +58,11 @@ EOF
while [[ $# -gt 0 ]]; do
case "$1" in
--integrate) STEP="integrate"; shift ;;
--no-integrate) NO_INTEGRATE=true; shift ;;
--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 ;;
@@ -84,7 +91,6 @@ if ! head -1 "$PLAN_FILE" | grep -q '^---$'; then
fi
if ! is_plan_file "$PLAN_FILE"; then
echo "Adding plan: true to frontmatter..."
set_frontmatter "$PLAN_FILE" "plan" "true"
fi
@@ -116,56 +122,91 @@ if [[ "$STATUS" == "ready" || "$STATUS" == "implementing" || "$STATUS" == "compl
[[ "$confirm" != "y" && "$confirm" != "Y" ]] && exit 0
fi
# ──────────────────────────────────────────────
# Route to the right step
# ──────────────────────────────────────────────
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 [[ "$STEP" == "integrate" ]]; then
# ──────────────────────────────────────────
# Step 2: Claude integration
# ──────────────────────────────────────────
# Find the latest feedback file
if [[ -f "$FEEDBACK_FILE" ]]; then
FOUND_FEEDBACK="$FEEDBACK_FILE"
else
# Search for any feedback file for the current iteration
FOUND_FEEDBACK=$(ls -t "${PLAN_FILE%.md}".feedback-*.md 2>/dev/null | head -1)
fi
if [[ -z "$FOUND_FEEDBACK" || ! -f "$FOUND_FEEDBACK" ]]; then
echo "Error: No feedback file found." >&2
echo "Expected: $FEEDBACK_FILE" >&2
echo "" >&2
echo "Run step 1 first: plan-refine $PLAN_FILE" >&2
echo "Then save ChatGPT's response to: $FEEDBACK_FILE" >&2
exit 1
fi
echo "=== plan-refine --integrate ==="
echo " Plan: $(basename "$PLAN_FILE")"
echo " Feedback: $(basename "$FOUND_FEEDBACK")"
echo " Iteration: $ITERATION -> $NEXT_ITERATION (target: $TARGET)"
if [[ "$DRY_RUN" == "true" ]]; then
echo "=== DRY RUN ==="
echo ""
if [[ "$DRY_RUN" == "true" ]]; then
echo "=== DRY RUN ==="
echo "Would run:"
echo " claude -p <integration-prompt> \\"
echo " --allowedTools \"Read,Edit,Write\" \\"
echo " --permission-mode acceptEdits \\"
echo " --add-dir \"$PLAN_DIR\""
[[ -n "$CLAUDE_MODEL" ]] && echo " --model $CLAUDE_MODEL"
exit 0
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
if [[ "$NO_INTEGRATE" == "true" ]]; then
echo "Skipping Claude integration (--no-integrate)."
else
echo "Claude integrating feedback into plan..."
# ──────────────────────────────────────────────
# Check Brave CDP connectivity
# ──────────────────────────────────────────────
CLAUDE_PROMPT="Read the original plan at: ${PLAN_FILE}
Read ChatGPT's feedback at: ${FOUND_FEEDBACK}
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}
@@ -175,95 +216,42 @@ Important instructions:
- 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 CLI exited with code $CLAUDE_EXIT" >&2
echo "Feedback is still available at: $FOUND_FEEDBACK" >&2
echo "You can integrate manually in Claude Code." >&2
exit $CLAUDE_EXIT
fi
echo "Integration complete. Plan updated."
CLAUDE_MODEL_ARGS=()
if [[ -n "$CLAUDE_MODEL" ]]; then
CLAUDE_MODEL_ARGS+=(--model "$CLAUDE_MODEL")
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"
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 ""
echo "=== Iteration $NEXT_ITERATION/$TARGET complete ==="
if [[ $NEXT_ITERATION -ge $TARGET ]]; then
echo ""
echo "Target iterations reached. Plan may be ready for bead splitting."
echo "To advance status: set 'status: splitting' in the frontmatter."
fi
else
# ──────────────────────────────────────────
# Step 1: Prepare ChatGPT prompt
# ──────────────────────────────────────────
echo "=== plan-refine ==="
echo " Plan: $(basename "$PLAN_FILE")"
echo " Status: $STATUS"
echo " Iteration: $ITERATION -> $NEXT_ITERATION (target: $TARGET)"
echo ""
# Use Oracle's --render --copy to bundle prompt + file content
if command -v oracle &>/dev/null; then
if [[ "$DRY_RUN" == "true" ]]; then
echo "=== DRY RUN ==="
echo "Would run: oracle --render --copy -p <eval-prompt> --file $PLAN_FILE"
echo ""
echo "=== PROMPT ==="
echo "$EVAL_PROMPT"
exit 0
fi
oracle --render --copy \
-p "$EVAL_PROMPT" \
--file "$PLAN_FILE" 2>/dev/null
echo "ChatGPT prompt copied to clipboard (assembled by Oracle)."
else
# Fallback: manual clipboard assembly
if [[ "$DRY_RUN" == "true" ]]; then
echo "=== DRY RUN ==="
echo "Would copy evaluation prompt + plan content to clipboard."
exit 0
fi
PLAN_CONTENT=$(cat "$PLAN_FILE")
CLIPBOARD="${EVAL_PROMPT}
---
${PLAN_CONTENT}"
echo "$CLIPBOARD" | pbcopy
echo "ChatGPT prompt copied to clipboard."
fi
echo ""
echo "Next steps:"
echo " 1. Paste into ChatGPT (Cmd+V)"
echo " 2. Wait for response"
echo " 3. Copy ChatGPT's full response"
echo " 4. Save it to: $FEEDBACK_FILE"
echo " 5. Run: plan-refine $(basename "$PLAN_FILE") --integrate"
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