diff --git a/skills/auto-github-contributor/scripts/browser-verify.sh b/skills/auto-github-contributor/scripts/browser-verify.sh index 0967223..60f08ea 100755 --- a/skills/auto-github-contributor/scripts/browser-verify.sh +++ b/skills/auto-github-contributor/scripts/browser-verify.sh @@ -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 --out [--selector ] [--wait ] # Output : writes PNG to --out, prints "SCREENSHOT=" 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: " 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" @@ -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 @@ -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" <} # 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 \ No newline at end of file diff --git a/skills/auto-github-contributor/scripts/dev-loop-check.sh b/skills/auto-github-contributor/scripts/dev-loop-check.sh index 00ed63a..2933424 100755 --- a/skills/auto-github-contributor/scripts/dev-loop-check.sh +++ b/skills/auto-github-contributor/scripts/dev-loop-check.sh @@ -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 ] @@ -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 } @@ -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. @@ -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 \ No newline at end of file