Browse Source

Revert "feat(desktop): add WSL backend mode (#12914)"

This reverts commit 213a87234dd7579873787070e5f8ad98eb88bce8.
Adam 2 weeks ago
parent
commit
2e8082dd21

+ 1 - 1
packages/app/src/app.tsx

@@ -43,7 +43,7 @@ function UiI18nBridge(props: ParentProps) {
 
 declare global {
   interface Window {
-    __OPENCODE__?: { updaterEnabled?: boolean; serverPassword?: string; deepLinks?: string[]; wsl?: boolean }
+    __OPENCODE__?: { updaterEnabled?: boolean; serverPassword?: string; deepLinks?: string[] }
   }
 }
 

+ 0 - 28
packages/app/src/components/settings-general.tsx

@@ -367,34 +367,6 @@ export const SettingsGeneral: Component = () => {
           </div>
         </div>
 
-        <Show when={platform.platform === "desktop" && platform.os === "windows" && platform.getWslEnabled}>
-          {(_) => {
-            const [enabledResource, actions] = createResource(() => platform.getWslEnabled?.())
-            const enabled = () => (enabledResource.state === "pending" ? undefined : enabledResource.latest)
-
-            return (
-              <div class="flex flex-col gap-1">
-                <h3 class="text-14-medium text-text-strong pb-2">{language.t("settings.desktop.section.wsl")}</h3>
-
-                <div class="bg-surface-raised-base px-4 rounded-lg">
-                  <SettingsRow
-                    title={language.t("settings.desktop.wsl.title")}
-                    description={language.t("settings.desktop.wsl.description")}
-                  >
-                    <div data-action="settings-wsl">
-                      <Switch
-                        checked={enabled() ?? false}
-                        disabled={enabledResource.state === "pending"}
-                        onChange={(checked) => platform.setWslEnabled?.(checked)?.finally(() => actions.refetch())}
-                      />
-                    </div>
-                  </SettingsRow>
-                </div>
-              </div>
-            )
-          }}
-        </Show>
-
         {/* Updates Section */}
         <div class="flex flex-col gap-1">
           <h3 class="text-14-medium text-text-strong pb-2">{language.t("settings.general.section.updates")}</h3>

+ 0 - 6
packages/app/src/context/platform.tsx

@@ -57,12 +57,6 @@ export type Platform = {
   /** Set the default server URL to use on app startup (platform-specific) */
   setDefaultServerUrl?(url: string | null): Promise<void> | void
 
-  /** Get the configured WSL integration (desktop only) */
-  getWslEnabled?(): Promise<boolean>
-
-  /** Set the configured WSL integration (desktop only) */
-  setWslEnabled?(config: boolean): Promise<void> | void
-
   /** Get the preferred display backend (desktop only) */
   getDisplayBackend?(): Promise<DisplayBackend | null> | DisplayBackend | null
 

+ 0 - 3
packages/app/src/i18n/ar.ts

@@ -508,9 +508,6 @@ export const dict = {
   "settings.section.server": "الخادم",
   "settings.tab.general": "عام",
   "settings.tab.shortcuts": "اختصارات",
-  "settings.desktop.section.wsl": "WSL",
-  "settings.desktop.wsl.title": "WSL integration",
-  "settings.desktop.wsl.description": "Run the OpenCode server inside WSL on Windows.",
 
   "settings.general.section.appearance": "المظهر",
   "settings.general.section.notifications": "إشعارات النظام",

+ 0 - 3
packages/app/src/i18n/br.ts

@@ -512,9 +512,6 @@ export const dict = {
   "settings.section.server": "Servidor",
   "settings.tab.general": "Geral",
   "settings.tab.shortcuts": "Atalhos",
-  "settings.desktop.section.wsl": "WSL",
-  "settings.desktop.wsl.title": "WSL integration",
-  "settings.desktop.wsl.description": "Run the OpenCode server inside WSL on Windows.",
 
   "settings.general.section.appearance": "Aparência",
   "settings.general.section.notifications": "Notificações do sistema",

+ 0 - 3
packages/app/src/i18n/bs.ts

@@ -539,9 +539,6 @@ export const dict = {
   "settings.section.server": "Server",
   "settings.tab.general": "Opšte",
   "settings.tab.shortcuts": "Prečice",
-  "settings.desktop.section.wsl": "WSL",
-  "settings.desktop.wsl.title": "WSL integration",
-  "settings.desktop.wsl.description": "Run the OpenCode server inside WSL on Windows.",
 
   "settings.general.section.appearance": "Izgled",
   "settings.general.section.notifications": "Sistemske obavijesti",

+ 0 - 3
packages/app/src/i18n/da.ts

@@ -512,9 +512,6 @@ export const dict = {
   "settings.section.server": "Server",
   "settings.tab.general": "Generelt",
   "settings.tab.shortcuts": "Genveje",
-  "settings.desktop.section.wsl": "WSL",
-  "settings.desktop.wsl.title": "WSL integration",
-  "settings.desktop.wsl.description": "Run the OpenCode server inside WSL on Windows.",
 
   "settings.general.section.appearance": "Udseende",
   "settings.general.section.notifications": "Systemmeddelelser",

+ 0 - 3
packages/app/src/i18n/de.ts

@@ -556,9 +556,6 @@ export const dict = {
   "settings.section.server": "Server",
   "settings.tab.general": "Allgemein",
   "settings.tab.shortcuts": "Tastenkombinationen",
-  "settings.desktop.section.wsl": "WSL",
-  "settings.desktop.wsl.title": "WSL integration",
-  "settings.desktop.wsl.description": "Run the OpenCode server inside WSL on Windows.",
 
   "settings.general.section.appearance": "Erscheinungsbild",
   "settings.general.section.notifications": "Systembenachrichtigungen",

+ 0 - 3
packages/app/src/i18n/en.ts

@@ -583,9 +583,6 @@ export const dict = {
   "settings.section.server": "Server",
   "settings.tab.general": "General",
   "settings.tab.shortcuts": "Shortcuts",
-  "settings.desktop.section.wsl": "WSL",
-  "settings.desktop.wsl.title": "WSL integration",
-  "settings.desktop.wsl.description": "Run the OpenCode server inside WSL on Windows.",
 
   "settings.general.section.appearance": "Appearance",
   "settings.general.section.notifications": "System notifications",

+ 0 - 3
packages/app/src/i18n/es.ts

@@ -515,9 +515,6 @@ export const dict = {
   "settings.section.server": "Servidor",
   "settings.tab.general": "General",
   "settings.tab.shortcuts": "Atajos",
-  "settings.desktop.section.wsl": "WSL",
-  "settings.desktop.wsl.title": "WSL integration",
-  "settings.desktop.wsl.description": "Run the OpenCode server inside WSL on Windows.",
 
   "settings.general.section.appearance": "Apariencia",
   "settings.general.section.notifications": "Notificaciones del sistema",

+ 0 - 3
packages/app/src/i18n/fr.ts

@@ -522,9 +522,6 @@ export const dict = {
   "settings.section.server": "Serveur",
   "settings.tab.general": "Général",
   "settings.tab.shortcuts": "Raccourcis",
-  "settings.desktop.section.wsl": "WSL",
-  "settings.desktop.wsl.title": "WSL integration",
-  "settings.desktop.wsl.description": "Run the OpenCode server inside WSL on Windows.",
 
   "settings.general.section.appearance": "Apparence",
   "settings.general.section.notifications": "Notifications système",

+ 0 - 3
packages/app/src/i18n/ja.ts

@@ -507,9 +507,6 @@ export const dict = {
   "settings.section.server": "サーバー",
   "settings.tab.general": "一般",
   "settings.tab.shortcuts": "ショートカット",
-  "settings.desktop.section.wsl": "WSL",
-  "settings.desktop.wsl.title": "WSL integration",
-  "settings.desktop.wsl.description": "Run the OpenCode server inside WSL on Windows.",
 
   "settings.general.section.appearance": "外観",
   "settings.general.section.notifications": "システム通知",

+ 0 - 3
packages/app/src/i18n/ko.ts

@@ -513,9 +513,6 @@ export const dict = {
   "settings.section.server": "서버",
   "settings.tab.general": "일반",
   "settings.tab.shortcuts": "단축키",
-  "settings.desktop.section.wsl": "WSL",
-  "settings.desktop.wsl.title": "WSL integration",
-  "settings.desktop.wsl.description": "Run the OpenCode server inside WSL on Windows.",
 
   "settings.general.section.appearance": "모양",
   "settings.general.section.notifications": "시스템 알림",

+ 0 - 3
packages/app/src/i18n/no.ts

@@ -515,9 +515,6 @@ export const dict = {
   "settings.section.server": "Server",
   "settings.tab.general": "Generelt",
   "settings.tab.shortcuts": "Snarveier",
-  "settings.desktop.section.wsl": "WSL",
-  "settings.desktop.wsl.title": "WSL integration",
-  "settings.desktop.wsl.description": "Run the OpenCode server inside WSL on Windows.",
 
   "settings.general.section.appearance": "Utseende",
   "settings.general.section.notifications": "Systemvarsler",

+ 0 - 3
packages/app/src/i18n/pl.ts

@@ -514,9 +514,6 @@ export const dict = {
   "settings.section.server": "Serwer",
   "settings.tab.general": "Ogólne",
   "settings.tab.shortcuts": "Skróty",
-  "settings.desktop.section.wsl": "WSL",
-  "settings.desktop.wsl.title": "WSL integration",
-  "settings.desktop.wsl.description": "Run the OpenCode server inside WSL on Windows.",
 
   "settings.general.section.appearance": "Wygląd",
   "settings.general.section.notifications": "Powiadomienia systemowe",

+ 0 - 3
packages/app/src/i18n/ru.ts

@@ -517,9 +517,6 @@ export const dict = {
   "settings.section.server": "Сервер",
   "settings.tab.general": "Основные",
   "settings.tab.shortcuts": "Горячие клавиши",
-  "settings.desktop.section.wsl": "WSL",
-  "settings.desktop.wsl.title": "WSL integration",
-  "settings.desktop.wsl.description": "Run the OpenCode server inside WSL on Windows.",
 
   "settings.general.section.appearance": "Внешний вид",
   "settings.general.section.notifications": "Системные уведомления",

+ 0 - 3
packages/app/src/i18n/th.ts

@@ -516,9 +516,6 @@ export const dict = {
   "settings.section.server": "เซิร์ฟเวอร์",
   "settings.tab.general": "ทั่วไป",
   "settings.tab.shortcuts": "ทางลัด",
-  "settings.desktop.section.wsl": "WSL",
-  "settings.desktop.wsl.title": "WSL integration",
-  "settings.desktop.wsl.description": "Run the OpenCode server inside WSL on Windows.",
 
   "settings.general.section.appearance": "รูปลักษณ์",
   "settings.general.section.notifications": "การแจ้งเตือนระบบ",

+ 0 - 3
packages/app/src/i18n/zh.ts

@@ -548,9 +548,6 @@ export const dict = {
   "settings.section.server": "服务器",
   "settings.tab.general": "通用",
   "settings.tab.shortcuts": "快捷键",
-  "settings.desktop.section.wsl": "WSL",
-  "settings.desktop.wsl.title": "WSL integration",
-  "settings.desktop.wsl.description": "Run the OpenCode server inside WSL on Windows.",
 
   "settings.general.section.appearance": "外观",
   "settings.general.section.notifications": "系统通知",

+ 0 - 3
packages/app/src/i18n/zht.ts

@@ -545,9 +545,6 @@ export const dict = {
   "settings.section.server": "伺服器",
   "settings.tab.general": "一般",
   "settings.tab.shortcuts": "快速鍵",
-  "settings.desktop.section.wsl": "WSL",
-  "settings.desktop.wsl.title": "WSL integration",
-  "settings.desktop.wsl.description": "Run the OpenCode server inside WSL on Windows.",
 
   "settings.general.section.appearance": "外觀",
   "settings.general.section.notifications": "系統通知",

+ 0 - 4
packages/desktop/AGENTS.md

@@ -1,4 +0,0 @@
-# Desktop package notes
-
-- Never call `invoke` manually in this package.
-- Use the generated bindings in `packages/desktop/src/bindings.ts` for core commands/events.

+ 25 - 113
packages/desktop/src-tauri/src/cli.rs

@@ -3,11 +3,8 @@ use tauri_plugin_shell::{
     ShellExt,
     process::{Command, CommandChild, CommandEvent, TerminatedPayload},
 };
-use tauri_plugin_store::StoreExt;
 use tokio::sync::oneshot;
 
-use crate::constants::{SETTINGS_STORE, WSL_ENABLED_KEY};
-
 const CLI_INSTALL_DIR: &str = ".opencode/bin";
 const CLI_BINARY_NAME: &str = "opencode";
 
@@ -23,7 +20,7 @@ pub struct Config {
 }
 
 pub async fn get_config(app: &AppHandle) -> Option<Config> {
-    create_command(app, "debug config", &[])
+    create_command(app, "debug config")
         .output()
         .await
         .inspect_err(|e| tracing::warn!("Failed to read OC config: {e}"))
@@ -152,106 +149,25 @@ fn get_user_shell() -> String {
     std::env::var("SHELL").unwrap_or_else(|_| "/bin/sh".to_string())
 }
 
-fn is_wsl_enabled(app: &tauri::AppHandle) -> bool {
-    let Ok(store) = app.store(SETTINGS_STORE) else {
-        return false;
-    };
-
-    store
-        .get(WSL_ENABLED_KEY)
-        .as_ref()
-        .and_then(|value| value.as_bool())
-        .unwrap_or(false)
-}
-
-fn shell_escape(input: &str) -> String {
-    if input.is_empty() {
-        return "''".to_string();
-    }
-
-    let mut escaped = String::from("'");
-    escaped.push_str(&input.replace("'", "'\"'\"'"));
-    escaped.push('\'');
-    escaped
-}
-
-pub fn create_command(app: &tauri::AppHandle, args: &str, extra_env: &[(&str, String)]) -> Command {
+pub fn create_command(app: &tauri::AppHandle, args: &str) -> Command {
     let state_dir = app
         .path()
         .resolve("", BaseDirectory::AppLocalData)
         .expect("Failed to resolve app local data dir");
 
-    let mut envs = vec![
-        (
-            "OPENCODE_EXPERIMENTAL_ICON_DISCOVERY".to_string(),
-            "true".to_string(),
-        ),
-        (
-            "OPENCODE_EXPERIMENTAL_FILEWATCHER".to_string(),
-            "true".to_string(),
-        ),
-        ("OPENCODE_CLIENT".to_string(), "desktop".to_string()),
-        (
-            "XDG_STATE_HOME".to_string(),
-            state_dir.to_string_lossy().to_string(),
-        ),
-    ];
-    envs.extend(
-        extra_env
-            .iter()
-            .map(|(key, value)| (key.to_string(), value.clone())),
-    );
-
-    if cfg!(windows) {
-        if is_wsl_enabled(app) {
-            tracing::info!("WSL is enabled, spawning CLI server in WSL");
-            let version = app.package_info().version.to_string();
-            let mut script = vec![
-                "set -e".to_string(),
-                "BIN=\"$HOME/.opencode/bin/opencode\"".to_string(),
-                "if [ ! -x \"$BIN\" ]; then".to_string(),
-                format!(
-                    "  curl -fsSL https://opencode.ai/install | bash -s -- --version {} --no-modify-path",
-                    shell_escape(&version)
-                ),
-                "fi".to_string(),
-            ];
-
-            let mut env_prefix = vec![
-                "OPENCODE_EXPERIMENTAL_ICON_DISCOVERY=true".to_string(),
-                "OPENCODE_EXPERIMENTAL_FILEWATCHER=true".to_string(),
-                "OPENCODE_CLIENT=desktop".to_string(),
-                "XDG_STATE_HOME=\"$HOME/.local/state\"".to_string(),
-            ];
-            env_prefix.extend(
-                envs.iter()
-                    .filter(|(key, _)| key != "OPENCODE_EXPERIMENTAL_ICON_DISCOVERY")
-                    .filter(|(key, _)| key != "OPENCODE_EXPERIMENTAL_FILEWATCHER")
-                    .filter(|(key, _)| key != "OPENCODE_CLIENT")
-                    .filter(|(key, _)| key != "XDG_STATE_HOME")
-                    .map(|(key, value)| format!("{}={}", key, shell_escape(value))),
-            );
-
-            script.push(format!("{} exec \"$BIN\" {}", env_prefix.join(" "), args));
-
-            return app
-                .shell()
-                .command("wsl")
-                .args(["-e", "bash", "-lc", &script.join("\n")]);
-        } else {
-            let mut cmd = app
-                .shell()
-                .sidecar("opencode-cli")
-                .unwrap()
-                .args(args.split_whitespace());
-
-            for (key, value) in envs {
-                cmd = cmd.env(key, value);
-            }
-
-            return cmd;
-        }
-    } else {
+    #[cfg(target_os = "windows")]
+    return app
+        .shell()
+        .sidecar("opencode-cli")
+        .unwrap()
+        .args(args.split_whitespace())
+        .env("OPENCODE_EXPERIMENTAL_ICON_DISCOVERY", "true")
+        .env("OPENCODE_EXPERIMENTAL_FILEWATCHER", "true")
+        .env("OPENCODE_CLIENT", "desktop")
+        .env("XDG_STATE_HOME", &state_dir);
+
+    #[cfg(not(target_os = "windows"))]
+    return {
         let sidecar = get_sidecar_path(app);
         let shell = get_user_shell();
 
@@ -261,14 +177,14 @@ pub fn create_command(app: &tauri::AppHandle, args: &str, extra_env: &[(&str, St
             format!("\"{}\" {}", sidecar.display(), args)
         };
 
-        let mut cmd = app.shell().command(&shell).args(["-il", "-c", &cmd]);
-
-        for (key, value) in envs {
-            cmd = cmd.env(key, value);
-        }
-
-        cmd
-    }
+        app.shell()
+            .command(&shell)
+            .env("OPENCODE_EXPERIMENTAL_ICON_DISCOVERY", "true")
+            .env("OPENCODE_EXPERIMENTAL_FILEWATCHER", "true")
+            .env("OPENCODE_CLIENT", "desktop")
+            .env("XDG_STATE_HOME", &state_dir)
+            .args(["-il", "-c", &cmd])
+    };
 }
 
 pub fn serve(
@@ -281,16 +197,12 @@ pub fn serve(
 
     tracing::info!(port, "Spawning sidecar");
 
-    let envs = [
-        ("OPENCODE_SERVER_USERNAME", "opencode".to_string()),
-        ("OPENCODE_SERVER_PASSWORD", password.to_string()),
-    ];
-
     let (mut rx, child) = create_command(
         app,
         format!("--print-logs --log-level WARN serve --hostname {hostname} --port {port}").as_str(),
-        &envs,
     )
+    .env("OPENCODE_SERVER_USERNAME", "opencode")
+    .env("OPENCODE_SERVER_PASSWORD", password)
     .spawn()
     .expect("Failed to spawn opencode");
 

+ 0 - 1
packages/desktop/src-tauri/src/constants.rs

@@ -2,7 +2,6 @@ use tauri_plugin_window_state::StateFlags;
 
 pub const SETTINGS_STORE: &str = "opencode.settings.dat";
 pub const DEFAULT_SERVER_URL_KEY: &str = "defaultServerUrl";
-pub const WSL_ENABLED_KEY: &str = "wslEnabled";
 pub const UPDATER_ENABLED: bool = option_env!("TAURI_SIGNING_PRIVATE_KEY").is_some();
 
 pub fn window_state_flags() -> StateFlags {

+ 22 - 85
packages/desktop/src-tauri/src/lib.rs

@@ -52,13 +52,6 @@ enum InitStep {
     Done,
 }
 
-#[derive(serde::Deserialize, specta::Type)]
-#[serde(rename_all = "snake_case")]
-enum WslPathMode {
-    Windows,
-    Linux,
-}
-
 struct InitState {
     current: watch::Receiver<InitStep>,
 }
@@ -627,50 +620,32 @@ fn check_linux_app(app_name: &str) -> bool {
     return true;
 }
 
-#[tauri::command]
-#[specta::specta]
-fn wsl_path(path: String, mode: Option<WslPathMode>) -> Result<String, String> {
-    if !cfg!(windows) {
-        return Ok(path);
-    }
-
-    let flag = match mode.unwrap_or(WslPathMode::Linux) {
-        WslPathMode::Windows => "-w",
-        WslPathMode::Linux => "-u",
-    };
-
-    let output = if path.starts_with('~') {
-        let suffix = path.strip_prefix('~').unwrap_or("");
-        let escaped = suffix.replace('"', "\\\"");
-        let cmd = format!("wslpath {flag} \"$HOME{escaped}\"");
-        Command::new("wsl")
-            .args(["-e", "sh", "-lc", &cmd])
-            .output()
-            .map_err(|e| format!("Failed to run wslpath: {e}"))?
-    } else {
-        Command::new("wsl")
-            .args(["-e", "wslpath", flag, &path])
-            .output()
-            .map_err(|e| format!("Failed to run wslpath: {e}"))?
-    };
-
-    if !output.status.success() {
-        let stderr = String::from_utf8_lossy(&output.stderr).trim().to_string();
-        if stderr.is_empty() {
-            return Err("wslpath failed".to_string());
-        }
-        return Err(stderr);
-    }
-
-    Ok(String::from_utf8_lossy(&output.stdout).trim().to_string())
-}
-
 #[cfg_attr(mobile, tauri::mobile_entry_point)]
 pub fn run() {
-    let builder = make_specta_builder();
+    let builder = tauri_specta::Builder::<tauri::Wry>::new()
+        // Then register them (separated by a comma)
+        .commands(tauri_specta::collect_commands![
+            kill_sidecar,
+            cli::install_cli,
+            await_initialization,
+            server::get_default_server_url,
+            server::set_default_server_url,
+            get_display_backend,
+            set_display_backend,
+            markdown::parse_markdown_command,
+            check_app_exists,
+            resolve_app_path
+        ])
+        .events(tauri_specta::collect_events![LoadingWindowComplete])
+        .error_handling(tauri_specta::ErrorHandlingMode::Throw);
 
     #[cfg(debug_assertions)] // <- Only export on non-release builds
-    export_types(&builder);
+    builder
+        .export(
+            specta_typescript::Typescript::default(),
+            "../src/bindings.ts",
+        )
+        .expect("Failed to export typescript bindings");
 
     #[cfg(all(target_os = "macos", not(debug_assertions)))]
     let _ = std::process::Command::new("killall")
@@ -737,44 +712,6 @@ pub fn run() {
         });
 }
 
-fn make_specta_builder() -> tauri_specta::Builder<tauri::Wry> {
-    tauri_specta::Builder::<tauri::Wry>::new()
-        // Then register them (separated by a comma)
-        .commands(tauri_specta::collect_commands![
-            kill_sidecar,
-            cli::install_cli,
-            await_initialization,
-            server::get_default_server_url,
-            server::set_default_server_url,
-            server::get_wsl_config,
-            server::set_wsl_config,
-            get_display_backend,
-            set_display_backend,
-            markdown::parse_markdown_command,
-            check_app_exists,
-            wsl_path,
-            resolve_app_path
-        ])
-        .events(tauri_specta::collect_events![LoadingWindowComplete])
-        .error_handling(tauri_specta::ErrorHandlingMode::Throw)
-}
-
-fn export_types(builder: &tauri_specta::Builder<tauri::Wry>) {
-    builder
-        .export(
-            specta_typescript::Typescript::default(),
-            "../src/bindings.ts",
-        )
-        .expect("Failed to export typescript bindings");
-}
-
-#[cfg(test)]
-#[test]
-fn test_export_types() {
-    let builder = make_specta_builder();
-    export_types(&builder);
-}
-
 #[derive(tauri_specta::Event, serde::Deserialize, specta::Type)]
 struct LoadingWindowComplete;
 

+ 1 - 44
packages/desktop/src-tauri/src/server.rs

@@ -8,20 +8,9 @@ use tokio::task::JoinHandle;
 
 use crate::{
     cli,
-    constants::{DEFAULT_SERVER_URL_KEY, SETTINGS_STORE, WSL_ENABLED_KEY},
+    constants::{DEFAULT_SERVER_URL_KEY, SETTINGS_STORE},
 };
 
-#[derive(Clone, serde::Serialize, serde::Deserialize, specta::Type, Debug)]
-pub struct WslConfig {
-    pub enabled: bool,
-}
-
-impl Default for WslConfig {
-    fn default() -> Self {
-        Self { enabled: false }
-    }
-}
-
 #[tauri::command]
 #[specta::specta]
 pub fn get_default_server_url(app: AppHandle) -> Result<Option<String>, String> {
@@ -59,38 +48,6 @@ pub async fn set_default_server_url(app: AppHandle, url: Option<String>) -> Resu
     Ok(())
 }
 
-#[tauri::command]
-#[specta::specta]
-pub fn get_wsl_config(app: AppHandle) -> Result<WslConfig, String> {
-    let store = app
-        .store(SETTINGS_STORE)
-        .map_err(|e| format!("Failed to open settings store: {}", e))?;
-
-    let enabled = store
-        .get(WSL_ENABLED_KEY)
-        .as_ref()
-        .and_then(|v| v.as_bool())
-        .unwrap_or(false);
-
-    Ok(WslConfig { enabled })
-}
-
-#[tauri::command]
-#[specta::specta]
-pub fn set_wsl_config(app: AppHandle, config: WslConfig) -> Result<(), String> {
-    let store = app
-        .store(SETTINGS_STORE)
-        .map_err(|e| format!("Failed to open settings store: {}", e))?;
-
-    store.set(WSL_ENABLED_KEY, serde_json::Value::Bool(config.enabled));
-
-    store
-        .save()
-        .map_err(|e| format!("Failed to save settings: {}", e))?;
-
-    Ok(())
-}
-
 pub async fn get_saved_server_url(app: &tauri::AppHandle) -> Option<String> {
     if let Some(url) = get_default_server_url(app.clone()).ok().flatten() {
         tracing::info!(%url, "Using desktop-specific custom URL");

+ 1 - 10
packages/desktop/src-tauri/src/windows.rs

@@ -1,7 +1,4 @@
-use crate::{
-    constants::{UPDATER_ENABLED, window_state_flags},
-    server::get_wsl_config,
-};
+use crate::constants::{UPDATER_ENABLED, window_state_flags};
 use std::{ops::Deref, time::Duration};
 use tauri::{AppHandle, Manager, Runtime, WebviewUrl, WebviewWindow, WebviewWindowBuilder};
 use tauri_plugin_window_state::AppHandleExt;
@@ -25,11 +22,6 @@ impl MainWindow {
             return Ok(Self(window));
         }
 
-        let wsl_enabled = get_wsl_config(app.clone())
-            .ok()
-            .map(|v| v.enabled)
-            .unwrap_or(false);
-
         let window_builder = base_window_config(
             WebviewWindowBuilder::new(app, Self::LABEL, WebviewUrl::App("/".into())),
             app,
@@ -44,7 +36,6 @@ impl MainWindow {
             r#"
             window.__OPENCODE__ ??= {{}};
             window.__OPENCODE__.updaterEnabled = {UPDATER_ENABLED};
-            window.__OPENCODE__.wsl = {wsl_enabled};
           "#
         ));
 

+ 0 - 9
packages/desktop/src/bindings.ts

@@ -10,13 +10,10 @@ export const commands = {
 	awaitInitialization: (events: Channel) => __TAURI_INVOKE<ServerReadyData>("await_initialization", { events }),
 	getDefaultServerUrl: () => __TAURI_INVOKE<string | null>("get_default_server_url"),
 	setDefaultServerUrl: (url: string | null) => __TAURI_INVOKE<null>("set_default_server_url", { url }),
-	getWslConfig: () => __TAURI_INVOKE<WslConfig>("get_wsl_config"),
-	setWslConfig: (config: WslConfig) => __TAURI_INVOKE<null>("set_wsl_config", { config }),
 	getDisplayBackend: () => __TAURI_INVOKE<"wayland" | "auto" | null>("get_display_backend"),
 	setDisplayBackend: (backend: LinuxDisplayBackend) => __TAURI_INVOKE<null>("set_display_backend", { backend }),
 	parseMarkdownCommand: (markdown: string) => __TAURI_INVOKE<string>("parse_markdown_command", { markdown }),
 	checkAppExists: (appName: string) => __TAURI_INVOKE<boolean>("check_app_exists", { appName }),
-	wslPath: (path: string, mode: "windows" | "linux" | null) => __TAURI_INVOKE<string>("wsl_path", { path, mode }),
 	resolveAppPath: (appName: string) => __TAURI_INVOKE<string | null>("resolve_app_path", { appName }),
 };
 
@@ -37,12 +34,6 @@ export type ServerReadyData = {
 		password: string | null,
 	};
 
-export type WslConfig = {
-		enabled: boolean,
-	};
-
-export type WslPathMode = "windows" | "linux";
-
 /* Tauri Specta runtime */
 function makeEvent<T>(name: string) {
     const base = {

+ 301 - 337
packages/desktop/src/index.tsx

@@ -16,6 +16,7 @@ import { open as shellOpen } from "@tauri-apps/plugin-shell"
 import { type as ostype } from "@tauri-apps/plugin-os"
 import { check, Update } from "@tauri-apps/plugin-updater"
 import { getCurrentWindow } from "@tauri-apps/api/window"
+import { invoke } from "@tauri-apps/api/core"
 import { isPermissionGranted, requestPermission } from "@tauri-apps/plugin-notification"
 import { relaunch } from "@tauri-apps/plugin-process"
 import { AsyncStorage } from "@solid-primitives/storage"
@@ -29,7 +30,7 @@ import { UPDATER_ENABLED } from "./updater"
 import { initI18n, t } from "./i18n"
 import pkg from "../package.json"
 import "./styles.css"
-import { commands, InitStep, type WslConfig } from "./bindings"
+import { commands, InitStep } from "./bindings"
 import { Channel } from "@tauri-apps/api/core"
 import { createMenu } from "./menu"
 
@@ -58,374 +59,338 @@ const listenForDeepLinks = async () => {
   await onOpenUrl((urls) => emitDeepLinks(urls)).catch(() => undefined)
 }
 
-const createPlatform = (password: Accessor<string | null>): Platform => {
-  const os = (() => {
+const createPlatform = (password: Accessor<string | null>): Platform => ({
+  platform: "desktop",
+  os: (() => {
     const type = ostype()
     if (type === "macos" || type === "windows" || type === "linux") return type
     return undefined
-  })()
-
-  const wslHome = async () => {
-    if (os !== "windows" || !window.__OPENCODE__?.wsl) return undefined
-    return commands.wslPath("~", "windows").catch(() => undefined)
-  }
+  })(),
+  version: pkg.version,
+
+  async openDirectoryPickerDialog(opts) {
+    const result = await open({
+      directory: true,
+      multiple: opts?.multiple ?? false,
+      title: opts?.title ?? t("desktop.dialog.chooseFolder"),
+    })
+    return result
+  },
+
+  async openFilePickerDialog(opts) {
+    const result = await open({
+      directory: false,
+      multiple: opts?.multiple ?? false,
+      title: opts?.title ?? t("desktop.dialog.chooseFile"),
+    })
+    return result
+  },
 
-  const handleWslPicker = async <T extends string | string[]>(result: T | null): Promise<T | null> => {
-    if (!result || !window.__OPENCODE__?.wsl) return result
-    if (Array.isArray(result)) {
-      return Promise.all(result.map((path) => commands.wslPath(path, "linux").catch(() => path))) as any
+  async saveFilePickerDialog(opts) {
+    const result = await save({
+      title: opts?.title ?? t("desktop.dialog.saveFile"),
+      defaultPath: opts?.defaultPath,
+    })
+    return result
+  },
+
+  openLink(url: string) {
+    void shellOpen(url).catch(() => undefined)
+  },
+
+  async openPath(path: string, app?: string) {
+    const os = ostype()
+    if (os === "windows" && app) {
+      const resolvedApp = await commands.resolveAppPath(app)
+      return openerOpenPath(path, resolvedApp || app)
+    }
+    return openerOpenPath(path, app)
+  },
+
+  back() {
+    window.history.back()
+  },
+
+  forward() {
+    window.history.forward()
+  },
+
+  storage: (() => {
+    type StoreLike = {
+      get(key: string): Promise<string | null | undefined>
+      set(key: string, value: string): Promise<unknown>
+      delete(key: string): Promise<unknown>
+      clear(): Promise<unknown>
+      keys(): Promise<string[]>
+      length(): Promise<number>
     }
-    return commands.wslPath(result, "linux").catch(() => result) as any
-  }
-
-  return {
-    platform: "desktop",
-    os,
-    version: pkg.version,
-
-    async openDirectoryPickerDialog(opts) {
-      const defaultPath = await wslHome()
-      const result = await open({
-        directory: true,
-        multiple: opts?.multiple ?? false,
-        title: opts?.title ?? t("desktop.dialog.chooseFolder"),
-        defaultPath,
-      })
-      return await handleWslPicker(result)
-    },
-
-    async openFilePickerDialog(opts) {
-      const result = await open({
-        directory: false,
-        multiple: opts?.multiple ?? false,
-        title: opts?.title ?? t("desktop.dialog.chooseFile"),
-      })
-      return handleWslPicker(result)
-    },
-
-    async saveFilePickerDialog(opts) {
-      const result = await save({
-        title: opts?.title ?? t("desktop.dialog.saveFile"),
-        defaultPath: opts?.defaultPath,
-      })
-      return handleWslPicker(result)
-    },
-
-    openLink(url: string) {
-      void shellOpen(url).catch(() => undefined)
-    },
-    async openPath(path: string, app?: string) {
-      const os = ostype()
-      if (os === "windows") {
-        const resolvedApp = (app && (await commands.resolveAppPath(app))) || app
-        const resolvedPath = await (async () => {
-          if (window.__OPENCODE__?.wsl) {
-            const converted = await commands.wslPath(path, "windows").catch(() => null)
-            if (converted) return converted
-          }
 
-          return path
-        })()
-        return openerOpenPath(resolvedPath, resolvedApp)
-      }
-      return openerOpenPath(path, app)
-    },
-
-    back() {
-      window.history.back()
-    },
-
-    forward() {
-      window.history.forward()
-    },
-
-    storage: (() => {
-      type StoreLike = {
-        get(key: string): Promise<string | null | undefined>
-        set(key: string, value: string): Promise<unknown>
-        delete(key: string): Promise<unknown>
-        clear(): Promise<unknown>
-        keys(): Promise<string[]>
-        length(): Promise<number>
-      }
+    const WRITE_DEBOUNCE_MS = 250
 
-      const WRITE_DEBOUNCE_MS = 250
+    const storeCache = new Map<string, Promise<StoreLike>>()
+    const apiCache = new Map<string, AsyncStorage & { flush: () => Promise<void> }>()
+    const memoryCache = new Map<string, StoreLike>()
 
-      const storeCache = new Map<string, Promise<StoreLike>>()
-      const apiCache = new Map<string, AsyncStorage & { flush: () => Promise<void> }>()
-      const memoryCache = new Map<string, StoreLike>()
+    const flushAll = async () => {
+      const apis = Array.from(apiCache.values())
+      await Promise.all(apis.map((api) => api.flush().catch(() => undefined)))
+    }
 
-      const flushAll = async () => {
-        const apis = Array.from(apiCache.values())
-        await Promise.all(apis.map((api) => api.flush().catch(() => undefined)))
+    if ("addEventListener" in globalThis) {
+      const handleVisibility = () => {
+        if (document.visibilityState !== "hidden") return
+        void flushAll()
       }
 
-      if ("addEventListener" in globalThis) {
-        const handleVisibility = () => {
-          if (document.visibilityState !== "hidden") return
-          void flushAll()
-        }
+      window.addEventListener("pagehide", () => void flushAll())
+      document.addEventListener("visibilitychange", handleVisibility)
+    }
 
-        window.addEventListener("pagehide", () => void flushAll())
-        document.addEventListener("visibilitychange", handleVisibility)
+    const createMemoryStore = () => {
+      const data = new Map<string, string>()
+      const store: StoreLike = {
+        get: async (key) => data.get(key),
+        set: async (key, value) => {
+          data.set(key, value)
+        },
+        delete: async (key) => {
+          data.delete(key)
+        },
+        clear: async () => {
+          data.clear()
+        },
+        keys: async () => Array.from(data.keys()),
+        length: async () => data.size,
       }
+      return store
+    }
 
-      const createMemoryStore = () => {
-        const data = new Map<string, string>()
-        const store: StoreLike = {
-          get: async (key) => data.get(key),
-          set: async (key, value) => {
-            data.set(key, value)
-          },
-          delete: async (key) => {
-            data.delete(key)
-          },
-          clear: async () => {
-            data.clear()
-          },
-          keys: async () => Array.from(data.keys()),
-          length: async () => data.size,
-        }
-        return store
-      }
+    const getStore = (name: string) => {
+      const cached = storeCache.get(name)
+      if (cached) return cached
 
-      const getStore = (name: string) => {
-        const cached = storeCache.get(name)
+      const store = Store.load(name).catch(() => {
+        const cached = memoryCache.get(name)
         if (cached) return cached
 
-        const store = Store.load(name).catch(() => {
-          const cached = memoryCache.get(name)
-          if (cached) return cached
+        const memory = createMemoryStore()
+        memoryCache.set(name, memory)
+        return memory
+      })
 
-          const memory = createMemoryStore()
-          memoryCache.set(name, memory)
-          return memory
-        })
+      storeCache.set(name, store)
+      return store
+    }
 
-        storeCache.set(name, store)
-        return store
-      }
+    const createStorage = (name: string) => {
+      const pending = new Map<string, string | null>()
+      let timer: ReturnType<typeof setTimeout> | undefined
+      let flushing: Promise<void> | undefined
 
-      const createStorage = (name: string) => {
-        const pending = new Map<string, string | null>()
-        let timer: ReturnType<typeof setTimeout> | undefined
-        let flushing: Promise<void> | undefined
-
-        const flush = async () => {
-          if (flushing) return flushing
-
-          flushing = (async () => {
-            const store = await getStore(name)
-            while (pending.size > 0) {
-              const batch = Array.from(pending.entries())
-              pending.clear()
-              for (const [key, value] of batch) {
-                if (value === null) {
-                  await store.delete(key).catch(() => undefined)
-                } else {
-                  await store.set(key, value).catch(() => undefined)
-                }
+      const flush = async () => {
+        if (flushing) return flushing
+
+        flushing = (async () => {
+          const store = await getStore(name)
+          while (pending.size > 0) {
+            const batch = Array.from(pending.entries())
+            pending.clear()
+            for (const [key, value] of batch) {
+              if (value === null) {
+                await store.delete(key).catch(() => undefined)
+              } else {
+                await store.set(key, value).catch(() => undefined)
               }
             }
-          })().finally(() => {
-            flushing = undefined
-          })
-
-          return flushing
-        }
+          }
+        })().finally(() => {
+          flushing = undefined
+        })
 
-        const schedule = () => {
-          if (timer) return
-          timer = setTimeout(() => {
-            timer = undefined
-            void flush()
-          }, WRITE_DEBOUNCE_MS)
-        }
+        return flushing
+      }
 
-        const api: AsyncStorage & { flush: () => Promise<void> } = {
-          flush,
-          getItem: async (key: string) => {
-            const next = pending.get(key)
-            if (next !== undefined) return next
-
-            const store = await getStore(name)
-            const value = await store.get(key).catch(() => null)
-            if (value === undefined) return null
-            return value
-          },
-          setItem: async (key: string, value: string) => {
-            pending.set(key, value)
-            schedule()
-          },
-          removeItem: async (key: string) => {
-            pending.set(key, null)
-            schedule()
-          },
-          clear: async () => {
-            pending.clear()
-            const store = await getStore(name)
-            await store.clear().catch(() => undefined)
-          },
-          key: async (index: number) => {
-            const store = await getStore(name)
-            return (await store.keys().catch(() => []))[index]
-          },
-          getLength: async () => {
-            const store = await getStore(name)
-            return await store.length().catch(() => 0)
-          },
-          get length() {
-            return api.getLength()
-          },
-        }
+      const schedule = () => {
+        if (timer) return
+        timer = setTimeout(() => {
+          timer = undefined
+          void flush()
+        }, WRITE_DEBOUNCE_MS)
+      }
 
-        return api
+      const api: AsyncStorage & { flush: () => Promise<void> } = {
+        flush,
+        getItem: async (key: string) => {
+          const next = pending.get(key)
+          if (next !== undefined) return next
+
+          const store = await getStore(name)
+          const value = await store.get(key).catch(() => null)
+          if (value === undefined) return null
+          return value
+        },
+        setItem: async (key: string, value: string) => {
+          pending.set(key, value)
+          schedule()
+        },
+        removeItem: async (key: string) => {
+          pending.set(key, null)
+          schedule()
+        },
+        clear: async () => {
+          pending.clear()
+          const store = await getStore(name)
+          await store.clear().catch(() => undefined)
+        },
+        key: async (index: number) => {
+          const store = await getStore(name)
+          return (await store.keys().catch(() => []))[index]
+        },
+        getLength: async () => {
+          const store = await getStore(name)
+          return await store.length().catch(() => 0)
+        },
+        get length() {
+          return api.getLength()
+        },
       }
 
-      return (name = "default.dat") => {
-        const cached = apiCache.get(name)
-        if (cached) return cached
+      return api
+    }
 
-        const api = createStorage(name)
-        apiCache.set(name, api)
-        return api
-      }
-    })(),
-
-    checkUpdate: async () => {
-      if (!UPDATER_ENABLED) return { updateAvailable: false }
-      const next = await check().catch(() => null)
-      if (!next) return { updateAvailable: false }
-      const ok = await next
-        .download()
-        .then(() => true)
-        .catch(() => false)
-      if (!ok) return { updateAvailable: false }
-      update = next
-      return { updateAvailable: true, version: next.version }
-    },
-
-    update: async () => {
-      if (!UPDATER_ENABLED || !update) return
-      if (ostype() === "windows") await commands.killSidecar().catch(() => undefined)
-      await update.install().catch(() => undefined)
-    },
-
-    restart: async () => {
-      await commands.killSidecar().catch(() => undefined)
-      await relaunch()
-    },
-
-    notify: async (title, description, href) => {
-      const granted = await isPermissionGranted().catch(() => false)
-      const permission = granted ? "granted" : await requestPermission().catch(() => "denied")
-      if (permission !== "granted") return
-
-      const win = getCurrentWindow()
-      const focused = await win.isFocused().catch(() => document.hasFocus())
-      if (focused) return
-
-      await Promise.resolve()
-        .then(() => {
-          const notification = new Notification(title, {
-            body: description ?? "",
-            icon: "https://opencode.ai/favicon-96x96-v3.png",
-          })
-          notification.onclick = () => {
-            const win = getCurrentWindow()
-            void win.show().catch(() => undefined)
-            void win.unminimize().catch(() => undefined)
-            void win.setFocus().catch(() => undefined)
-            if (href) {
-              window.history.pushState(null, "", href)
-              window.dispatchEvent(new PopStateEvent("popstate"))
-            }
-            notification.close()
-          }
+    return (name = "default.dat") => {
+      const cached = apiCache.get(name)
+      if (cached) return cached
+
+      const api = createStorage(name)
+      apiCache.set(name, api)
+      return api
+    }
+  })(),
+
+  checkUpdate: async () => {
+    if (!UPDATER_ENABLED) return { updateAvailable: false }
+    const next = await check().catch(() => null)
+    if (!next) return { updateAvailable: false }
+    const ok = await next
+      .download()
+      .then(() => true)
+      .catch(() => false)
+    if (!ok) return { updateAvailable: false }
+    update = next
+    return { updateAvailable: true, version: next.version }
+  },
+
+  update: async () => {
+    if (!UPDATER_ENABLED || !update) return
+    if (ostype() === "windows") await commands.killSidecar().catch(() => undefined)
+    await update.install().catch(() => undefined)
+  },
+
+  restart: async () => {
+    await commands.killSidecar().catch(() => undefined)
+    await relaunch()
+  },
+
+  notify: async (title, description, href) => {
+    const granted = await isPermissionGranted().catch(() => false)
+    const permission = granted ? "granted" : await requestPermission().catch(() => "denied")
+    if (permission !== "granted") return
+
+    const win = getCurrentWindow()
+    const focused = await win.isFocused().catch(() => document.hasFocus())
+    if (focused) return
+
+    await Promise.resolve()
+      .then(() => {
+        const notification = new Notification(title, {
+          body: description ?? "",
+          icon: "https://opencode.ai/favicon-96x96-v3.png",
         })
-        .catch(() => undefined)
-    },
+        notification.onclick = () => {
+          const win = getCurrentWindow()
+          void win.show().catch(() => undefined)
+          void win.unminimize().catch(() => undefined)
+          void win.setFocus().catch(() => undefined)
+          if (href) {
+            window.history.pushState(null, "", href)
+            window.dispatchEvent(new PopStateEvent("popstate"))
+          }
+          notification.close()
+        }
+      })
+      .catch(() => undefined)
+  },
 
-    fetch: (input, init) => {
-      const pw = password()
+  fetch: (input, init) => {
+    const pw = password()
 
-      const addHeader = (headers: Headers, password: string) => {
-        headers.append("Authorization", `Basic ${btoa(`opencode:${password}`)}`)
-      }
+    const addHeader = (headers: Headers, password: string) => {
+      headers.append("Authorization", `Basic ${btoa(`opencode:${password}`)}`)
+    }
 
-      if (input instanceof Request) {
-        if (pw) addHeader(input.headers, pw)
-        return tauriFetch(input)
-      } else {
-        const headers = new Headers(init?.headers)
-        if (pw) addHeader(headers, pw)
-        return tauriFetch(input, {
-          ...(init as any),
-          headers: headers,
-        })
-      }
-    },
-
-    getWslEnabled: async () => {
-      const next = await commands.getWslConfig().catch(() => null)
-      if (next) return next.enabled
-      return window.__OPENCODE__!.wsl ?? false
-    },
-
-    setWslEnabled: async (enabled) => {
-      await commands.setWslConfig({ enabled })
-    },
-
-    getDefaultServerUrl: async () => {
-      const result = await commands.getDefaultServerUrl().catch(() => null)
-      return result
-    },
-
-    setDefaultServerUrl: async (url: string | null) => {
-      await commands.setDefaultServerUrl(url)
-    },
-
-    getDisplayBackend: async () => {
-      const result = await commands.getDisplayBackend().catch(() => null)
-      return result
-    },
-
-    setDisplayBackend: async (backend) => {
-      await commands.setDisplayBackend(backend)
-    },
-
-    parseMarkdown: (markdown: string) => commands.parseMarkdownCommand(markdown),
-
-    webviewZoom,
-
-    checkAppExists: async (appName: string) => {
-      return commands.checkAppExists(appName)
-    },
-
-    async readClipboardImage() {
-      const image = await readImage().catch(() => null)
-      if (!image) return null
-      const bytes = await image.rgba().catch(() => null)
-      if (!bytes || bytes.length === 0) return null
-      const size = await image.size().catch(() => null)
-      if (!size) return null
-      const canvas = document.createElement("canvas")
-      canvas.width = size.width
-      canvas.height = size.height
-      const ctx = canvas.getContext("2d")
-      if (!ctx) return null
-      const imageData = ctx.createImageData(size.width, size.height)
-      imageData.data.set(bytes)
-      ctx.putImageData(imageData, 0, 0)
-      return new Promise<File | null>((resolve) => {
-        canvas.toBlob((blob) => {
-          if (!blob) return resolve(null)
-          resolve(new File([blob], `pasted-image-${Date.now()}.png`, { type: "image/png" }))
-        }, "image/png")
+    if (input instanceof Request) {
+      if (pw) addHeader(input.headers, pw)
+      return tauriFetch(input)
+    } else {
+      const headers = new Headers(init?.headers)
+      if (pw) addHeader(headers, pw)
+      return tauriFetch(input, {
+        ...(init as any),
+        headers: headers,
       })
-    },
-  }
-}
+    }
+  },
+
+  getDefaultServerUrl: async () => {
+    const result = await commands.getDefaultServerUrl().catch(() => null)
+    return result
+  },
+
+  setDefaultServerUrl: async (url: string | null) => {
+    await commands.setDefaultServerUrl(url)
+  },
+
+  getDisplayBackend: async () => {
+    const result = await invoke<DisplayBackend | null>("get_display_backend").catch(() => null)
+    return result
+  },
+
+  setDisplayBackend: async (backend) => {
+    await invoke("set_display_backend", { backend }).catch(() => undefined)
+  },
+
+  parseMarkdown: (markdown: string) => commands.parseMarkdownCommand(markdown),
+
+  webviewZoom,
+
+  checkAppExists: async (appName: string) => {
+    return commands.checkAppExists(appName)
+  },
+
+  async readClipboardImage() {
+    const image = await readImage().catch(() => null)
+    if (!image) return null
+    const bytes = await image.rgba().catch(() => null)
+    if (!bytes || bytes.length === 0) return null
+    const size = await image.size().catch(() => null)
+    if (!size) return null
+    const canvas = document.createElement("canvas")
+    canvas.width = size.width
+    canvas.height = size.height
+    const ctx = canvas.getContext("2d")
+    if (!ctx) return null
+    const imageData = ctx.createImageData(size.width, size.height)
+    imageData.data.set(bytes)
+    ctx.putImageData(imageData, 0, 0)
+    return new Promise<File | null>((resolve) => {
+      canvas.toBlob((blob) => {
+        if (!blob) return resolve(null)
+        resolve(new File([blob], `pasted-image-${Date.now()}.png`, { type: "image/png" }))
+      }, "image/png")
+    })
+  },
+})
 
 let menuTrigger = null as null | ((id: string) => void)
 createMenu((id) => {
@@ -435,7 +400,6 @@ void listenForDeepLinks()
 
 render(() => {
   const [serverPassword, setServerPassword] = createSignal<string | null>(null)
-
   const platform = createPlatform(() => serverPassword())
 
   function handleClick(e: MouseEvent) {