Repository navigation
feat(providers): proveedor Antigravity con cuota por modelo del IDE - #207
Conversation
Antigravity no deja una sesión reutilizable en disco y su cuota es un
grupo propio, distinto del de Gemini CLI. El proveedor consulta el
servidor de lenguaje local que arranca el IDE (GetUserStatus, no
oficial): token CSRF desde la línea de comandos del proceso lanzado con
--app_data_dir antigravity y puerto HTTP desde language_server.log del
arranque actual (mismo pid). La petición va solo a 127.0.0.1 y el token
no se guarda.
Un medidor por modelo agrupando las variantes de esfuerzo (High/Medium/
Low), el más gastado primero; plan desde userTier.description. La
ventana (5 h o semanal) se deduce del tiempo hasta el reinicio. Con el
IDE cerrado el informe queda en Warning con instrucciones.
Config AntigravityConfig { enabled } (sin cuentas adicionales), pestaña
en Ajustes, tipos TS, visibilidad, dataKey, i18n, monograma AG y filas
en los README.
|
@eichhorn-micaela muchas gracias por la contribución. El proveedor está bien planteado: viene desactivado por defecto, la consulta va solo a Antes de activar la revisión y los workflows de CI necesitamos estos cambios: 1. Ventana mal deducida cerca del reinicio (
|
…instante Una cuota semanal a la que le quedan menos de 5 h para el reinicio se clasificaba como ventana de 5 h, con ventana y ritmo incorrectos en sus últimas horas. Ahora la ventana sale de señales fiables: más de 5 h hasta el reinicio solo puede ser semanal; un reinicio ya visto conserva la ventana deducida entonces (memoria en proceso por medidor); un reinicio que cambió y cae dentro de 5 h es una ventana de 5 h; y los modelos con el mismo resetTime exacto comparten ventana. Sin ninguna señal, window_seconds queda en None. Tests del borde semanal con menos de 5 h, del aprendizaje de 5 h por reinicio cambiado, del grupo y de reinicios lejanos o pasados. Refs: feedback de review en egdev6#207
… documentado Indica en los README y en la pestaña de Ajustes que por ahora solo se verificó en Windows, y añade Antigravity (GetUserStatus interno) al aviso de endpoints no documentados. Refs: feedback de review en egdev6#207
Conflicto en Settings.tsx: main movió los paneles de suscripción a componentes con catálogos ES/EN; la sección de Antigravity pasa a AntigravityPanel con sus claves en es.ts/en.ts. docs/i18n-inventory.md se toma de main y se regenera aparte.
|
Gracias por la revisión. Apliqué los tres puntos:
El inventario i18n está regenerado en 78392f4. Además integré Verificación local tras el merge: |
…aneles Mismo patrón que el resto de paneles migrados en C1b (egdev6#217): español verbatim con locale es e inglés sin restos de español con locale en. Refs: coordinación C1b / egdev6#207
|
Sobre la coordinación con C1b: como #217 entró antes, el panel de Antigravity ya está migrado a los catálogos ES/EN ( Para completar el patrón, en 8ff9070 añadí sus casos a
El panel no usa Verificación: |
|
@eichhorn-micaela gracias por los cambios. Los avisos de Windows y del endpoint interno están resueltos, y la migración de Por ejemplo, todo en UTC: el 27 de octubre a las 15:37 se observa un reinicio semanal del 29 de octubre a las 18:37 y se aprende ¿Puedes añadir ese caso de salto semanal tras una pausa y hacer la inferencia conservadora cuando falte evidencia? En una transición ambigua es preferible |
…nsultas Un reinicio que cambia y cae dentro de 5 h solo demuestra una ventana de 5 h si la consulta anterior es reciente. Si el reinicio cambió, la ventana nueva empezó después de esa consulta; una semanal acabaría al menos 7 días después de ella y no podría quedarle ≤ 5 h antes de 7 días − 5 h. Ahora se guarda cuándo se vio cada reinicio y, tras una pausa mayor (Antigravity cerrado), la transición es ambigua y queda en None en vez de aprender 5 h. Tests: el salto semanal tras una pausa (27 oct → 5 nov) del review y la cota del intervalo a ambos lados del límite. Refs: feedback de review en egdev6#207
|
Hola @eichhorn-micaela, gracias por la contribución. He revisado el commit
Validación: las 13 pruebas del proveedor y 3 del modelo pasan en un harness aislado. Las tres pruebas adicionales que exigen aislamiento del proxy, coincidencia exacta del PID y delimitación del bloque fallan y reproducen los problemas anteriores. No ejecuté la suite completa ni hice una prueba con el IDE real. ¿Puedes añadir estas regresiones junto con las correcciones? |
…del log de otros procesos P1: la consulta usaba el cliente HTTP compartido, que respeta HTTP_PROXY/ALL_PROXY; sin un NO_PROXY que excluya loopback, el token X-Codeium-Csrf-Token llegaba al proxy aunque la URL fuese 127.0.0.1. Ahora va con un cliente dedicado (local_client) con no_proxy(), sin seguir redirecciones y con timeout propio. P2: http_port buscaba «pid N» como subcadena (pid 123 coincidía con pid 1234) y, si el bloque de ese pid no tenía puerto HTTP, seguía por los arranques posteriores. Ahora compara el pid completo del marcador de arranque y solo mira su bloque, hasta el siguiente «Starting…». Regresiones (RED observado antes del arreglo): pid exacto, bloque delimitado, proxy configurado que no recibe la consulta y redirección que no se sigue, con servidores de prueba en loopback. Refs: feedback de review en egdev6#207
|
Hola @eichhorn-micaela, he revisado el head En la comprobación local pasan los 17 tests de Antigravity, los 788 tests del frontend, TypeScript y el inventario i18n. No he probado el IDE real en Windows ni ejecutado la suite Rust completa; tampoco pude comprobar el formato porque el entorno no tiene ¡Muchas gracias por aportar el proveedor Antigravity y por atender las revisiones con sus pruebas de regresión! |
|
Gracias por la revisión. Los dos puntos eran correctos y están corregidos en 1d7c4c8, con sus regresiones. Antes de arreglarlos vi fallar cada test por el motivo que describiste. P1 · Proxy. La consulta ya no usa el cliente compartido. Va con un cliente dedicado (
Probé el proxy configurándolo en el builder, no con variables de entorno, para no mutar el entorno global en tests que corren en paralelo. P2 · Puerto.
Verificación
|
…nes) en feat/wsl-adapter Trae a la rama de la PR el main vigente de egdev6/quorb (f3897bc, incluye egdev6#207 y egdev6#219). docs/i18n-inventory.md se regenera desde el árbol fusionado en un commit aparte para que el header refleje el head real. Co-Authored-By: Claude Code <noreply@anthropic.com>
1. shell_strategy no confunde error WSL con ausencia de Bash: `control_raw` devuelve el output crudo, así que se clasifica con `errors::classify`: si la salida contiene un token WSL reconocido (p. ej. WSL_E_DISTRO_NOT_FOUND porque la distro desapareció entre la enumeración y la sonda), se propaga el error real en vez de caer a `ShPosix` como estrategia válida. El fallback a `ShPosix` queda solo para el caso normal `command -v` sin bash (salida vacía, sin token). Regresión: shell_strategy_propagates_wsl_distro_loss_not_sh_posix. 2. kill_remote_process no escala tras observar la muerte: si una sonda `kill -0` ve el PID muerto, se rompe y NO se vuelve a comprobar ni se envía KILL (un `kill -0` posterior podría devolver 0 porque el PID fue reutilizado por otro proceso — señalizar al proceso equivocado). La identidad de la instancia se protege observando la desaparición, no volviendo a preguntar por el número. Test determinista case_disappears_then_reappears: PID que desaparece y reaparece con otra identidad → no recibe KILL. 3. session_path usa semántica del GUEST (POSIX), no del host Windows: `Path::is_absolute()` en Windows devuelve false para `/home/u/...` y true para `C:\...`, justo al revés del guest. Nuevo helper `is_guest_absolute` (empieza por `/`) y tests: una ruta Windows explícita se rechaza en modo WSL, y `/etc/passwd` como relativa del proveedor se rechaza aunque en Windows no sea "absoluta". docs/i18n-inventory.md regenerado tras integrar main del upstream (incluye egdev6#207 y egdev6#219) y los cambios de este commit. Co-Authored-By: Claude Code <noreply@anthropic.com>
…#220) * ci(wsl): registrar el lab W3 en main para poder despacharlo El workflow w3-evidence.yml vive en w2-fase-a; GitHub solo ofrece para dispatch los workflows presentes en la rama por defecto del repo. Se añade aquí (mismo contenido, sin cambios) para que aparezca en el desplegable de "Run workflow" del fork y se pueda lanzar con ref=w2-fase-a. Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(w3-lab): usar windows-2022 (windows-latest ya no trae WSL) El run falló en el primer paso: `windows-latest` es ahora la imagen windows-2025-vs2026, sin WSL instalado. Las imágenes con WSL preinstalado son windows-2022 y windows-2019 (el lab W0 corrió en la que entonces era latest). Se fija windows-2022 y se añade una comprobación explícita de WSL al inicio, para que su ausencia se reporte con un mensaje claro en vez de un exit code opaco. Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(w3-lab): windows-latest + sonda --version + exit 0 (igual a la rama) Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(w3-lab): sha256 a fichero (PS7 .Content es byte[]) — igual a la rama Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(w3-lab): veredicto global + evidencia always() (igual a la rama) Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(w3-lab): volcado del import al log (igual a la rama) Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(w3-lab): import con directorio creado (igual a la rama) Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(w3-lab): Gap 1 con testigo (igual a la rama) Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(w3-lab): senal de fichero + .wslconfig (igual a la rama) Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(w3-lab): configurar WSL del runner (igual a la rama) Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(w3-lab): shift antes del exec (igual a la rama) Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(w3-lab): background + EXIT aparte (igual a la rama) Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(w3-lab): Start-Job para el launch (igual a la rama) Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(w3-lab): sleep 1 + diagnostico en vivo (igual a la rama) Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(w3-lab): background dentro de la distro (igual a la rama) Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(w3-lab): redireccion en una linea (igual a la rama) Co-Authored-By: Claude Code <noreply@anthropic.com> * feat(w3-lab): Gap 1b (igual a la rama) Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(w3-lab): script a fichero en Gap 1b (igual a la rama) Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(w3-lab): vmIdleTimeout=-1 (igual a la rama) Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(w3-lab): veredicto global solo por Gap 2 (igual a la rama) Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(w3-lab): Gap 1b continue-on-error (igual a la rama) Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(w3-lab): Stop-Process tolerante (igual a la rama) Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(w3-lab): caso empty como string (igual a la rama) Co-Authored-By: Claude Code <noreply@anthropic.com> * feat(w3-lab): probar Ubuntu con systemd (igual a la rama) Co-Authored-By: Claude Code <noreply@anthropic.com> * feat(w3-lab): Ubuntu por wsl --install (igual a la rama) Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(w3-lab): desactivar OOBE de Ubuntu (igual a la rama) Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(w3-lab): restaurar list-after (igual a la rama) Co-Authored-By: [CC] <noreply@anthropic.com> * feat(wsl): adaptador WSL (Fase A+B) + lab W3 de evidencia — issue #90 Trasplanta a main el contrato `WslAdapter` y su implementación real contra `wsl.exe`, junto con el lab W3 que lo acredita con WSL real: - src-tauri/src/wsl/: Fase A (mod.rs contrato + mock determinista, errors.rs) y Fase B (real.rs RealWslAdapter, process.rs lanzador con cancelación acotada nivel 1). Solo depende de cli_process + std. - lib.rs: expone `pub mod wsl`. - src-tauri/examples/wsl-wslenv-probe.rs: harness que mide WSLENV por el lanzamiento real del adaptador (run_command -> env_with -> ProcessRunner con env_clear().envs()); no es un binario del producto. - .github/workflows/w3-evidence.yml + scripts/wsl-f14-probe.rs: el lab de evidencia — Gap 1 (pidfile endurecido, kill acotado, testigo ajeno), Gap 1b (timeout del host), Gap 2 (F14 doble frontera por la vía real) y Gap 3 (WSLENV por el adaptador real, allowlist x ramas + no-duplicar). El lab ejercita el código real y en WSL real destapó y corrigió un bug de shell_strategy (exec no ejecuta builtins -> SCRIPT_COMMAND_V). Incluye el Caso I estricto (debe escalar a KILL) y el contrato nonpath=ausente. Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(wsl): corregir borrow de runner en test, retoques de review y i18n (#90) - real.rs: el test shell_strategy_uses_command_v_script_not_exec movía `runner` en `adapter(runner)` y luego leía `runner.calls()` (E0382 del CI). FakeRunner ya deriva Clone (Arc<Mutex>), así que se pasa `runner.clone()` y el test conserva el acceso a las llamadas reales. - real.rs: eliminar `let mut args = args;` redundante en list_distributions_uses_verbose_list_without_distro. - wsl-wslenv-probe.rs: documentar en parse_env la limitación del salto de línea en el formato `env` (valores con `=` se conservan enteros). - docs/i18n-inventory.md: regenerado (el módulo wsl/ añade textos i18n). Hallazgo de revisión descartado tras verificación: `exec "$@"` con `$@` entrecomillado NO re-evalúa $(...) en los posicionales (confirmado en shell real); no hay inyección por variables de entorno, y read_file usa run_scoped a propósito para conservar la cancelación acotada. Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(wsl): aplicar los 3 hallazgos de la revisión PR #220 1. shell_strategy no confunde error WSL con ausencia de Bash: `control_raw` devuelve el output crudo, así que se clasifica con `errors::classify`: si la salida contiene un token WSL reconocido (p. ej. WSL_E_DISTRO_NOT_FOUND porque la distro desapareció entre la enumeración y la sonda), se propaga el error real en vez de caer a `ShPosix` como estrategia válida. El fallback a `ShPosix` queda solo para el caso normal `command -v` sin bash (salida vacía, sin token). Regresión: shell_strategy_propagates_wsl_distro_loss_not_sh_posix. 2. kill_remote_process no escala tras observar la muerte: si una sonda `kill -0` ve el PID muerto, se rompe y NO se vuelve a comprobar ni se envía KILL (un `kill -0` posterior podría devolver 0 porque el PID fue reutilizado por otro proceso — señalizar al proceso equivocado). La identidad de la instancia se protege observando la desaparición, no volviendo a preguntar por el número. Test determinista case_disappears_then_reappears: PID que desaparece y reaparece con otra identidad → no recibe KILL. 3. session_path usa semántica del GUEST (POSIX), no del host Windows: `Path::is_absolute()` en Windows devuelve false para `/home/u/...` y true para `C:\...`, justo al revés del guest. Nuevo helper `is_guest_absolute` (empieza por `/`) y tests: una ruta Windows explícita se rechaza en modo WSL, y `/etc/passwd` como relativa del proveedor se rechaza aunque en Windows no sea "absoluta". docs/i18n-inventory.md regenerado tras integrar main del upstream (incluye #207 y #219) y los cambios de este commit. Co-Authored-By: Claude Code <noreply@anthropic.com> * docs(i18n): regenerar el inventario tras los cambios de src-tauri/src El gate compara el hash del árbol `src-tauri/src/` con el declarado, así que los cambios de los 3 hallazgos lo dejaban desactualizado (aunque los textos no hubieran cambiado). Regenerado desde el árbol actual. Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(wsl): identidad de instancia en el pidfile y rutas POSIX (#90) Revisión del mantenedor (2026-11-02), dos puntos: 1. Identidad del proceso. El pidfile guardaba solo el número de PID; entre leerlo y el primer kill, un PID reutilizado por otro proceso de la distro habría recibido TERM/KILL ajeno. Ahora la instancia publica un TOKEN (sufijo aleatorio del directorio) en `token` y el proceso final lo hereda como `QUORB_WSL_TOKEN` vía `exec`. Antes de señalar se comprueba que `/proc/<pid>/environ` contiene el token (fail-closed: identidad no verificada -> no se señala; recuperación explícita del nivel 2). Con regresión: identidad cambiada sin que ninguna sonda observe el PID ausente -> no TERM, no KILL. 2. Rutas con semántica del host. `session_path` componía con `Path::join`, que en Windows introduce `\` en una ruta que viaja literal al `cat` de la distro (Linux): allí `\` no separa nada y se buscaría otro fichero. Ahora se compone con separador `/` (join_guest_path) y se rechazan con `InvalidArgument` las rutas explícitas o relativas que lleven `\`. Tests que fijan el argumento exacto en cualquier plataforma. Co-Authored-By: Claude Code <noreply@anthropic.com> * docs(i18n): regenerar el inventario tras los mensajes POSIX/identidad Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(wsl): ligar la comprobación de identidad al TERM y al KILL (#90) Bloqueo de la revisión del mantenedor (2026-11-03): la identidad se comprobaba antes del TERM, pero durante la espera solo se consultaba `kill -0` y el KILL final se enviaba sin volver a comprobar. Si el proceso original moría y su PID se reutilizaba entre sondas, el nuevo dueño recibía el KILL. La comprobación y el envío van ahora en UNA sola invocación (`SCRIPT_SIGNAL_IF_IDENTITY`: `tr … | grep -qxF … && kill -<señal> <pid>`), también para la escalada: no hay proceso de verificación separado que deje ventana entre verificar y señalizar, y si el PID fue reutilizado el grep falla y no se envía nada (fail-closed). Regresión determinista añadida: identidad correcta → TERM → el original muere y el PID se reutiliza entre sondas (todas las `kill -0` ven vivo) → la escalada re-verifica y el proceso nuevo NO recibe KILL. Co-Authored-By: Claude Code <noreply@anthropic.com> * docs(i18n): regenerar el inventario tras el KILL ligado a identidad Co-Authored-By: Claude Code <noreply@anthropic.com> --------- Co-authored-by: Claude Code <noreply@anthropic.com>
* ci(wsl): registrar el lab W3 en main para poder despacharlo El workflow w3-evidence.yml vive en w2-fase-a; GitHub solo ofrece para dispatch los workflows presentes en la rama por defecto del repo. Se añade aquí (mismo contenido, sin cambios) para que aparezca en el desplegable de "Run workflow" del fork y se pueda lanzar con ref=w2-fase-a. Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(w3-lab): usar windows-2022 (windows-latest ya no trae WSL) El run falló en el primer paso: `windows-latest` es ahora la imagen windows-2025-vs2026, sin WSL instalado. Las imágenes con WSL preinstalado son windows-2022 y windows-2019 (el lab W0 corrió en la que entonces era latest). Se fija windows-2022 y se añade una comprobación explícita de WSL al inicio, para que su ausencia se reporte con un mensaje claro en vez de un exit code opaco. Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(w3-lab): windows-latest + sonda --version + exit 0 (igual a la rama) Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(w3-lab): sha256 a fichero (PS7 .Content es byte[]) — igual a la rama Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(w3-lab): veredicto global + evidencia always() (igual a la rama) Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(w3-lab): volcado del import al log (igual a la rama) Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(w3-lab): import con directorio creado (igual a la rama) Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(w3-lab): Gap 1 con testigo (igual a la rama) Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(w3-lab): senal de fichero + .wslconfig (igual a la rama) Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(w3-lab): configurar WSL del runner (igual a la rama) Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(w3-lab): shift antes del exec (igual a la rama) Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(w3-lab): background + EXIT aparte (igual a la rama) Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(w3-lab): Start-Job para el launch (igual a la rama) Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(w3-lab): sleep 1 + diagnostico en vivo (igual a la rama) Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(w3-lab): background dentro de la distro (igual a la rama) Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(w3-lab): redireccion en una linea (igual a la rama) Co-Authored-By: Claude Code <noreply@anthropic.com> * feat(w3-lab): Gap 1b (igual a la rama) Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(w3-lab): script a fichero en Gap 1b (igual a la rama) Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(w3-lab): vmIdleTimeout=-1 (igual a la rama) Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(w3-lab): veredicto global solo por Gap 2 (igual a la rama) Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(w3-lab): Gap 1b continue-on-error (igual a la rama) Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(w3-lab): Stop-Process tolerante (igual a la rama) Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(w3-lab): caso empty como string (igual a la rama) Co-Authored-By: Claude Code <noreply@anthropic.com> * feat(w3-lab): probar Ubuntu con systemd (igual a la rama) Co-Authored-By: Claude Code <noreply@anthropic.com> * feat(w3-lab): Ubuntu por wsl --install (igual a la rama) Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(w3-lab): desactivar OOBE de Ubuntu (igual a la rama) Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(w3-lab): restaurar list-after (igual a la rama) Co-Authored-By: [CC] <noreply@anthropic.com> * feat(wsl): adaptador WSL (Fase A+B) + lab W3 de evidencia — issue #90 Trasplanta a main el contrato `WslAdapter` y su implementación real contra `wsl.exe`, junto con el lab W3 que lo acredita con WSL real: - src-tauri/src/wsl/: Fase A (mod.rs contrato + mock determinista, errors.rs) y Fase B (real.rs RealWslAdapter, process.rs lanzador con cancelación acotada nivel 1). Solo depende de cli_process + std. - lib.rs: expone `pub mod wsl`. - src-tauri/examples/wsl-wslenv-probe.rs: harness que mide WSLENV por el lanzamiento real del adaptador (run_command -> env_with -> ProcessRunner con env_clear().envs()); no es un binario del producto. - .github/workflows/w3-evidence.yml + scripts/wsl-f14-probe.rs: el lab de evidencia — Gap 1 (pidfile endurecido, kill acotado, testigo ajeno), Gap 1b (timeout del host), Gap 2 (F14 doble frontera por la vía real) y Gap 3 (WSLENV por el adaptador real, allowlist x ramas + no-duplicar). El lab ejercita el código real y en WSL real destapó y corrigió un bug de shell_strategy (exec no ejecuta builtins -> SCRIPT_COMMAND_V). Incluye el Caso I estricto (debe escalar a KILL) y el contrato nonpath=ausente. Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(wsl): corregir borrow de runner en test, retoques de review y i18n (#90) - real.rs: el test shell_strategy_uses_command_v_script_not_exec movía `runner` en `adapter(runner)` y luego leía `runner.calls()` (E0382 del CI). FakeRunner ya deriva Clone (Arc<Mutex>), así que se pasa `runner.clone()` y el test conserva el acceso a las llamadas reales. - real.rs: eliminar `let mut args = args;` redundante en list_distributions_uses_verbose_list_without_distro. - wsl-wslenv-probe.rs: documentar en parse_env la limitación del salto de línea en el formato `env` (valores con `=` se conservan enteros). - docs/i18n-inventory.md: regenerado (el módulo wsl/ añade textos i18n). Hallazgo de revisión descartado tras verificación: `exec "$@"` con `$@` entrecomillado NO re-evalúa $(...) en los posicionales (confirmado en shell real); no hay inyección por variables de entorno, y read_file usa run_scoped a propósito para conservar la cancelación acotada. Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(wsl): aplicar los 3 hallazgos de la revisión PR #220 1. shell_strategy no confunde error WSL con ausencia de Bash: `control_raw` devuelve el output crudo, así que se clasifica con `errors::classify`: si la salida contiene un token WSL reconocido (p. ej. WSL_E_DISTRO_NOT_FOUND porque la distro desapareció entre la enumeración y la sonda), se propaga el error real en vez de caer a `ShPosix` como estrategia válida. El fallback a `ShPosix` queda solo para el caso normal `command -v` sin bash (salida vacía, sin token). Regresión: shell_strategy_propagates_wsl_distro_loss_not_sh_posix. 2. kill_remote_process no escala tras observar la muerte: si una sonda `kill -0` ve el PID muerto, se rompe y NO se vuelve a comprobar ni se envía KILL (un `kill -0` posterior podría devolver 0 porque el PID fue reutilizado por otro proceso — señalizar al proceso equivocado). La identidad de la instancia se protege observando la desaparición, no volviendo a preguntar por el número. Test determinista case_disappears_then_reappears: PID que desaparece y reaparece con otra identidad → no recibe KILL. 3. session_path usa semántica del GUEST (POSIX), no del host Windows: `Path::is_absolute()` en Windows devuelve false para `/home/u/...` y true para `C:\...`, justo al revés del guest. Nuevo helper `is_guest_absolute` (empieza por `/`) y tests: una ruta Windows explícita se rechaza en modo WSL, y `/etc/passwd` como relativa del proveedor se rechaza aunque en Windows no sea "absoluta". docs/i18n-inventory.md regenerado tras integrar main del upstream (incluye #207 y #219) y los cambios de este commit. Co-Authored-By: Claude Code <noreply@anthropic.com> * docs(i18n): regenerar el inventario tras los cambios de src-tauri/src El gate compara el hash del árbol `src-tauri/src/` con el declarado, así que los cambios de los 3 hallazgos lo dejaban desactualizado (aunque los textos no hubieran cambiado). Regenerado desde el árbol actual. Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(wsl): identidad de instancia en el pidfile y rutas POSIX (#90) Revisión del mantenedor (2026-11-02), dos puntos: 1. Identidad del proceso. El pidfile guardaba solo el número de PID; entre leerlo y el primer kill, un PID reutilizado por otro proceso de la distro habría recibido TERM/KILL ajeno. Ahora la instancia publica un TOKEN (sufijo aleatorio del directorio) en `token` y el proceso final lo hereda como `QUORB_WSL_TOKEN` vía `exec`. Antes de señalar se comprueba que `/proc/<pid>/environ` contiene el token (fail-closed: identidad no verificada -> no se señala; recuperación explícita del nivel 2). Con regresión: identidad cambiada sin que ninguna sonda observe el PID ausente -> no TERM, no KILL. 2. Rutas con semántica del host. `session_path` componía con `Path::join`, que en Windows introduce `\` en una ruta que viaja literal al `cat` de la distro (Linux): allí `\` no separa nada y se buscaría otro fichero. Ahora se compone con separador `/` (join_guest_path) y se rechazan con `InvalidArgument` las rutas explícitas o relativas que lleven `\`. Tests que fijan el argumento exacto en cualquier plataforma. Co-Authored-By: Claude Code <noreply@anthropic.com> * docs(i18n): regenerar el inventario tras los mensajes POSIX/identidad Co-Authored-By: Claude Code <noreply@anthropic.com> * feat(wsl): resolver sesiones por el adaptador — SessionResolver (#91) El puente del camino 1: un resolvedor que sabe DÓNDE vive la sesión de un proveedor según el entorno (host Windows/macOS vs distro WSL) y CÓMO se lee — con `read_file` del adaptador (`wsl cat` con cancelación acotada) en WSL, o del disco local en host. Los proveedores no conocen WSL. Contrato de sesiones (#91): - Ruta explícita con prioridad; una inválida es error sin fallback. - Sin credenciales en el entorno elegido, nunca se usa una cuenta de otro entorno silenciosamente. - Errores tipados: Absent (necesita login), Unreadable, Invalid y Wsl (el fallo es del subsistema o la distro, no de la sesión) — la UI distingue "login" de "WSL roto". - No se copian tokens: cada entorno lee en su casa. Tests deterministas con MockWslAdapter: lectura en host y en distro, ausente en cada entorno, y fallo del subsistema propagado como WslError. 80 tests del módulo wsl pasan. Co-Authored-By: Claude Code <noreply@anthropic.com> * feat(wsl): resolver sesiones de los proveedores por entorno (#91) Cablea el SessionResolver en la lectura de uso: en host se mantiene el comportamiento de siempre (disco local, incluido el respaldo del Keychain de macOS); en WSL la sesión de cada CLI (Claude, Codex, Gemini, Grok) se resuelve y se lee DENTRO de la distro, con el home de su default user resuelto por el adaptador (F7). El fichero de sesión por proveedor tiene una sola fuente (credentials_file_name) para que host y WSL compongan la misma ruta relativa. Si el entorno configurado no se puede resolver (WSL sin instalar, distro ausente), el orbe muestra un error explícito de WSL: nunca se cae a una cuenta de otro entorno. Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(wsl): lecturas del entorno WSL en hilos propios + sello de la distro (#91) Revisión PR #220 (HIGH): el adaptador es síncrono y las lecturas de sesión esperan a wsl.exe (hasta 20 s cada una); hacerlas en el executor async congelaba el widget con varias cuentas. El resolvedor pasa a `Arc<dyn WslAdapter>` y expone `read_async` (spawn_blocking); resolve_home también va en hilo propio. El crate ya usaba este patrón (claude.rs, antigravity.rs). El sello de sesiones (session_stamp) también observa el entorno: en WSL se lee el contenido de los ficheros dentro de la distro (misma fuente que los fetch: credentials_path > home del entorno) y se suma su huella, de modo que un login dentro de la distro refresca el widget aunque el host no tenga mtime accesible. Co-Authored-By: Claude Code <noreply@anthropic.com> * docs(wsl): espacio en el doc de Arc del SessionResolver (review 2º pase) Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(wsl): método del trait en scope y Result en el sello (CI real) Dos errores que solo aparecieron al compilar el crate completo en CI (el harness aislado no incluye lib.rs, que necesita Tauri): - E0599: `resolve_home` es un método del trait WslAdapter, no inherente; con el adaptador en `Arc` el trait tenía que estar en scope para el auto-deref. - E0277: al pasar `session_stamp` a async, Tauri exige que los commands async con `State` devuelvan Result (el futuro vive más que el borrow). Co-Authored-By: Claude Code <noreply@anthropic.com> * style(wsl): rustfmt en el import del trait en lib.rs Co-Authored-By: Claude Code <noreply@anthropic.com> * style: lints de clippy del alcance del milestone - wsl/real.rs y wsl/process.rs: doc comments sin línea vacía / sin indentación de lista (empty_line_after_doc_comments, doc_lazy_continuation). - config.rs: el test de session_env inicializa el struct en vez de reasignar campos (field_reassign_with_default). El resto de lints que reporta clippy son preexistentes de main y el CI del proyecto no ejecuta clippy. Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(wsl): rutas POSIX en el resolvedor y caché del home por distro (#91) Revisión del mantenedor (2026-11-02) aplicada a la PR de #91: - `SessionResolver::default_path` componía con `Path::join`, que en Windows introduce `\` en una ruta que viaja literal al `cat` de la distro (Linux, donde `\` no separa nada). Ahora usa `join_guest_path` (semántica POSIX) con test del argumento exacto en cualquier plataforma. - `session_stamp` se consulta cada 15 s y cada consulta resolvía el home de la distro con dos procesos wsl.exe (`resolve_home`), manteniendo la VM de WSL potencialmente siempre activa. Nuevo `WslHomeCache` en AppState: el home se resuelve una vez por distro y se invalida solo al cambiar la distro configurada. Co-Authored-By: Claude Code <noreply@anthropic.com> * docs(i18n): regenerar el inventario tras caché y POSIX del resolvedor Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(wsl): ligar la comprobación de identidad al TERM y al KILL (#90) Bloqueo de la revisión del mantenedor (2026-11-03): la identidad se comprobaba antes del TERM, pero durante la espera solo se consultaba `kill -0` y el KILL final se enviaba sin volver a comprobar. Si el proceso original moría y su PID se reutilizaba entre sondas, el nuevo dueño recibía el KILL. La comprobación y el envío van ahora en UNA sola invocación (`SCRIPT_SIGNAL_IF_IDENTITY`: `tr … | grep -qxF … && kill -<señal> <pid>`), también para la escalada: no hay proceso de verificación separado que deje ventana entre verificar y señalizar, y si el PID fue reutilizado el grep falla y no se envía nada (fail-closed). Regresión determinista añadida: identidad correcta → TERM → el original muere y el PID se reutiliza entre sondas (todas las `kill -0` ven vivo) → la escalada re-verifica y el proceso nuevo NO recibe KILL. Co-Authored-By: Claude Code <noreply@anthropic.com> * docs(i18n): regenerar el inventario tras el KILL ligado a identidad Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(wsl): rutas POSIX en cuentas adicionales y validación de la explícita (#91) Revisión del mantenedor (2026-11-04), dos defectos de rutas solo reproducibles en Windows: 1. Cuentas adicionales ilegibles en WSL. La ruta se componía con `PathBuf::join`, que en Windows inserta `\` en el interior, y `join_guest_path` solo normalizaba la frontera: el guest recibía `/home/u/.quorb\accounts\…` y la cuenta quedaba «Sin sesión» sin error visible. Ahora `account_session_path` compone con POSIX en todo el recorrido; un `config_dir` absoluto del guest se usa tal cual (sin re-enraizar) y lo que no sea POSIX (separadores de Windows o rutas relativas) se rechaza con un error de configuración accionable, que en `fetch_account` se convierte en el report de la cuenta sin tocar la red. Regresión del WslCall exacto en `wsl_session_stamp`. 2. La ruta explícita no se validaba como ruta del guest. `resolve` devolvía `PathBuf::from(explicit)` tal cual: la UNC que sugiere Ajustes (`\\wsl.localhost\…`) viajaba literal al `cat`, fallaba como «no existe» y se mostraba «Sin sesión» ocultando un error de configuración. `resolve` devuelve ahora `Result` y en WSL valida la ruta (POSIX absoluta del guest); los proveedores mapean `Invalid` a un error explícito y el sello omite la ruta inválida. Co-Authored-By: Claude Code <noreply@anthropic.com> * docs(i18n): regenerar el inventario tras POSIX de cuentas y explícita (#91) Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(wsl): rutas del guest con separador POSIX en todo el recorrido (#91) El CI de Windows confirmó el defecto de la revisión (2026-11-04): el `Path::join` interno inserta `\` también entre componentes (`.quorb\.credentials.json`), no solo en la frontera. Los proveedores componían sus rutas por defecto con `Path::new(".claude").join(...)`. Nuevo `guest_relative` (una sola fuente): compone la relativa del guest con `/` en cualquier plataforma, sin `Path::join`. Se usa en los cuatro proveedores, en la composición de cuentas adicionales (`fetch_account` y `wsl_session_stamp`) y en los tests. Regresión que fija el string POSIX exacto y el `WslCall` de la cuenta adicional. Co-Authored-By: Claude Code <noreply@anthropic.com> * docs(i18n): regenerar el inventario tras guest_relative (#91) Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(wsl): proveedores sin CLI y layout por defecto en WSL (#91) Review rust (2026-11-04): - HIGH: `account_session_path` cortaba también las cuentas de proveedores SIN login por CLI (openrouter, zai, nan, copilot…) en modo WSL, porque el lookup del fichero se evaluaba antes del match por proveedor. Ahora los proveedores sin sesión CLI devuelven `Ok(None)` y su fetch normal sigue usando su token. - MEDIUM (documentado): sin `config_dir`, dos cuentas del mismo proveedor comparten `~/.quorb/<fichero>` (igual que en host); el aislamiento real lo da el config_dir de Ajustes. Test que fija el layout y el choque. - Menores: `trim_end_matches('/')` en config_dir; `guest_relative` solo en tests (sin warning en el build no-test). Co-Authored-By: Claude Code <noreply@anthropic.com> * docs(i18n): regenerar el inventario tras retirar el mensaje de "sin login CLI" Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(wsl): layout host para cuentas por defecto y fuentes únicas (#91) Revisión del mantenedor (2026-11-06): - BLOQUEANTE resuelto: la carpeta por defecto de las cuentas adicionales en WSL es ahora la MISMA que en host — home_dir del canal + `accounts/<provider>-<suffix>` + fichero, con POSIX del guest. Dos cuentas del mismo proveedor sin config_dir ya no comparten `~/.quorb/<fichero>` (el aislamiento que declara wsl/session.rs) y los canales con otro home_dir no divergen. El test que fijaba el comportamiento compartido se invierte (`default_extra_accounts_are_ isolated_without_config_dir`). - Menor 1: la regla «absoluta del guest y sin \» vive en UNA sola fuente (`wsl::guest_path_problem`), usada por `SessionResolver::resolve`, `wsl::session_path` y `account_session_path`. - Menor 2: las rutas de los proveedores principales salen de una única fuente (`provider_session_relative`) usada por los cuatro fetch y por `wsl_session_stamp` (ya no se repiten a mano). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * docs(i18n): regenerar el inventario tras layout host y fuentes únicas (#91) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * docs(i18n): regenerar el inventario tras integrar main (#239) --------- Co-authored-by: Claude Code <noreply@anthropic.com> Co-authored-by: egdev6 <egdev6@gmail.com>
Issue relacionada
Issue: no hay issue previa (contribución de un proveedor nuevo).
ODD: no aplica.
Alcance
Nuevo proveedor Antigravity (IDE de Google): cuota del agente por modelo, la misma que muestra el panel de cuotas del IDE.
oauth_creds.jsoncomo en Gemini CLI) y su cuota es un grupo propio, distinto del de Gemini CLI. Por eso no sirve reutilizar el proveedor Gemini.POST http://127.0.0.1:<puerto>/exa.language_server_pb.LanguageServerService/GetUserStatus(endpoint no oficial).--csrf_tokendel procesolanguage_serverlanzado con--app_data_dir antigravity. Así se descartan Windsurf y otros IDEs que usan el mismo binario. Sin el token, el servidor responde 401.listening on random port at N for HTTPdelanguage_server.log, solo si pertenece al arranque del mismo pid.127.0.0.1y el token no se persiste.userTier.description(p. ej. «Google AI Pro»). La ventana (5 h o semanal) se deduce del tiempo que falta para el reinicio, porque la respuesta no la incluye.Warningcon instrucciones, sin error.AntigravityConfig { enabled }, pestaña en Ajustes, tipos TS, visibilidad,dataKey, i18n, monogramaAG,OFFICIAL_USAGE_URLy filas en los README.Exclusiones: sin cuentas adicionales (en la máquina hay una sola sesión del IDE, así que no se añade a
ACCOUNT_PROVIDERS). En Windows, el proceso se descubre conGet-CimInstance, sin ventana. Linux/macOS usanpsy la carpeta de configuración del SO, pero solo se probó en Windows.Coordinación
Contribuidor: @eichhorn-micaela
Evidencia de asignación o acuerdo: N/A
Aceptación y validación
fetchreal devolvióOk, plan «Google AI Pro» y 5 medidores (Claude Opus 5.5, Claude Sonnet 5.5, GPT-OSS 120B, Gemini 3.8 Flash con ventana de 5 h; Gemini 4 Argon con ventana semanal).cargo test --locked: 335 OK (7 nuevos enproviders::antigravity; base 328), 1 ignorado preexistente.cargo fmt --all -- --check: limpio.cargo clippy --all-targets: sin avisos en el código nuevo.npm run typecheck: limpio.vitest run --dir src: 731 OK.node scripts/i18n-inventory.mjs --check: OK (inventario regenerado en un commit aparte).npm run app:build: OK, generaQuorb_0.8.0_x64-setup.exey el.msi.scripts/setup-signing.test.mjsfallan en local conEPERMal crear symlinks (Windows sin modo desarrollador). Son ajenos a este cambio. No se probó en Linux/macOS.