metis-desk/scripts/setup-playwright-wsl.sh

113 lines
4.4 KiB
Bash
Raw Normal View History

#!/usr/bin/env bash
# Prepara el entorno Docker fijado; no instala navegadores ni modifica Codex global.
set -euo pipefail
if [[ "${1:-}" == "--help" ]]; then
printf '%s\n' 'Uso: bash scripts/setup-playwright-wsl.sh' \
'Requiere WSL2, Python >=3.11 y Docker Linux accesible.' \
'Reutiliza la imagen fijada o la descarga; comprueba Chromium y red host.'
exit 0
fi
if [[ $# -ne 0 ]]; then
printf '%s\n' 'Error: argumento desconocido; utiliza --help.' >&2
exit 2
fi
script_dir=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)
repo_dir=$(cd -- "$script_dir/.." && pwd)
kernel_release=$(uname -r)
if [[ "${kernel_release,,}" != *microsoft* || "${kernel_release,,}" != *wsl2* ]]; then
printf '%s\n' 'Error: ejecuta este instalador desde bash dentro de WSL2.' >&2
exit 1
fi
for executable in python3 docker timeout; do
if ! command -v "$executable" >/dev/null 2>&1; then
printf 'Error: falta %s. Consulta docs/playwright-mcp.md.\n' "$executable" >&2
exit 1
fi
done
if ! python3 -c 'import sys; sys.exit(sys.version_info < (3, 11))'; then
printf '%s\n' 'Error: se necesita Python 3.11 o posterior (tomllib).' >&2
exit 1
fi
trap 'printf "Error: preparación interrumpida en la línea %s. Revisa Docker y docs/playwright-mcp.md.\n" "$LINENO" >&2' ERR
METIS_MCP_IMAGE=$(python3 - "$repo_dir/.codex/config.toml" <<'PY'
import re
import sys
import tomllib
with open(sys.argv[1], 'rb') as source:
config = tomllib.load(source)['mcp_servers']['playwright']
images = [arg for arg in config['args'] if re.fullmatch(r'mcr\.microsoft\.com/playwright/mcp:v[\d.]+@sha256:[a-f0-9]{64}', arg)]
if config['command'] != 'docker' or len(images) != 1 or '--network=host' not in config['args']:
sys.exit('Error: se requiere la configuración Docker oficial fijada y red host.')
print(images[0])
PY
)
if ! timeout 30 docker info --format '{{.OSType}}' | python3 -c 'import sys; sys.exit(sys.stdin.read().strip() != "linux")'; then
printf '%s\n' 'Error: Docker Linux no responde. Activa el daemon o la integración WSL; comprueba los permisos del usuario.' >&2
exit 1
fi
if timeout 30 docker image inspect "$METIS_MCP_IMAGE" >/dev/null 2>&1; then
printf '%s\n' 'La imagen fijada ya está disponible; se reutiliza.'
else
printf '%s\n' 'Descargando servidor y Chromium compatibles en la misma imagen oficial…'
timeout 600 docker pull "$METIS_MCP_IMAGE"
fi
# El endpoint efímero solo devuelve un token de prueba; no sirve archivos del equipo.
python3 - "$METIS_MCP_IMAGE" <<'PY'
import http.server
import subprocess
import sys
import threading
import uuid
token = uuid.uuid4().hex
container = 'metis-playwright-setup-' + token[:12]
class ProbeHandler(http.server.BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.end_headers()
self.wfile.write(token.encode())
def log_message(self, format, *args):
pass
code = """const { chromium } = require('playwright');
(async () => {
const response = await fetch(process.argv[1], {signal: AbortSignal.timeout(10000)});
if (!response.ok || await response.text() !== process.argv[2]) {
throw new Error('La red host no alcanza WSL.');
}
const browser = await chromium.launch({channel: 'chromium', headless: true, args: ['--no-sandbox']});
try {
console.log(JSON.stringify({chromium: browser.version(), network: 'WSL loopback OK'}));
} finally {
await browser.close();
}
})().catch(error => {console.error(error.message); process.exitCode = 1;});"""
try:
with http.server.HTTPServer(('127.0.0.1', 0), ProbeHandler) as server:
threading.Thread(target=server.serve_forever, daemon=True).start()
try:
subprocess.run([
'docker', 'run', '--rm', '--init', '--name=' + container,
'--network=host', '--shm-size=1g', '--workdir=/app', '--entrypoint=node',
sys.argv[1], '-e', code,
'http://127.0.0.1:' + str(server.server_port), token,
], check=True, timeout=90)
finally:
server.shutdown()
except (OSError, subprocess.SubprocessError) as error:
sys.exit('Error: fallo al validar Chromium/red host. Revisa Docker Desktop y sus permisos. ' + str(error))
finally:
subprocess.run(['docker', 'rm', '-f', container], capture_output=True, timeout=15, check=False)
PY
printf '%s\n' 'Entorno preparado. No se ha modificado la configuración global de Codex.' \
'Arranca Metis y ejecuta: python3 scripts/check-playwright-mcp.py <URL-real>'