Skip to content

fix(wsl): transfer selected account homes only in login tabs - #2170

Merged
openwong2kim merged 6 commits into
openwong2kim:mainfrom
snowyukitty:contribution/wsl-account-env-20261014
Oct 14, 2026
Merged

openwong2kim merged 6 commits into
openwong2kim:mainfrom
snowyukitty:contribution/wsl-account-env-20261014

Conversation

@snowyukitty

@snowyukitty snowyukitty commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Settings account-login tabs now explicitly transfer the selected account home into WSL, so the Linux login command writes credentials where the Windows reader expects them. Ordinary WSL panes keep their existing Linux profile selection, avoiding Windows-only notify/MCP/hooks copied into provisioned account directories.

Changes

  • Set an explicit wslAccountLoginEnvKey hint only in the Settings login flow and carry it through both native and daemon PTY creation. The shared injection accepts only CODEX_HOME or CLAUDE_CONFIG_DIR; it never infers this hint from a workspace binding, inherited account home, or profile env.
  • Transfer only the login vendor's nonempty home: /pu for Windows drive/UNC paths, /u for explicit Linux paths. Login tabs normalize only that key's flags; ordinary panes preserve user-authored WSLENV entries. Preserve all unrelated entries and the caller's env object.
  • Add login/ordinary-pane regressions, renderer and backend forwarding coverage, and opt-in native WSL synthetic persistence/baseline fixtures. Document the internal create hint.

CHANGELOG entry

Fixed

  • A WSL login tab receives the account directory selected in Settings. Windows account paths are translated for the Linux agent, and explicit Linux profile paths are preserved. Previously the login could use a different directory while wmux kept waiting for the selected account. This transfer is limited to the login tab's vendor; ordinary WSL panes retain their existing Linux profile selection. (fix(wsl): transfer selected account homes only in login tabs #2170)

Stability tier impact

  • Change to an internal surface (optional client/daemon login hint; no stable external contract change).

Substrate contract impact (Substrate 3.0)

No stable substrate contract changes. The internal daemon.createSession hint is documented in docs/api/inventory.md.

Test plan

  • Five focused files: 52 pass / 15 platform skips, including the unchanged agent slug architecture guard. The same login regressions against the previous published implementation (09385dc67) produce 12 failures / 38 passes / 15 skips, covering unwanted default transfers, cross-vendor transfer, unsupported hints, and missing login-hint forwarding.
  • Native Windows Node 24.21.0 / Ubuntu-24.04: six cases pass. Four login fixtures cover both vendors and Windows/Linux path spellings, synthetic persisted JSON, spaces/apostrophe, and another account left unchanged. Two ordinary-pane fixtures compare the resulting account env to an unmodified Linux launch. Opt in with WMUX_TEST_WSL=1 and optional WMUX_TEST_WSL_DISTRO, then run src/shared/__tests__/wslAccountEnv.runtime.test.ts through vitest.runtime.config.ts.
  • All eight typecheck slices pass on the final merged tree (20573f3d2 upstream base); Windows daemon/web build and CSP also pass. ESLint baseline comparison against that upstream finds zero new diagnostics (17 existing errors / 24 existing warnings across touched legacy files).
  • Full Linux suite on the final merged tree (Node 22.23.3, npm 11.19.0, non-root init-enabled container): 29,695 unit tests pass / 101 skip; 300 runtime tests pass / 181 skip. Daemon/web build and CSP pass. The opt-in WSL cases skip on Linux and were run separately on Windows above.
  • No authenticated OAuth, packaged UI smoke, or real network UNC fixture was run. Login tabs themselves still read the provisioned Windows config; rewriting its notify/MCP/hooks and general WSL account binding are outside this scoped fix. Daemon recovery of the same interrupted login session may retain its generated WSLENV; the hint is not a workspace/profile setting.

Related issues / PRs

Related to #2127; does not claim to close every cause of the reported login wait. The scope follows the login-only option discussed in the maintainer's review.

Reviewer checklist

  • CHANGELOG fragment is included.
  • Stability tier impact is classified.
  • Internal create hint is documented; no stable substrate update is required.
  • Tests cover login transfer and ordinary-pane preservation.
  • Verification limitations are explicit.
  • No credentials, private paths, unrelated changes or large binaries are included.

@coderabbitai

coderabbitai Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: e8f338eb-0c5e-4ddf-9ab5-4575afe8a9c8
📥 Commits

Reviewing files that changed from the base of the PR and between 09385dc and 80e193c.

📒 Files selected for processing: 16
  • changelog.d/2170.md
  • docs/api/inventory.md
  • src/daemon/DaemonSessionManager.ts
  • src/daemon/__tests__/wslDistroSpawnArgs.test.ts
  • src/daemon/index.ts
  • src/main/ipc/handlers/pty.handler.ts
  • src/main/pty/PTYManager.ts
  • src/main/pty/__tests__/PTYManager.createCancel.test.ts
  • src/preload/preload.ts
  • src/renderer/utils/__tests__/accountLogin.test.ts
  • src/renderer/utils/accountLogin.ts
  • src/renderer/utils/ptyCreateOptions.ts
  • src/shared/__tests__/wslAccountEnv.runtime.test.ts
  • src/shared/__tests__/wslIntegration.test.ts
  • src/shared/rpc.ts
  • src/shared/wslIntegration.ts
🚧 Files skipped from review as they are similar to previous changes: 1
  • changelog.d/2170.md

Included review availability: This review used your included allowance. Your plan provides up to 2 included reviews per hour; 1 remain after this review.

📝 Walkthrough

WSL login tabs pass the selected vendor’s account-directory key through PTY and daemon session creation. WSL injection transports that selected value using path-appropriate WSLENV flags. Ordinary WSL panes do not opt in, and explicit Linux account paths are preserved.

Changes: WSL login account directory transport

Layer / File(s) Summary
Select the login account directory
src/renderer/utils/ptyCreateOptions.ts, src/renderer/utils/accountLogin.ts, src/renderer/utils/__tests__/accountLogin.test.ts, src/preload/preload.ts
Login tabs pass CLAUDE_CONFIG_DIR or CODEX_HOME as the account key. Generic sign-in tabs do not pass the key.
Forward the opt-in through session creation
src/main/ipc/handlers/pty.handler.ts, src/main/pty/PTYManager.ts, src/main/pty/__tests__/PTYManager.createCancel.test.ts, src/shared/rpc.ts, src/daemon/index.ts, src/daemon/DaemonSessionManager.ts, src/daemon/__tests__/wslDistroSpawnArgs.test.ts
PTY creation forwards the optional key through local or daemon session creation to WSL injection. Tests verify forwarding for both vendors and verify that omitted keys remain unset.
Transport selected account paths into WSL
src/shared/wslIntegration.ts, src/shared/__tests__/wslIntegration.test.ts, src/shared/__tests__/wslAccountEnv.runtime.test.ts
buildWslInjection adds a nonempty selected account path to WSLENV. Windows drive and UNC paths use pu; other paths use u. Tests cover transport flags, preserved entries, vendor selection, absent values, and opt-in WSL runtime behavior.
Document account-key behavior
docs/api/inventory.md, changelog.d/2170.md
The daemon inventory documents the internal hint. The changelog describes login-tab transport and distinguishes ordinary WSL panes.

Priority: ⬇️ Low

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix

Sequence Diagram(s)

sequenceDiagram
  participant LoginTab
  participant PTYCreate
  participant DaemonSession
  participant WSLInjection
  LoginTab->>PTYCreate: Pass vendor account key
  PTYCreate->>DaemonSession: Forward key for daemon sessions
  PTYCreate->>WSLInjection: Forward key for local sessions
  DaemonSession->>WSLInjection: Forward key for WSL injection
Loading

Suggested reviewers: openwong2kim

Merge Risk: ⚪ Minimal · up to 80e19

The change appears ready to merge after normal checks. Its WSL account-home transfer is limited to login tabs; authenticated login and packaged UI behavior have not been smoke-tested.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 42.86% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 7 functions across 14 files. (2 skipped: … Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly and concisely describes the main change: transferring selected WSL account homes only for login tabs.
Full details: Docstring Coverage

Explanation

Docstring coverage is 42.86% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 7 functions across 14 files. (2 skipped: 2 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@snowyukitty
snowyukitty marked this pull request as ready for review October 14, 2026 00:36
@openwong2kim

openwong2kim commented Oct 14, 2026 •

Copy link
Copy Markdown
Owner

Thanks for picking up #2127 — WSLENV is the right transport, and the runtime test with spaces and an apostrophe is a nice touch.

One thing we noticed while reading it, and I'd love your take on how to handle it: buildWslInjection serves every WSL pane, not only the account-login tab, so the transfer also reaches workspaces bound to an account (and any inherited Windows CODEX_HOME / CLAUDE_CONFIG_DIR). An added account's directory starts as a copy of the Windows ~/.codex/config.toml (accountProvision.ts), which carries wmux's Windows-side notify = ["node","C:/…"] and [mcp_servers.wmux] entries. If Linux codex reads that file through /mnt/c, wmux-wsl-codex-config.mjs sees notify/MCP as already set and skips its Linux overrides, so those panes would lose the wmux MCP server and the turn-end notify. The copied Claude settings.json with Windows hook commands looks like the same class. It would also move existing WSL users from their Linux ~/.claude / ~/.codex to the Windows account home.

A couple of ways I can see:

  • keep this PR to the login tab (an opt-in flag on the injection, set only by the account-login launch), and treat account bindings in WSL agent panes as a follow-up; or
  • carry it to every pane, and teach the WSL helpers to replace wmux's own Windows entries.

The first feels like the smaller step to me, but you know this path better — what do you think? Happy to take the follow-up on our side either way.

(Tiny aside, not blocking: env[key] is matched case-sensitively, so a lower-case claude_config_dir from a profile is skipped.)

@snowyukitty
snowyukitty marked this pull request as draft October 14, 2026 04:00
@snowyukitty snowyukitty changed the title fix(wsl): carry selected account homes into Linux launches fix(wsl): transfer selected account homes only in login tabs Oct 14, 2026
@snowyukitty
snowyukitty marked this pull request as ready for review October 14, 2026 04:39

@Jorlpj Jorlpj left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for narrowing this to the login tab. I checked it against today's main and on a Windows box with WSL. Nothing blocking; two notes from probes, in case they help the follow-up.

What I ran

  • Merged 80e193cf6 with main at 469d7607b locally: no conflicts. On the merge, the four focused unit files (wslIntegration, wslDistroSpawnArgs, PTYManager.createCancel, accountLogin) give 50 passed / 15 skipped.
  • The opt-in runtime file, WMUX_TEST_WSL=1 WMUX_TEST_WSL_DISTRO=Ubuntu-24.04 with vitest.runtime.config.ts, gives 6/6 on Windows 11 + Ubuntu-24.04 (WSL2).

1. The fix only changes behaviour for a Linux-native CLI (informational)

A common WSL setup puts the Windows npm global dir on the Linux PATH through interop. There, command -v codex in WSL resolves to /mnt/c/Users/<user>/AppData/Roaming/npm/codex. That npm shim falls back to node.exe, so Codex runs as a Windows process.

A Windows process started from WSL inherits the Windows environment of the wsl.exe that launched the session, whatever WSLENV says. Probe, with a fresh variable and no WSLENV entry:

$env:WMUXFRESH_X = "C:\fresh\<random>"; $env:WSLENV = ''
wsl -d Ubuntu-24.04 -- sh -c 'echo "linux=[${WMUXFRESH_X-unset}]"; cmd.exe /d /c "echo win=[%WMUXFRESH_X%]"'
linux=[unset]
win=[C:\fresh\<random>]

So with a Windows Codex reached through interop, the login tab already wrote to the selected account dir before this PR, and it still does: /pu does not pass the variable back to Win32. The change only matters when the WSL codex / claude is a Linux install. That fits the changelog wording ("translated for the Linux agent"). It also means #2127 is fixed by this PR only if the reporter's WSL codex is Linux-native. If it is the Windows shim, the wait has another cause.

2. UNC account dirs that the distro cannot translate (not reachable from Settings today)

The windowsPath check also sends \\… paths through /pu. WSL translates \\wsl.localhost\<this distro>\… and \\wsl$\<this distro>\… correctly (→ /home/…). For another distro's \\wsl.localhost\<other>\… or a network \\server\share\…, the variable is dropped entirely in Linux (${VAR+set} is empty). wsl.exe also prints wsl: Failed to translate '<path>' on stderr, and in a PTY that lands in the login tab. The login then falls back to the Linux default home, and the watcher keeps waiting.

Settings never builds such a path: onboarding always uses <wmux dir>/accounts/<vendor>-<id> on the local drive, and canonicalizeConfigDir keeps a \\wsl.localhost\… input as UNC. So this only matters if account dirs ever become user-chosen. The PR's test plan lists a real UNC fixture as not run, so this is just the observed behaviour for that gap. If you want to cover it, a small guard is enough: forward only drive paths and \\wsl.localhost\<target distro>\ / \\wsl$\<target distro>\, and otherwise skip the entry. I have not tested that guard.

@openwong2kim openwong2kim added the needs-wsl-verify Touches a WSL code path that needs a live run in a WSL distro label Oct 14, 2026
@openwong2kim

Copy link
Copy Markdown
Owner

Live WSL verification of #2170

Verified build: this PR's head 80e193cf6, packaged locally (npm run package). I ran it on Windows 11 Home 10.0.26200 with WSL2 Ubuntu 24.04.5 (kernel 6.18, the WSL user is dev), using an isolated profile (WMUX_DATA_SUFFIX=-wv2170). Codex CLI and Claude Code are installed inside the distro.

The #2127 flow through the real UI

  1. Settings → Terminal → Default shell: WSL.
  2. Settings → Accounts → + Add account → Codex, named "wv2170 codex" → Create & log in. The login tab opened as a WSL pane (wsl.exe -d Ubuntu) and ran codex login, which printed its localhost:1455 OAuth URL.
  3. I stopped codex login with Ctrl+C, without signing in to OpenAI, and inspected the same pane:
    • CODEX_HOME=/mnt/c/Users/rizz/.wmux-wv2170/accounts/codex-1a002516. This is the folder Settings provisioned, C:\Users\rizz\.wmux-wv2170\accounts\codex-1a002516.
    • WSLENV contains CODEX_HOME/pu. CLAUDE_CONFIG_DIR is empty, so the other vendor's key is not transferred.
    • codex login had already created its log/ and tmp/ in that folder, so the Linux CLI now writes where the Windows side reads.
  4. Codex counts as logged in once auth.json exists. I wrote a synthetic one at the path the CLI would use, "$CODEX_HOME/auth.json" from inside WSL. Within the 2 s poll the wait cleared:
    • the account appeared in accounts.list with loggedIn: true
    • the login tab closed by itself

What each WSL pane receives (same pty.create path as the login tab)

Case CODEX_HOME in WSL CLAUDE_CONFIG_DIR in WSL User var
Ordinary pane, CODEX_HOME = the Windows account folder in env, no hint. This is exactly how the login tab was spawned before this PR, so codex login fell back to ~/.codex and the app kept waiting. (empty) (empty)
Ordinary pane, no env (empty) (empty)
Hint CLAUDE_CONFIG_DIR, Windows path with a space and an apostrophe, plus a CODEX_HOME that must not transfer (empty) /mnt/c/Users/rizz/.wmux-wv2170/accounts/claude dir's x
Hint CODEX_HOME, Linux path /home/dev/.codex-wv2170 /home/dev/.codex-wv2170 (unchanged, /u) (empty)
Ordinary pane with the user's own WSLENV=WV2170_USER/u (empty) (empty) kept

Tests on Windows

  • Focused unit tests (wslIntegration, wslDistroSpawnArgs, PTYManager.createCancel, accountLogin): 4 files, 50 passed and 15 platform skips.
  • The opt-in real-WSL runtime test (WMUX_TEST_WSL=1 WMUX_TEST_WSL_DISTRO=Ubuntu, wslAccountEnv.runtime.test.ts through vitest.runtime.config.ts): 6 passed.

No side effects: the owner's ~/.codex/auth.json and ~/.claude/settings.json are unchanged, and the isolated app and daemon were stopped (0 processes left).

Not covered here: a real OpenAI sign-in (the credential write was synthetic), the Claude login command end to end (I checked only its environment), and a non-default WSL distro.

@openwong2kim openwong2kim removed the needs-wsl-verify Touches a WSL code path that needs a live run in a WSL distro label Oct 14, 2026
@openwong2kim
openwong2kim merged commit 290de11 into openwong2kim:main Oct 14, 2026
21 checks passed
@openwong2kim

Copy link
Copy Markdown
Owner

Thanks @Jorlpj, and sorry I missed this review before my verification comment. Both points stand:

  1. My live run used a Linux-native Codex (command -v codex → /home/dev/.npm-global/bin/codex), so it covers only that case. I reopened [Bug]: can't sign into codex using wsl #2127 and asked the reporter for command -v codex. If it is the Windows shim under /mnt/c/..., the wait has another cause and [Bug]: can't sign into codex using wsl #2127 stays open for it.
  2. UNC paths the distro cannot translate: agreed that Settings cannot produce one today. Your suggested guard is tracked in WSL login tab: an account home on an untranslatable UNC path is dropped silently #2202 (forward only drive paths and \\wsl.localhost\<target>\ / \\wsl$\<target>\, otherwise no entry and a visible error). It is not part of this PR, since the PR is already merged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants