Repository navigation
feat(wsl): sesiones de proveedores por el adaptador — issue #91 - #239
Conversation
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>
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>
Co-Authored-By: Claude Code <noreply@anthropic.com>
Co-Authored-By: Claude Code <noreply@anthropic.com>
Co-Authored-By: Claude Code <noreply@anthropic.com>
Co-Authored-By: Claude Code <noreply@anthropic.com>
Co-Authored-By: Claude Code <noreply@anthropic.com>
Co-Authored-By: Claude Code <noreply@anthropic.com>
Co-Authored-By: Claude Code <noreply@anthropic.com>
Co-Authored-By: Claude Code <noreply@anthropic.com>
Co-Authored-By: Claude Code <noreply@anthropic.com>
Co-Authored-By: Claude Code <noreply@anthropic.com>
Co-Authored-By: Claude Code <noreply@anthropic.com>
Co-Authored-By: Claude Code <noreply@anthropic.com>
Co-Authored-By: Claude Code <noreply@anthropic.com>
Co-Authored-By: Claude Code <noreply@anthropic.com>
Co-Authored-By: Claude Code <noreply@anthropic.com>
Co-Authored-By: Claude Code <noreply@anthropic.com>
Co-Authored-By: Claude Code <noreply@anthropic.com>
Co-Authored-By: Claude Code <noreply@anthropic.com>
Co-Authored-By: Claude Code <noreply@anthropic.com>
Co-Authored-By: Claude Code <noreply@anthropic.com>
Co-Authored-By: Claude Code <noreply@anthropic.com>
Co-Authored-By: Claude Code <noreply@anthropic.com>
Co-Authored-By: Claude Code <noreply@anthropic.com>
Co-Authored-By: Claude Code <noreply@anthropic.com>
Co-Authored-By: [CC] <noreply@anthropic.com>
…ev6#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>
# Conflicts: # docs/i18n-inventory.md
# Conflicts: # docs/i18n-inventory.md
…6#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>
Co-Authored-By: Claude Code <noreply@anthropic.com>
# Conflicts: # docs/i18n-inventory.md
# Conflicts: # docs/i18n-inventory.md # src-tauri/src/wsl/mod.rs # src-tauri/src/wsl/process.rs # src-tauri/src/wsl/real.rs
|
Gracias por la PR, @sosan. El diseño está bien pensado y se nota el trabajo: separar el resolvedor de los proveedores, no caer a otro entorno y sacar la lectura del executor son decisiones correctas. Los cinco checks pasan. Aun así, antes de integrar hay dos defectos de rutas que conviene resolver. 1. Las cuentas adicionales quedan ilegibles en WSL. En 2. La ruta explícita no se valida como ruta del invitado. Los dos son solo reproducibles en Windows en runtime, y por eso los tests de Linux y macOS no los ven. El test Puntos menores, sin bloquear:
Lo que verifiqué correcto: con Esta revisión fue estática, y el contraste de evidencia fue la CI del head. No ejecuté el código de la PR ni reproduje los dos defectos en una distro real. |
…cita (egdev6#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>
…egdev6#91) Co-Authored-By: Claude Code <noreply@anthropic.com>
…gdev6#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>
Co-Authored-By: Claude Code <noreply@anthropic.com>
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>
…ogin CLI" Co-Authored-By: Claude Code <noreply@anthropic.com>
|
Gracias por la revisión, @egdev6 — los dos defectos de rutas están corregidos y, además, tu hallazgo se reprodujo en la CI: el primer arreglo falló en Windows con 1. Cuentas adicionales en WSL.
2. La ruta explícita se valida como ruta del invitado.
Review de la skill (adicional a la tuya), ya absorbida:
Regresiones (harness 170/170 + los cinco checks de la PR en verde, Windows incluido): Puntos menores, decididos:
Head actual: |
|
Gracias por los cambios, @sosan. Los dos defectos de rutas quedaron bien resueltos: Queda un bloqueo, introducido por el arreglo: la carpeta por defecto de las cuentas adicionales en WSL no es la misma que en host.
Hay dos consecuencias:
Propuesta: que WSL componga la misma ruta que host ( Menores, sin bloquear:
Las decisiones sobre los puntos menores anteriores (distro vacía tratada como host, UI de Ajustes pendiente, Esta revisión fue estática sobre |
# Conflicts: # docs/i18n-inventory.md
…v6#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>
…egdev6#91) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
egdev6
left a comment
There was a problem hiding this comment.
Gracias, @sosan. Revisé el head 44d7a02 y el bloqueo de la ronda anterior está resuelto: las cuentas adicionales en WSL componen la misma ruta que host (home_dir del canal + accounts/<provider>-<suffix>), y el test ahora exige rutas distintas para dos cuentas. También quedaron en una sola fuente la regla POSIX (guest_path_problem) y las rutas de los proveedores (provider_session_relative).
Apruebo la PR. Antes de integrarla faltan dos cosas:
- Conflicto con
mainendocs/i18n-inventory.md. Es generado: basta con mergearmainy regenerarlo connode scripts/i18n-inventory.mjs. - CI sobre el head. Con el conflicto, los workflows no corrieron sobre los cambios de hoy; los últimos checks son de
a3e02c8. Integro cuando los cinco estén en verde, en especial Windows, que es donde aparecían los defectos de rutas.
Los puntos menores pendientes (regresión directa del WslCall en fetch_account, UI de sessionEnv/wslDistro, costo del sello, distro vacía y el expect de provider_session_relative) quedan como seguimiento en #243.
Revisión estática sobre el diff y el código del head; no ejecuté la PR en una distro real.
# Conflicts: # docs/i18n-inventory.md
|
Gracias por la revisión, @egdev6 — los dos defectos de rutas están corregidos y, además, tu hallazgo se reprodujo en la CI: el primer arreglo falló en Windows con 1. Cuentas adicionales en WSL.
2. La ruta explícita se valida como ruta del invitado.
Review de la skill (adicional a la tuya), ya absorbida:
Regresiones (harness 170/170 + los cinco checks de la PR en verde, Windows incluido): Puntos menores, decididos:
Head actual: |
PR encadenada sobre #220 (ya en
main). Implementa la resolución de sesiones de los proveedores por entorno (issue #91): en host se mantiene el comportamiento de siempre y en WSL cada CLI lee su sesión dentro de la distro, por el adaptador de #90.Alcance
SessionResolver(wsl/session.rs): decide dónde está la sesión según el entorno y cómo se lee, sin que los proveedores conozcan WSL.credentials_path) > ruta por defecto del entorno.read_asynccorre la lectura en hilo propio (spawn_blocking): la espera awsl.exeno bloquea el executor.claude,codex,gemini,grok) y de las cuentas adicionales: la carpeta de cada cuenta se compone sobre el home del entorno elegido. Mapeo de errores:Absent → NeedsLogin, fallo del subsistema →Errorcon el detalle de WSL.session_env(host/wsl) ywsl_distroenAppConfig;wslsin distro se trata como host (la resolución nunca inventa una distro).credentials_file_namecomo fuente única de la ruta relativa por proveedor.lib.rs):session_resolver(async) construye el resolvedor del entorno;fetch_usage,check_providerysession_stamplo usan. Si el entorno configurado no se puede resolver (WSL sin instalar, distro ausente), el orbe muestra un error explícito de WSL.WslHomeCacheenAppState):resolve_homelanza dos procesoswsl.exe; consession_stampcada 15 s, el home se resuelve una vez por distro y se invalida solo al cambiar la distro configurada.SessionResolver::default_pathcompone conjoin_guest_path(siempre/), no conPath::join, que en Windows inserta\en una ruta que viaja literal alcatde la distro. Tests del argumento exacto en cualquier plataforma.session_stamplee el contenido dentro de la distro (misma fuente de rutas que los fetch) y suma su huella, de modo que un login dentro de la distro refresca el widget aunque el host no tengamtimeaccesible.Tests
wsl/session.rs(host/WSL/read_async/POSIX),session_stampen WSL, yconfig::session_env.wsl,config,model,cli_processy los cuatro proveedores con elmod.rsreal).cargo fmt --checklimpio, inventario i18n regenerado (--checkOK).Evidencias
47446da: run41741077834— success.47446da: run41741073716—GAP1,GAP1B,GAP2,GAP3PASS.Nota (follow-up conocido)
En la señalización de procesos queda una ventana mínima entre el
grepde identidad y elkilldentro del mismo shell; cerrarla del todo requeriríapidfd_open/pidfd_send_signal, que el shell no expone de forma portable. El diseño es fail-closed: si el PID cambió de dueño, elgrepfalla y no se señala nada (cubierto por regresión determinista en #220).Closes #91
🤖 Generated with Claude Code