#!/usr/bin/env bash set -euo pipefail if [[ $# -lt 1 ]]; then echo "Usage: tools/pw [args...]" >&2 exit 1 fi for arg in "$@"; do if [[ "$arg" == "--session" || "$arg" == "--session="* ]]; then echo "Do not pass --session directly. Use PLAYWRIGHT_SHARED_SESSION." >&2 exit 2 fi done CODEX_HOME="${CODEX_HOME:-$HOME/.codex}" PWCLI="${PWCLI:-$CODEX_HOME/skills/playwright/scripts/playwright_cli.sh}" SESSION="${PLAYWRIGHT_SHARED_SESSION:-codex-shared}" LOCK_TIMEOUT="${PLAYWRIGHT_SHARED_LOCK_TIMEOUT:-120}" LOCK_DIR="${PLAYWRIGHT_SHARED_LOCK_DIR:-/tmp/pw-shared-session.lock}" INIT_MODE="${PLAYWRIGHT_SHARED_INIT_MODE:-headed}" if ! command -v npx >/dev/null 2>&1; then echo "npx is required." >&2 exit 1 fi if [[ ! -x "$PWCLI" ]]; then echo "Playwright wrapper not found or not executable: $PWCLI" >&2 exit 1 fi acquire_lock() { local start_ts now lock_pid lock_mtime start_ts="$(date +%s)" while ! mkdir "$LOCK_DIR" 2>/dev/null; do lock_pid="" if [[ -f "$LOCK_DIR/pid" ]]; then lock_pid="$(cat "$LOCK_DIR/pid" 2>/dev/null || true)" fi if [[ -z "$lock_pid" ]]; then lock_mtime="$(stat -f %m "$LOCK_DIR" 2>/dev/null || echo 0)" now="$(date +%s)" if (( now - lock_mtime >= 5 )); then rm -rf "$LOCK_DIR" 2>/dev/null || true continue fi fi if [[ -n "$lock_pid" ]] && ! kill -0 "$lock_pid" 2>/dev/null; then rm -rf "$LOCK_DIR" 2>/dev/null || true continue fi now="$(date +%s)" if (( now - start_ts >= LOCK_TIMEOUT )); then echo "Timeout waiting for Playwright shared-session lock: $LOCK_DIR" >&2 exit 1 fi sleep 1 done printf "%s\n" "$$" > "$LOCK_DIR/pid" trap 'rm -rf "$LOCK_DIR" 2>/dev/null || true' EXIT INT TERM } run_pw() { "$PWCLI" --session "$SESSION" "$@" } is_missing_session_error() { local text="$1" if echo "$text" | rg -qi "session.*not found|no browser|not open|closed"; then return 0 fi return 1 } acquire_lock cmd=("$@") verb="${cmd[0]}" if [[ "$verb" == "open" ]]; then url="" for (( i = 1; i < ${#cmd[@]}; i++ )); do arg="${cmd[$i]}" if [[ "$arg" != -* ]]; then url="$arg" break fi done if [[ -n "$url" ]]; then set +e out="$(run_pw snapshot 2>&1)" code=$? set -e if [[ $code -eq 0 ]]; then run_pw goto "$url" run_pw snapshot exit 0 fi if ! is_missing_session_error "$out"; then echo "$out" >&2 exit $code fi fi fi if [[ "$verb" != "open" ]]; then set +e out="$(run_pw "${cmd[@]}" 2>&1)" code=$? set -e if [[ $code -eq 0 ]]; then echo "$out" exit 0 fi if is_missing_session_error "$out"; then set +e if [[ "$INIT_MODE" == "headless" ]]; then run_pw open about:blank >/dev/null 2>&1 init_code=$? elif [[ "$INIT_MODE" == "headed" ]]; then run_pw open about:blank --headed >/dev/null 2>&1 init_code=$? if [[ $init_code -ne 0 ]]; then run_pw open about:blank >/dev/null 2>&1 init_code=$? fi else run_pw open about:blank --headed >/dev/null 2>&1 init_code=$? if [[ $init_code -ne 0 ]]; then run_pw open about:blank >/dev/null 2>&1 init_code=$? fi fi set -e if [[ $init_code -ne 0 ]]; then echo "Failed to initialize shared Playwright session." >&2 exit 1 fi run_pw "${cmd[@]}" exit 0 fi echo "$out" >&2 exit $code fi run_pw "${cmd[@]}"