feat(browser): auto-commit con 178 cambios

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-20 18:22:23 +02:00
parent 7d100e7f3e
commit 763e06c127
178 changed files with 19917 additions and 317 deletions
@@ -0,0 +1,94 @@
#!/usr/bin/env bash
# focus_cdp_tab_window — trae al frente la pestaña + la ventana del SO de un Chrome con CDP
#
# Handoff humano de captcha: activa la tab del captcha (opcional, via CDP) y levanta
# la ventana X11 del proceso browser principal de ese puerto para que un humano resuelva
# el captcha a mano. Best-effort y robusto: cada paso continua aunque uno falle.
focus_cdp_tab_window() {
set -uo pipefail
local port="${1:-}"
local target_id="${2:-}"
# 1. Validacion de entorno y dependencias.
if [[ -z "$port" ]]; then
echo "focus_cdp_tab_window: falta el puerto CDP (uso: focus_cdp_tab_window <port> [target_id])" >&2
return 2
fi
if [[ -z "${DISPLAY:-}" ]]; then
echo "focus_cdp_tab_window: sin entorno grafico (DISPLAY vacio)" >&2
return 3
fi
if ! command -v wmctrl >/dev/null 2>&1 || ! command -v xdotool >/dev/null 2>&1; then
echo "focus_cdp_tab_window: falta wmctrl/xdotool" >&2
return 4
fi
# 2. Activar la tab del captcha dentro del browser (best-effort, no aborta).
if [[ -n "$target_id" ]]; then
curl -sf "http://127.0.0.1:${port}/json/activate/${target_id}" >/dev/null 2>&1 || true
fi
# 3. Encontrar el PID del proceso BROWSER principal de ese puerto.
# De las lineas que matchean el flag de debugging, el browser process es el que
# NO lleva --type= (los renderers/gpu/utility/zygote son procesos hijos).
local browser_pid=""
local line
while IFS= read -r line; do
[[ -z "$line" ]] && continue
if [[ "$line" == *"--type="* ]]; then
continue
fi
# pgrep -af antepone el PID seguido de la cmdline.
browser_pid="${line%% *}"
break
done < <(pgrep -af -- "remote-debugging-port=${port}" 2>/dev/null)
if [[ -z "$browser_pid" ]]; then
echo "focus_cdp_tab_window: no hay chromium en el puerto ${port}" >&2
return 5
fi
# 4. Resolver el window id top-level.
# Primero por wmctrl -lp (columna 3 = PID). Fallback xdotool si el main no expone _NET_WM_PID.
local wid=""
while IFS= read -r line; do
[[ -z "$line" ]] && continue
# Formato: <wid> <desktop> <pid> <host> <title...>
local w_id w_pid
w_id="$(awk '{print $1}' <<<"$line")"
w_pid="$(awk '{print $3}' <<<"$line")"
if [[ "$w_pid" == "$browser_pid" ]]; then
wid="$w_id"
break
fi
done < <(wmctrl -lp 2>/dev/null)
if [[ -z "$wid" ]]; then
wid="$(xdotool search --pid "$browser_pid" --onlyvisible 2>/dev/null | head -n1)"
fi
if [[ -z "$wid" ]]; then
echo "focus_cdp_tab_window: no se encontro ventana top-level para pid ${browser_pid} (puerto ${port})" >&2
return 6
fi
# 5. Traer al frente con REINTENTO (xfwm de XFCE pisa el primer activate/raise).
# Espera no bloqueante con read -t en vez de sleep.
local attempt
for attempt in 1 2; do
xdotool windowactivate "$wid" >/dev/null 2>&1 || true
read -r -t 0.2 _ < /dev/zero 2>/dev/null || true
xdotool windowraise "$wid" >/dev/null 2>&1 || true
done
# 6. Salida legible y JSON-parseable simple.
echo "focus_cdp_tab_window: focused win=${wid} pid=${browser_pid} port=${port} tab=${target_id:--}"
return 0
}
# Permitir ejecucion directa: focus_cdp_tab_window <port> [target_id]
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
focus_cdp_tab_window "$@"
fi