Skip to content

Add desktop WSL backend mode - #2353

Closed
Jgratton24 wants to merge 15 commits into
pingdotgg:mainfrom
Jgratton24:josh/desktop-wsl-backend
Closed

Jgratton24 wants to merge 15 commits into
pingdotgg:mainfrom
Jgratton24:josh/desktop-wsl-backend

Conversation

@Jgratton24

@Jgratton24 Jgratton24 commented Apr 26, 2026 •

Copy link
Copy Markdown
Contributor

What Changed

Adds an opt-in Windows desktop mode that keeps the Electron UI native while launching the local T3 Code backend inside WSL. Scoped to the desktop backend lifecycle path — complements rather than replaces the broader WSL-hosted interop work in #170.

Architecture:

  • DesktopWslEnvironment service (apps/desktop/src/wsl/DesktopWslEnvironment.ts): Effect-based service that detects WSL availability, lists distros, pre-warms the VM, converts Windows paths via wslpath, resolves the user's Linux home dir (cached per distro), and prepares node-pty inside the target distro. Toolchain pre-flight names the specific missing tools (node, make, g++, python3) with an actionable apt-install line up front, before any rebuild attempt.
  • Pure path helpers (apps/desktop/src/wsl/wslPathParsing.ts): wsl.exe --list --verbose parser, UNC-path distro extraction, picker default-path resolution (~, ~/..., /..., and \\wsl.localhost\...), and strict DISTRO_NAME_PATTERN. Fully unit-tested.
  • WSL spawn path (apps/desktop/src/backend/DesktopBackendConfiguration.ts): when wslMode === "wsl", the backend manager spawns wsl.exe -d <distro> -- node <linux-entry> --bootstrap-fd 0 --dev-url <url>. Bootstrap JSON is delivered on stdin (extra stdio fds do not survive the wsl.exe bridge); the dev-server URL is passed as a CLI flag because WSLENV translation of URL-shaped values is unreliable. t3Home is omitted from the bootstrap so the Linux backend uses its own home directory — keeping per-backend state (env-id, threads, projects) cleanly partitioned.
  • Settings (apps/desktop/src/settings/DesktopAppSettings.ts): new wslMode and wslDistro fields persisted with strict distro-name validation. setWslMode returns a { changed } discriminator so the IPC handler can skip the restart when the toggle is a no-op.
  • IPC (apps/desktop/src/ipc/methods/wsl.ts): getWslState and setWslBackend methods. The swap stops the running backend in-process, starts the new one, waits for ready with a 2-minute bound, and rolls back to the previous mode on timeout. The rollback's own readiness is checked and surfaces a distinct "degraded state" message if it also fails.
  • Renderer swap flow (apps/web/src/components/settings/ConnectionsSettings.tsx): a "Backend runtime" <Select> with an AlertDialog confirmation, phased loading copy (Restarting backend… → Re-establishing session… → Syncing threads…), and a 180s global ceiling. WS connection events are silenced via suppressReconnect for the duration of the swap so toasts don't flash during the deliberate disconnect. After the new backend's HTTP readiness, the renderer re-authenticates (each backend signs sessions with its own key, so the old cookie 401s), drops the previous env's slice from environmentStateById, and waits for the new welcome event before declaring success.
  • Folder picker (apps/desktop/src/ipc/methods/window.ts): when WSL mode is on, the picker default path resolves through the same pure helper, and ~/... paths expand against the user's actual Linux home (cached per-distro) instead of the /home parent.
  • Server bootstrap fix (apps/server/src/bootstrap.ts): EACCES on the inherited stdin fd is treated as a duplication error so the /proc/self/fd/<fd> fallback path applies under WSL.

Why

Closes #2346 and #192 — the original community ask for WSL support (105 👍, 23 comments). Running the desktop app on Windows currently means launching the backend directly under Windows, which forces users with a WSL-based dev setup to either run the desktop app inside WSL (no native UX) or fall back to the web UI. This change keeps the Electron UI native on Windows while letting the backend run alongside the user's existing Linux toolchain.

The PR is size:XL, but the implementation is partitioned by responsibility: the DesktopWslEnvironment service and pure path helpers are independently testable, the WSL spawn branch in DesktopBackendConfiguration is a self-contained addition, and the renderer swap UX is localized to ConnectionsSettings.tsx. There is no straightforward way to split this without either shipping a permanently-disabled feature flag or merging the UI before the backend works behind it.

UI Changes

Adds a "Backend runtime" selector to the Connections settings panel: a design-system <Select> listing Local (Windows) and one entry per discovered WSL distro (default distro marked). Picking a different value opens an AlertDialog confirming the swap, which transitions through Restarting backend… → Re-establishing session… → Syncing threads… while the backend restarts, the renderer re-bootstraps, and the new welcome event arrives. Toasts surface success and error states.

WSL backend off

WSL backend off

WSL backend on with Ubuntu selected

WSL backend on

Confirmation dialog before a swap

Enable WSL backend confirmation dialog

The dialog sets the cold-start time expectation ("this may take a little while") and notes that each backend keeps its own threads — switching back returns the original list rather than wiping it.

Phased loading during a swap

Restarting backend loading state

Verification

  • bun run typecheck clean
  • bun run lint clean (no new warnings introduced by this PR)
  • bun --filter @t3tools/desktop run test — covers DesktopWslEnvironment toolchain parsing and the wslPathParsing helpers. Pre-existing failures in DesktopAppIdentity/DesktopEnvironment are unrelated Windows path-normalization issues that also fail on the parent commit.
  • bun --filter @t3tools/web run test
  • Full end-to-end pass on Windows 11 / Ubuntu (WSL2): Windows → WSL → Windows backend swaps with cold VM start, folder picker resolving a WSL ~/project initialPath against the user's real home dir, re-picking the resolved-default distro confirmed as a no-op (no dialog, no restart), and the rollback path when the target distro is broken.

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

Note

Add WSL backend mode to the desktop app

  • Adds a DesktopWslEnvironment service (DesktopWslEnvironment.ts) that detects WSL availability, lists distros, converts paths, and verifies/builds node-pty inside a WSL distro.
  • Extends DesktopBackendStartConfig and resolveBackendStartConfig to launch the backend via wsl.exe when WSL mode is active, forwarding selected secrets and merging WSLENV; falls back to the Windows backend if WSL is unavailable.
  • Adds getWslState and setWslBackend IPC handlers and preload bridge methods so the renderer can query and switch backend runtime.
  • Adds a 'Backend runtime' dropdown and confirmation dialog to Connections Settings (ConnectionsSettings.tsx) that restarts the backend, reauthenticates, and waits for the new welcome event.
  • Persists wslMode and wslDistro in DesktopAppSettings with validation and safe defaults.
  • Introduces suppressReconnect to silence connection-state toasts during the backend swap.
  • Risk: WSL backend swap has a 6-minute global timeout; on failure it attempts rollback but if rollback also times out the IPC call fails with WslBackendSwapError.

Macroscope summarized 00b200c.


Note

High Risk
Large cross-cutting change to backend spawn, env/bootstrap partitioning, and auth/session flow on swap; failures are mitigated by rollback and Windows fallback when WSL is missing, but misconfiguration or partial swap timeouts can still strand users until restart.

Overview
Adds an opt-in WSL backend for the Windows desktop: the Electron shell stays native while the local server can run inside a chosen WSL distro via wsl.exe, with separate data homes so Windows and WSL threads do not collide.

Desktop main process: New DesktopWslEnvironment (distro list, pre-warm, wslpath, Linux home, node-pty toolchain checks). DesktopBackendConfiguration picks WSL vs Windows spawn: WSL uses stdin bootstrap (--bootstrap-fd 0), optional --dev-url, strips T3CODE_HOME from the child env, merges WSLENV for API keys, and omits t3Home in bootstrap; if WSL is requested but unavailable, it falls back to Windows instead of a stuck preflight loop. DesktopBackendManager gains configurable args/env delivery, preflight-only restart paths, and waitForReady for swaps. Persisted wslMode / wslDistro in app settings with distro name validation.

IPC & renderer: getWslState / setWslBackend stop/restart the backend with a 2-minute readiness wait and automatic settings rollback on failure. Connections settings get a Backend runtime selector (confirm dialog, phased progress, reauth after swap, welcome sync). suppressReconnect hides WS toasts during intentional swaps; folder picker defaults resolve to WSL UNC paths when in WSL mode. Server bootstrap treats stdin EACCES like other fd duplication errors under WSL.

Reviewed by Cursor Bugbot for commit 00b200c. Bugbot is set up for automated code reviews on this repo. Configure here.

@coderabbitai

coderabbitai Bot commented Apr 26, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 79caec88-84c6-4b1a-ad62-5a66d02a2bd5

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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 and usage tips.

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Apr 26, 2026
Comment thread apps/desktop/src/main.ts Outdated
Comment thread apps/desktop/src/main.ts Outdated
Comment thread apps/desktop/src/main.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a574cbb5d0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/desktop/src/backendReadiness.ts Outdated
@macroscopeapp

macroscopeapp Bot commented Apr 26, 2026 •

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR introduces a substantial new feature (WSL backend mode) with ~2000 lines across multiple new files, new IPC methods, settings, and UI components. Additionally, there are unresolved review comments including a high-severity timeout race condition that warrants human attention.

You can customize Macroscope's approvability policy. Learn more.

Comment thread apps/desktop/src/backendReadiness.ts Outdated
Comment thread apps/desktop/src/main.ts Outdated
Comment thread apps/desktop/src/main.ts Outdated
Comment thread apps/desktop/src/wsl.ts Outdated
Comment thread apps/desktop/src/wsl.ts Outdated
Comment thread apps/web/src/components/settings/ConnectionsSettings.tsx Outdated
Comment thread apps/desktop/src/main.ts Outdated
Comment thread apps/desktop/src/main.ts Outdated
Comment thread apps/desktop/src/main.ts Outdated
@github-actions github-actions Bot added size:XL 500-999 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels Apr 26, 2026
@adenafil

Copy link
Copy Markdown

wow this is great man

Comment thread apps/desktop/src/backendReadiness.ts Outdated
Comment thread apps/desktop/src/main.ts Outdated
Comment thread apps/desktop/src/main.ts Outdated
Comment thread apps/web/src/components/settings/ConnectionsSettings.tsx
@juliusmarminge

Copy link
Copy Markdown
Member

Wow great work! Will find some time to test and review next week!

@juliusmarminge
juliusmarminge self-requested a review April 27, 2026 02:34
Comment thread apps/desktop/src/main.ts Outdated
@github-actions github-actions Bot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Apr 27, 2026
Comment thread apps/desktop/src/wsl.ts Outdated
Comment thread apps/desktop/src/main.ts Outdated
@Jgratton24
Jgratton24 force-pushed the josh/desktop-wsl-backend branch from f241be6 to 017f1d6 Compare April 27, 2026 17:52
Comment thread apps/desktop/src/wsl.ts Outdated
Comment thread apps/desktop/src/main.ts Outdated
Comment thread apps/web/src/components/settings/ConnectionsSettings.tsx Outdated
Comment thread apps/web/src/rpc/wsConnectionState.ts
Comment thread apps/desktop/src/wsl.ts Outdated
@Jgratton24
Jgratton24 force-pushed the josh/desktop-wsl-backend branch from 28281c2 to 443ec84 Compare April 27, 2026 19:10
@vercel

vercel Bot commented May 4, 2026

Copy link
Copy Markdown

@Jgratton24 is attempting to deploy a commit to the Ping Labs Team on Vercel.

A member of the Team first needs to authorize it.

Comment thread apps/desktop/src/main.ts Outdated
Comment thread apps/web/src/rpc/wsConnectionState.ts Outdated
@juliusmarminge

Copy link
Copy Markdown
Member

Still on my list of things to review! I've not forgotten

Comment thread apps/desktop/src/wsl.ts Outdated
Comment thread apps/desktop/src/main.ts Outdated
Comment thread apps/desktop/src/wsl.ts Outdated
Comment thread apps/desktop/src/main.ts Outdated
The dropdown maps state.distro: null to the actual default distro's name
so the Select highlights a real option, but the no-op check still compared
target.distro (e.g. "Ubuntu") against state.distro (null). Re-picking the
visually-active row opened the confirmation dialog and triggered a full
backend restart for what was clearly a no-op. Resolve both sides through
the same null->default mapping before comparing.
The renderer's 180s ceiling was shorter than the IPC's worst-case duration:
setWslBackend can take up to ~2min for the initial readiness wait plus
another ~2min for the rollback readiness wait before throwing
WslBackendSwapError, so the client was firing "Backend swap took too long"
while the main process was still actively rolling back. Bump the ceiling
to 6 minutes (4min IPC worst case + ~60s reauth retry budget + 45s welcome
race) so a real hang still surfaces but a legitimate rollback completes.
…n through error recovery

- remove the unused `enabled` field from WslConfig and the unreferenced
  DEFAULT_WSL_CONFIG export; the toggle moved to DesktopAppSettings.wslMode
  during the migration and the field was carried along by every caller as
  noise that didn't influence behavior
- wrap the entire backend-swap flow (success + catch) in suppressReconnect
  so the catch-block reauth doesn't fire reconnect/offline toasts on top of
  the error toast the user is reading. The previous structure only
  suppressed during the happy path; recovery work landed outside the window
…e-fire false resolve

onWelcome subscribes with `immediate: true`, so the listener fires
synchronously with whatever welcome payload is already in the atom. The
previous code compared against `previousPrimaryEnvId` (descriptor-derived);
if the descriptor hadn't loaded yet, that was null and any non-null current
welcome would resolve the promise instantly, completing the "syncing" stage
before the new backend's welcome actually arrived. Capture the current
welcome's env-id from the atom as the baseline instead so the immediate
fire never matches the "new welcome arrived" predicate.
Comment thread apps/desktop/src/settings/DesktopProjectBackendPreferences.ts Outdated
Comment thread apps/web/src/components/settings/ConnectionsSettings.tsx Outdated
Comment thread apps/web/src/desktopWslBackendSwap.ts Outdated
@Jgratton24
Jgratton24 force-pushed the josh/desktop-wsl-backend branch from 1423710 to 923ed12 Compare May 16, 2026 15:46
Comment thread apps/desktop/src/settings/DesktopProjectBackendPreferences.ts Outdated
Comment thread apps/web/src/desktopWslBackendSwap.ts Outdated
Comment thread apps/desktop/src/settings/DesktopProjectBackendPreferences.ts Outdated
Comment thread apps/web/src/projectBackendPreference.ts Outdated
Comment thread apps/web/src/components/settings/ConnectionsSettings.tsx
Comment thread apps/desktop/src/backend/DesktopBackendConfiguration.ts Outdated
@Jgratton24
Jgratton24 force-pushed the josh/desktop-wsl-backend branch from 1091e1d to 4f3a90c Compare May 16, 2026 20:38
@valascus

Copy link
Copy Markdown

How possible would it be to have wsl backend set per project instead of the whole app?

I have some projects I prefer to run with native windows instead of wsl.

This would be even better. I have the same "problem".

@Jgratton24

Copy link
Copy Markdown
Contributor Author

@juliusmarminge I opened #2751 as a follow-up with the parallel Windows + WSL backend work on top of this PR.

I’m good with keeping them separate so this merges first and the follow-up rebases, or folding it all into #2353 if that’s easier to review

@valascus

valascus commented May 18, 2026 •

Copy link
Copy Markdown

This is a very much appreciated feature. It's been here for weeks, huge rebases were already made because the codebase changes so fast. Glad @Jgratton24 is being resilient.

@Jgratton24

Copy link
Copy Markdown
Contributor Author

@juliusmarminge quick bump on this when you get a chance. I think the only open question is whether you’d rather keep #2751 separate or fold it into #2353

@UtkarshUsername

Copy link
Copy Markdown
Contributor

Hello @Jgratton24, can you take a look at my comment on #2751 when you get a chance. Thanks

…ckend-merge-main

# Conflicts:
#	apps/desktop/src/backend/DesktopBackendConfiguration.ts
@os-netizen

Copy link
Copy Markdown

Would love to use this feature, I am still waiting for a good desktop app that integrates seamlessly with WSL

Resolves conflicts from upstream pingdotgg#2013 (mobile WIP) and its companion
refactors:

- ConnectionsSettings.tsx: drop the now-dead `~/rpc/wsRpcClient` type
  import (file removed upstream); WsRpcClient is now provided by
  @t3tools/client-runtime. Keep the live serverState / wsConnectionState
  / store imports.
- DesktopWslEnvironment.ts: rename the service id from the legacy
  `t3/desktop/WslEnvironment` to `@t3tools/desktop/wsl/DesktopWslEnvironment`
  to satisfy the Effect deterministic-key lint the TSGo migration enforces.

Full typecheck green across all 14 packages; web settings 27/27, desktop
wsl 31/31.
Comment thread apps/web/src/components/settings/ConnectionsSettings.tsx
Bugbot (medium): the WSL backend swap flow caps the wait for the new
backend's welcome event at 45s, then showed an unconditional "Backend
restarted" success toast. On a timeout the backend has genuinely
restarted (setWslBackend + reauth already succeeded), but thread state
may still reflect the prior backend until the delayed welcome lands, so
the copy overclaimed readiness.

Track which side of the 45s race wins and soften the success
description when the welcome didn't sync in time ("taking a moment to
finish syncing - your threads will refresh automatically"), instead of
asserting the backend is fully ready. Still a success (the restart did
happen); the global welcome subscription refreshes threads when the
welcome eventually arrives. Also clears the welcome-race timer once the
race settles.
Comment thread apps/web/src/components/settings/ConnectionsSettings.tsx
Comment thread apps/desktop/src/backend/DesktopBackendConfiguration.ts Outdated
…swaps

Two bugbot reports on the WSL backend flow:

High - "WSL off hides recovery control": when persisted wslMode is "wsl"
but WSL is unavailable (wsl.exe removed, no distro), backend resolution
still took the WSL spawn path and looped on preflight failures, while the
Connections "Backend runtime" row is hidden whenever WSL is unavailable -
leaving no in-app way back to Windows. resolveBackendStartConfig now
checks wslEnvironment.isAvailable and falls back to the Windows backend
(logging a warning) when WSL was requested but isn't usable. Added a
regression test asserting the Windows path is taken in that case.

Medium - "Six minute cap false failure": the swap wrapped setWslBackend +
reauth + welcome wait in one 6-minute Promise.race, so a slow-but-
successful swap could trip the ceiling during reauth/sync and surface
"Backend swap took too long" even though the backend already switched
(and getWslState would show the new mode). Track a swapCommitted flag set
once setWslBackend returns; when the global ceiling fires after commit,
report the switch as done with the still-syncing caveat instead of a hard
failure. Genuine pre-commit failures (aborted false, or setWslBackend
throwing) still take the error path.
Jgratton24 added a commit to Jgratton24/t3code that referenced this pull request May 31, 2026
…ailable

Parity with the pingdotgg#2353 fix for the "WSL off hides recovery control" report.
resolvePrimary took the wsl-only primary path whenever wslOnly +
wslBackendEnabled were persisted, without checking whether WSL is actually
usable. If WSL became unavailable (wsl.exe removed, no distro), the primary
looped on preflight failures while the Connections backend control is
hidden, leaving no in-app way back to Windows.

resolvePrimary now checks wslEnvironment.isAvailable and resolves the
Windows primary (logging a warning) when wsl-only was requested but WSL
isn't usable. Added a regression test asserting the Windows primary path
under isAvailable: false.

@cursor cursor Bot 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.

Cursor Bugbot has reviewed your changes and found 4 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 00b200c. Configure here.

flowTimeoutHandle = window.setTimeout(() => {
aborted = true;
reject(new Error("Backend swap took too long. Check WSL is responsive and try again."));
}, 360_000);

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.

Swap timeout beats WSL build

High Severity

The backend swap uses a six-minute Promise.race ceiling, but setWslBackend can block longer while WSL node-pty is built during configuration.resolve (up to five minutes) plus up to two minutes on waitForReady. The UI can show “swap took too long” and treat the flow as failed while the desktop swap is still running or completes successfully afterward.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 00b200c. Configure here.

}, [desktopBridge, pendingDesktopWslSelection]);

const renderWslRow = () => {
if (!desktopWslState || !desktopWslState.available) return null;

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.

WSL unavailable hides runtime selector

Medium Severity

The “Backend runtime” row is omitted whenever desktopWslState.available is false. If settings still say wslMode: "wsl" but WSL is missing or broken, the desktop falls back to the Windows backend yet the UI offers no way to persist local mode, leaving users stuck until WSL works again or settings are edited manually.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 00b200c. Configure here.


if (previousPrimaryEnvId) {
useStore.getState().removeEnvironmentState(previousPrimaryEnvId);
}

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.

Swap skips welcome env cleanup

Medium Severity

After a successful swap, stale thread state is dropped only when readPrimaryEnvironmentDescriptor() returns an environment id. The welcome wait uses getWelcomePayload() as its baseline, but if the descriptor is not loaded yet while a welcome payload exists, removeEnvironmentState is skipped and the old environment’s slice can remain in the store after the backend change.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 00b200c. Configure here.

return toUncPath(trimmedPath);
}

return homePath;

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.

WSL picker ignores Windows paths

Low Severity

In WSL backend mode, resolveWslPickFolderDefaultPath treats only UNC, ~, and Linux absolute paths specially; any other string (including typical C:\... initial paths) falls through to the generic WSL home default instead of opening near the requested folder.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 00b200c. Configure here.

@Jgratton24 Jgratton24 closed this Jun 4, 2026
@Jgratton24

Copy link
Copy Markdown
Contributor Author

Closing in favor of #2751

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

Labels

size:XXL 1,000+ changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Desktop WSL backend mode for Windows app

9 participants