docs: spec de arranque automatico (doctor.ps1) para .bat
This commit is contained in:
@@ -0,0 +1,131 @@
|
|||||||
|
# Diseño: arranque automático e inteligente para no-técnicos (doctor.ps1)
|
||||||
|
|
||||||
|
Fecha: 2026-08-22
|
||||||
|
Estado: aprobado en conversación
|
||||||
|
|
||||||
|
## Problema
|
||||||
|
|
||||||
|
Los `.bat` actuales son wrappers finos de dos `.ps1` robustos, pero asumen un
|
||||||
|
entorno ya preparado. Para una persona no técnica:
|
||||||
|
|
||||||
|
- Si falta Python (o `python` es el stub falso de la Microsoft Store), el
|
||||||
|
error parpadea y la ventana desaparece sin que se entienda nada.
|
||||||
|
- Si faltan dependencias (`pip install -e ".[web]"` nunca se corrió), uvicorn
|
||||||
|
muere con un traceback ilegible.
|
||||||
|
- Los errores terminan con la ventana cerrándose: imposible leer qué pasó.
|
||||||
|
|
||||||
|
## Objetivo
|
||||||
|
|
||||||
|
Doble clic en `start-server.bat` = la aplicación abre en el navegador,
|
||||||
|
siempre. El script detecta y repara el entorno por sí mismo. Un solo icono
|
||||||
|
para el usuario; `stop-server.bat` queda como acompañante.
|
||||||
|
|
||||||
|
## Enfoque elegido (B)
|
||||||
|
|
||||||
|
Separación de responsabilidades: **entorno** vs **ciclo de vida**.
|
||||||
|
|
||||||
|
```
|
||||||
|
start-server.bat ──> scripts/doctor.ps1 (NUEVO)
|
||||||
|
├─ ¿server ya vivo? ── sí --> abrir navegador, fin
|
||||||
|
├─ resolver Python (py -3 > python > python3)
|
||||||
|
│ └─ ninguno válido --> winget install
|
||||||
|
│ └─ sin winget --> abrir python.org + ERROR
|
||||||
|
├─ import-test de deps
|
||||||
|
│ └─ falla --> pip install -e ".[web]"
|
||||||
|
├─ ffmpeg presente? -- no --> aviso suave NO bloqueante
|
||||||
|
└─ ok --> scripts/start-server.ps1 -PythonExe $py
|
||||||
|
└─ puertos, healthz, browser (SIN CAMBIOS de lógica)
|
||||||
|
```
|
||||||
|
|
||||||
|
`start-server.ps1` conserva toda su lógica verificada (sondas TCP rápidas,
|
||||||
|
limpieza de entradas obsoletas, barrido 8000-8100, apertura de navegador).
|
||||||
|
Único cambio permitido: parámetro opcional `-PythonExe` (default `python`)
|
||||||
|
usado en la línea de comando de uvicorn.
|
||||||
|
|
||||||
|
### Por qué `-PythonExe` es necesario
|
||||||
|
|
||||||
|
Tras una instalación fresca vía winget, el PATH de la sesión actual **no**
|
||||||
|
incluye el Python nuevo. El doctor resuelve la ruta concreta
|
||||||
|
(`%LocalAppData%\Programs\Python\Python312\python.exe`) y se la pasa al
|
||||||
|
launcher; sin esto, el primer arranque post-instalación fallaría.
|
||||||
|
|
||||||
|
## Flujo detallado del doctor
|
||||||
|
|
||||||
|
1. **Server vivo primero** (antes de cualquier chequeo de entorno): sondea el
|
||||||
|
puerto registrado en `.run/server.info`; si responde, abre el navegador y
|
||||||
|
termina con exit 0. Evita instalar dependencias solo para decir "ya está
|
||||||
|
corriendo".
|
||||||
|
2. **Resolver Python**, candidatos en orden: `py -3`, `python`, `python3`.
|
||||||
|
Cada candidato es válido solo si:
|
||||||
|
- ejecuta `--version` y la salida matchea `Python 3.` con versión ≥ 3.10;
|
||||||
|
- su ruta **no** contiene `WindowsApps` (stub de la Store que no ejecuta nada).
|
||||||
|
3. **Instalar Python si falta**: `winget install --id Python.Python.3.12
|
||||||
|
--silent --accept-package-agreements --accept-source-agreements`. Después
|
||||||
|
de instalar, sondear rutas conocidas (`%LocalAppData%\Programs\Python\*`,
|
||||||
|
`C:\Program Files\Python312\`) antes de rendirse. Sin winget disponible:
|
||||||
|
abrir `https://www.python.org/downloads/` en el navegador + instrucción en
|
||||||
|
lenguaje simple + exit ≠ 0.
|
||||||
|
4. **Import-test de dependencias**:
|
||||||
|
`& $py -c "import fastapi, uvicorn, jinja2, sse_starlette, yt_dlp"`.
|
||||||
|
**Nunca** importa `yt_scraper.webapp.app` aquí: ese import abre la DB real
|
||||||
|
del proyecto vía `config.yaml`, corre migraciones y `reconcile_markdown`
|
||||||
|
(gotcha documentado en CLAUDE.md). Si falla el test:
|
||||||
|
`-m pip install -e ".[web]"` mostrando progreso ("instalando por primera
|
||||||
|
vez, puede tardar un par de minutos"). Si falta pip: `-m ensurepip`.
|
||||||
|
5. **ffmpeg**: `Get-Command ffmpeg`; ausente → aviso amarillo no bloqueante
|
||||||
|
("la descarga de audio no estará disponible; todo lo demás funciona").
|
||||||
|
6. Delegar: `& start-server.ps1 -PythonExe $py` + passthrough de args.
|
||||||
|
7. Propagar exit code.
|
||||||
|
|
||||||
|
## Reglas de ventana (.bat)
|
||||||
|
|
||||||
|
| Resultado | Ventana |
|
||||||
|
|---|---|
|
||||||
|
| Exit 0 | mensaje verde + cuenta regresiva ~5 s → cierra sola |
|
||||||
|
| Exit ≠ 0 | **queda abierta** (`pause`) con causa legible + últimas líneas de log |
|
||||||
|
|
||||||
|
Hoy los errores parpadean y desaparecen: es la regla más importante del
|
||||||
|
cambio. Aplica a ambos `.bat`.
|
||||||
|
|
||||||
|
## Mensajes
|
||||||
|
|
||||||
|
Español plano, sin jerga dirigida al usuario final ("servidor", "conexión";
|
||||||
|
no "puerto", "PID", "uvicorn", "PATH"):
|
||||||
|
|
||||||
|
- `[ok] Servidor listo en http://localhost:8000 — abriendo tu navegador...`
|
||||||
|
- `[ok] El servidor ya estaba corriendo — abriendo...`
|
||||||
|
- `[info] Instalando Python automáticamente (~25 MB)…`
|
||||||
|
- `[info] Instalando las piezas que faltan por primera vez (1-2 min)…`
|
||||||
|
- Error: `Algo falló al iniciar el servidor. Esto fue lo último que hizo:`
|
||||||
|
|
||||||
|
El pulido de copys aplica también a los mensajes visibles de
|
||||||
|
`start-server.ps1` y `stop-server.ps1` (solo texto; cero cambios de lógica).
|
||||||
|
|
||||||
|
## Errores cubiertos
|
||||||
|
|
||||||
|
| Caso | Detección | Acción |
|
||||||
|
|---|---|---|
|
||||||
|
| Stub falso Microsoft Store | `--version` falla o ruta `*WindowsApps*` | Siguiente candidato |
|
||||||
|
| Sin Python válido | 3 candidatos fallan | winget silencioso; sin winget → python.org + ERROR |
|
||||||
|
| PATH fresco post-instalación | winget OK | Sondeo de rutas conocidas |
|
||||||
|
| pip ausente | `-m pip --version` falla | `ensurepip` |
|
||||||
|
| Deps rotas/faltantes | import-test falla | `pip install -e ".[web]"` |
|
||||||
|
| ffmpeg ausente | `Get-Command` vacío | Aviso amarillo no bloqueante |
|
||||||
|
| Error de arranque | exit ≠ 0 del launcher | Ventana queda abierta con log |
|
||||||
|
|
||||||
|
## Fuera de alcance
|
||||||
|
|
||||||
|
- No se toca lógica de puertos, healthz, browser ni cancelación del launcher.
|
||||||
|
- No hay `setup.bat` separado (el doctor es el setup).
|
||||||
|
- No se instalan `[dev]` ni `[analysis]`: solo core + `[web]`, lo necesario
|
||||||
|
para correr la aplicación.
|
||||||
|
- Sin tests automatizados nuevos de PowerShell (el repo no tiene infra para
|
||||||
|
eso); verificación manual guiada por `-CheckOnly`.
|
||||||
|
|
||||||
|
## Verificación
|
||||||
|
|
||||||
|
- `doctor.ps1 -CheckOnly`: reporta qué haría sin cambiar nada (cada rama de
|
||||||
|
decisión observable sin efectos).
|
||||||
|
- Escenarios manuales: server ya vivo → solo navegador; server apagado →
|
||||||
|
arranque completo; stop limpio tras arranque; ventana persistente ante
|
||||||
|
error simulado (p. ej. PATH sin Python en un subproceso controlado).
|
||||||
Reference in New Issue
Block a user