Repository navigation
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>
… i18n) en feat/wsl-adapter El main avanzó con la corrección de colocación X11 (egdev6#221), la notarización resumible de macOS (egdev6#219) y el proveedor Antigravity (egdev6#207). Se integra sobre la rama del adaptador WSL; docs/i18n-inventory.md se regenera desde el árbol fusionado. Co-Authored-By: Claude Code <noreply@anthropic.com>
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>
Co-Authored-By: Claude Code <noreply@anthropic.com>
…v6#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 (egdev6#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>
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>
…tro (egdev6#91) Revisión PR egdev6#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>
Co-Authored-By: Claude Code <noreply@anthropic.com>
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>
Co-Authored-By: Claude Code <noreply@anthropic.com>
- 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>
…gdev6#91) Revisión del mantenedor (2026-11-02) aplicada a la PR de egdev6#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>
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 |
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