Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
158 changes: 108 additions & 50 deletions skills/auto-github-contributor/scripts/browser-verify.sh
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
#!/usr/bin/env bash

# Browser-based visual verification.
#
# This script drives a headless browser to capture screenshots / DOM dumps so
# the agent can eyeball the change before opening the PR. The actual automation
# body is intentionally a STUB — wire it up to whichever tool you prefer:
#
# - Playwright (pnpm dlx playwright screenshot ...)
# - Puppeteer (node ./scripts/puppet.js ...)
# - chrome-devtools MCP (mcp__chrome_devtools__take_screenshot)
# - Browser Use MCP
# the agent can eyeball the change before opening the PR. The Playwright
# backend is wired up by default; Puppeteer and chrome-devtools MCP are
# available as drop-in alternatives (see commented blocks below).
#
# Contract:
# Input : --url <url> --out <png-path> [--selector <css>] [--wait <ms>]
# Output : writes PNG to --out, prints "SCREENSHOT=<abs-path>" on stdout
# Stubs : when the automation body is not yet implemented, the script
# still creates the output directory, writes a placeholder note,
# and exits 0 with "stub: <reason>" so the agent flow continues.
# Stub : when the automation body fails, the script still creates the output
# directory, writes a placeholder note, and exits 0 so the agent flow
# continues.
#
# Backend selection (change the single `backend` variable below):
# playwright – Playwright CLI (default, works on all platforms)
# puppeteer – node + puppeteer.mjs
# chrome-mcp – chrome-devtools MCP (agent should use MCP tool directly)

set -euo pipefail
source "$(dirname "$0")/config.sh"
Expand All @@ -24,14 +26,16 @@ URL=""
OUT=""
SELECTOR=""
WAIT_MS="1500"
# Set to "playwright", "puppeteer", or "chrome-mcp"
backend="playwright"

while (($#)); do
case "$1" in
--url) URL="$2"; shift 2 ;;
--out) OUT="$2"; shift 2 ;;
--url) URL="$2"; shift 2 ;;
--out) OUT="$2"; shift 2 ;;
--selector) SELECTOR="$2"; shift 2 ;;
--wait) WAIT_MS="$2"; shift 2 ;;
*) agc::die "unknown flag: $1" ;;
--wait) WAIT_MS="$2"; shift 2 ;;
*) agc::die "unknown flag: $1" ;;
esac
done

Expand All @@ -40,48 +44,102 @@ done

mkdir -p "$(dirname "$OUT")"

agc::log "browser-verify url=${URL} out=${OUT} viewport=${AGC_BROWSER_VIEWPORT} headless=${AGC_BROWSER_HEADLESS}"

# --------------------------------------------------------------------------
# Implementation hook — pick ONE backend and uncomment.
# Left as stubs on purpose; user will plug in preferred tooling.
# --------------------------------------------------------------------------

# === Backend A: Playwright CLI =============================================
# agc::require npx
# VIEWPORT_W="${AGC_BROWSER_VIEWPORT%x*}"
# VIEWPORT_H="${AGC_BROWSER_VIEWPORT#*x}"
# npx --yes playwright@latest screenshot \
# --viewport-size="${VIEWPORT_W},${VIEWPORT_H}" \
# --wait-for-timeout "$WAIT_MS" \
# ${SELECTOR:+--selector "$SELECTOR"} \
# "$URL" "$OUT"

# === Backend B: Puppeteer via node =========================================
# node "$(dirname "$0")/puppet.mjs" --url "$URL" --out "$OUT" \
# --selector "$SELECTOR" --wait "$WAIT_MS" \
# --viewport "$AGC_BROWSER_VIEWPORT" --headless "$AGC_BROWSER_HEADLESS"

# === Backend C: chrome-devtools MCP ========================================
# The agent should call the MCP tool directly rather than shelling out.
# If routed through this script, print the hint so the agent knows to switch:
# agc::log "use mcp__chrome_devtools__take_screenshot instead of this shell"

# --------------------------------------------------------------------------
# Fallback: stub mode
# --------------------------------------------------------------------------
if [[ ! -s "$OUT" ]]; then
VIEWPORT_W="${AGC_BROWSER_VIEWPORT%x*}"
VIEWPORT_H="${AGC_BROWSER_VIEWPORT#*x}"

agc::log "browser-verify backend=${backend} url=${URL} out=${OUT} viewport=${AGC_BROWSER_VIEWPORT} headless=${AGC_BROWSER_HEADLESS}"

# ---------------------------------------------------------------------------
# Backend A: Playwright CLI (default)
# ---------------------------------------------------------------------------
playwright_backend() {
agc::require npx
local extra=()
[[ -n "$SELECTOR" ]] && extra+=(--selector "$SELECTOR")

if npx --yes playwright@latest screenshot \
--viewport-size="${VIEWPORT_W},${VIEWPORT_H}" \
--wait-for-timeout "$WAIT_MS" \
"${extra[@]}" \
"$URL" "$OUT" 2>/dev/null; then
return 0
fi
return 1
}

# ---------------------------------------------------------------------------
# Backend B: Puppeteer via node
# ---------------------------------------------------------------------------
puppeteer_backend() {
if [[ -f "$(dirname "$0")/puppet.mjs" ]]; then
node "$(dirname "$0")/puppet.mjs" \
--url "$URL" --out "$OUT" \
--selector "$SELECTOR" --wait "$WAIT_MS" \
--viewport "$AGC_BROWSER_VIEWPORT" \
--headless "$AGC_BROWSER_HEADLESS" 2>/dev/null
return $?
fi
return 1
}

# ---------------------------------------------------------------------------
# Backend C: chrome-devtools MCP
# ---------------------------------------------------------------------------
chrome_mcp_backend() {
# The agent should call mcp__chrome_devtools__take_screenshot directly.
# If routed here, just log the hint — we can't invoke MCP from bash.
agc::log "chrome-mcp: use mcp__chrome_devtools__take_screenshot tool directly"
return 1
}

# ---------------------------------------------------------------------------
# Run the selected backend; fall back to stub on failure
# ---------------------------------------------------------------------------
did_capture=false

case "$backend" in
playwright)
if playwright_backend; then
did_capture=true
agc::log "screenshot captured via Playwright: $OUT"
else
agc::log "Playwright capture failed, falling back to stub"
fi
;;
puppeteer)
if puppeteer_backend; then
did_capture=true
agc::log "screenshot captured via Puppeteer: $OUT"
else
agc::log "Puppeteer capture failed, falling back to stub"
fi
;;
chrome-mcp)
if chrome_mcp_backend; then
did_capture=true
else
agc::log "chrome-devtools MCP unavailable, falling back to stub"
fi
;;
*)
agc::die "unknown backend: $backend (expected playwright|puppeteer|chrome-mcp)"
;;
esac

# ---------------------------------------------------------------------------
# Stub fallback
# ---------------------------------------------------------------------------
if [[ "$did_capture" != "true" ]]; then
cat > "${OUT%.png}.stub.txt" <<EOF
# TODO(auto-gh): browser-verify backend not wired up yet.
# Requested: $URL
# browser-verify backend not captured for: $URL
# Backend: $backend
# Would write screenshot to: $OUT
# Selector: ${SELECTOR:-<full page>}
# Wait: ${WAIT_MS}ms
# Viewport: ${AGC_BROWSER_VIEWPORT}
EOF
agc::log "stub: browser backend not configured (see ${OUT%.png}.stub.txt)"
printf 'SCREENSHOT=%s\n' "${OUT%.png}.stub.txt"
exit 0
agc::log "stub: browser capture unavailable (see ${OUT%.png}.stub.txt)"
fi

printf 'SCREENSHOT=%s\n' "$OUT"
exit 0
65 changes: 41 additions & 24 deletions skills/auto-github-contributor/scripts/dev-loop-check.sh
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
#!/usr/bin/env bash

# Phase-aware dev-loop checker. Invoked from the repo workdir.
#
# Phases:
# --phase red → expect the newest test(s) to FAIL (proves coverage gap)
# --phase green → install + lint + typecheck + test (must all pass)
# --phase final → clean install + lint + typecheck + full tests + build
# --phase red → expect the newest test(s) to FAIL (proves coverage gap)
# --phase green → install + lint + typecheck + test (must all pass)
# --phase final → clean install + lint + typecheck + full tests + build
#
# Usage:
# dev-loop-check.sh --phase green [--workdir <dir>]
Expand Down Expand Up @@ -42,20 +44,20 @@ run() {

# Pick the right package manager command based on lockfile.
detect_install_cmd() {
if [[ -f pnpm-lock.yaml ]]; then echo "pnpm install --frozen-lockfile";
elif [[ -f yarn.lock ]]; then echo "yarn install --frozen-lockfile";
elif [[ -f package-lock.json ]]; then echo "npm ci";
elif [[ -f bun.lockb ]]; then echo "bun install --frozen-lockfile";
else echo "${AGC_INSTALL_CMD}";
if [[ -f pnpm-lock.yaml ]]; then echo "pnpm install --frozen-lockfile"
elif [[ -f yarn.lock ]]; then echo "yarn install --frozen-lockfile"
elif [[ -f package-lock.json ]]; then echo "npm ci"
elif [[ -f bun.lockb ]]; then echo "bun install --frozen-lockfile"
else echo "${AGC_INSTALL_CMD}"
fi
}

# Pick the JS package manager runner based on lockfile.
detect_runner() {
if [[ -f pnpm-lock.yaml ]]; then echo "pnpm run";
elif [[ -f yarn.lock ]]; then echo "yarn";
elif [[ -f bun.lockb ]]; then echo "bun run";
else echo "npm run";
if [[ -f pnpm-lock.yaml ]]; then echo "pnpm run"
elif [[ -f yarn.lock ]]; then echo "yarn"
elif [[ -f bun.lockb ]]; then echo "bun run"
else echo "npm run"
fi
}

Expand All @@ -76,6 +78,7 @@ TEST_CMD="$(detect_script test "$AGC_TEST_CMD")"
BUILD_CMD="$(detect_script build "$AGC_BUILD_CMD")"

case "$PHASE" in

red)
# Red: run only the test suite. Expect non-zero (failing new test) — we
# invert the exit code so a "correctly failing" red phase reports success.
Expand All @@ -90,24 +93,38 @@ case "$PHASE" in
;;

green)
run "install" bash -lc "$INSTALL_CMD"
run "lint" bash -lc "$LINT_CMD"
run "typecheck" bash -lc "$TYPECHECK_CMD"
run "test" bash -lc "$TEST_CMD"
run "install" bash -lc "$INSTALL_CMD"
run "lint" bash -lc "$LINT_CMD"
run "typecheck" bash -lc "$TYPECHECK_CMD"
run "test" bash -lc "$TEST_CMD"
;;

final)
run "install (clean)" bash -lc "$INSTALL_CMD"
run "lint" bash -lc "$LINT_CMD"
run "typecheck" bash -lc "$TYPECHECK_CMD"
run "test" bash -lc "$TEST_CMD"
run "build" bash -lc "$BUILD_CMD"
# TODO(auto-gh): repo-specific `verify` / e2e hook. Wire a shell command here
# once the target repo ships a stable e2e target (e.g. `pnpm test:e2e`).
run "install (clean)" bash -lc "$INSTALL_CMD"
run "lint" bash -lc "$LINT_CMD"
run "typecheck" bash -lc "$TYPECHECK_CMD"
run "test" bash -lc "$TEST_CMD"
run "build" bash -lc "$BUILD_CMD"

# Wired e2e / verify hook if the target repo defines one.
# Looks for: test:e2e, test:e2e:ci, or a top-level `verify` script.
if [[ -f package.json ]]; then
E2E_SCRIPT="$(jq -r '
.scripts["test:e2e"] // .scripts["test:e2e:ci"] // .scripts.verify // empty
' package.json 2>/dev/null || echo '')"
if [[ -n "$E2E_SCRIPT" ]] && [[ "$E2E_SCRIPT" != "null" ]]; then
RUNNER="$(detect_runner)"
run "e2e" bash -lc "$RUNNER $E2E_SCRIPT"
else
agc::log "e2e: no test:e2e / verify script found, skipping"
fi
fi

agc::log "final verification complete"
;;

*)
agc::die "invalid phase: $PHASE (expected red|green|final)"
;;
esac

esac