diff --git a/packages/app/src/app.tsx b/packages/app/src/app.tsx
index 5bbe86e2093d..e49b725a1975 100644
--- a/packages/app/src/app.tsx
+++ b/packages/app/src/app.tsx
@@ -43,7 +43,7 @@ function UiI18nBridge(props: ParentProps) {
declare global {
interface Window {
- __OPENCODE__?: { updaterEnabled?: boolean; serverPassword?: string; deepLinks?: string[] }
+ __OPENCODE__?: { updaterEnabled?: boolean; serverPassword?: string; deepLinks?: string[]; wsl?: boolean }
}
}
diff --git a/packages/app/src/components/settings-general.tsx b/packages/app/src/components/settings-general.tsx
index db057a4c41f7..72135c342e53 100644
--- a/packages/app/src/components/settings-general.tsx
+++ b/packages/app/src/components/settings-general.tsx
@@ -367,6 +367,34 @@ export const SettingsGeneral: Component = () => {
+
+ {(_) => {
+ const [enabledResource, actions] = createResource(() => platform.getWslEnabled?.())
+ const enabled = () => (enabledResource.state === "pending" ? undefined : enabledResource.latest)
+
+ return (
+
+
{language.t("settings.desktop.section.wsl")}
+
+
+
+
+ platform.setWslEnabled?.(checked)?.finally(() => actions.refetch())}
+ />
+
+
+
+
+ )
+ }}
+
+
{/* Updates Section */}
{language.t("settings.general.section.updates")}
diff --git a/packages/app/src/context/platform.tsx b/packages/app/src/context/platform.tsx
index 7aa6c6554006..e260c1977ed9 100644
--- a/packages/app/src/context/platform.tsx
+++ b/packages/app/src/context/platform.tsx
@@ -57,6 +57,12 @@ export type Platform = {
/** Set the default server URL to use on app startup (platform-specific) */
setDefaultServerUrl?(url: string | null): Promise | void
+ /** Get the configured WSL integration (desktop only) */
+ getWslEnabled?(): Promise
+
+ /** Set the configured WSL integration (desktop only) */
+ setWslEnabled?(config: boolean): Promise | void
+
/** Get the preferred display backend (desktop only) */
getDisplayBackend?(): Promise | DisplayBackend | null
diff --git a/packages/app/src/i18n/ar.ts b/packages/app/src/i18n/ar.ts
index 201d63660a39..7a09edc51842 100644
--- a/packages/app/src/i18n/ar.ts
+++ b/packages/app/src/i18n/ar.ts
@@ -508,6 +508,9 @@ 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": "إشعارات النظام",
diff --git a/packages/app/src/i18n/br.ts b/packages/app/src/i18n/br.ts
index b7f2d74857f7..ba09fbe03db0 100644
--- a/packages/app/src/i18n/br.ts
+++ b/packages/app/src/i18n/br.ts
@@ -512,6 +512,9 @@ 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",
diff --git a/packages/app/src/i18n/bs.ts b/packages/app/src/i18n/bs.ts
index 05eca1628e5e..38d6b79c94d9 100644
--- a/packages/app/src/i18n/bs.ts
+++ b/packages/app/src/i18n/bs.ts
@@ -539,6 +539,9 @@ 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",
diff --git a/packages/app/src/i18n/da.ts b/packages/app/src/i18n/da.ts
index 8ea4907c1b67..e36fb16d5b74 100644
--- a/packages/app/src/i18n/da.ts
+++ b/packages/app/src/i18n/da.ts
@@ -512,6 +512,9 @@ 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",
diff --git a/packages/app/src/i18n/de.ts b/packages/app/src/i18n/de.ts
index a4884a1033dc..633d51d05289 100644
--- a/packages/app/src/i18n/de.ts
+++ b/packages/app/src/i18n/de.ts
@@ -556,6 +556,9 @@ 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",
diff --git a/packages/app/src/i18n/en.ts b/packages/app/src/i18n/en.ts
index b0ffa70f84de..c138c7b61456 100644
--- a/packages/app/src/i18n/en.ts
+++ b/packages/app/src/i18n/en.ts
@@ -583,6 +583,9 @@ 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",
diff --git a/packages/app/src/i18n/es.ts b/packages/app/src/i18n/es.ts
index 50d9060703ea..ff4198228a5b 100644
--- a/packages/app/src/i18n/es.ts
+++ b/packages/app/src/i18n/es.ts
@@ -515,6 +515,9 @@ 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",
diff --git a/packages/app/src/i18n/fr.ts b/packages/app/src/i18n/fr.ts
index 7ad39f340639..402c095ba59d 100644
--- a/packages/app/src/i18n/fr.ts
+++ b/packages/app/src/i18n/fr.ts
@@ -522,6 +522,9 @@ 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",
diff --git a/packages/app/src/i18n/ja.ts b/packages/app/src/i18n/ja.ts
index a39bfbaf331b..312ac3262c78 100644
--- a/packages/app/src/i18n/ja.ts
+++ b/packages/app/src/i18n/ja.ts
@@ -507,6 +507,9 @@ 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": "システム通知",
diff --git a/packages/app/src/i18n/ko.ts b/packages/app/src/i18n/ko.ts
index b5927b210767..b162ab3916ef 100644
--- a/packages/app/src/i18n/ko.ts
+++ b/packages/app/src/i18n/ko.ts
@@ -513,6 +513,9 @@ 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": "시스템 알림",
diff --git a/packages/app/src/i18n/no.ts b/packages/app/src/i18n/no.ts
index 7d8cdd27f3dd..001b9eda6568 100644
--- a/packages/app/src/i18n/no.ts
+++ b/packages/app/src/i18n/no.ts
@@ -515,6 +515,9 @@ 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",
diff --git a/packages/app/src/i18n/pl.ts b/packages/app/src/i18n/pl.ts
index 76a47ea26f8d..2a20cd57e39c 100644
--- a/packages/app/src/i18n/pl.ts
+++ b/packages/app/src/i18n/pl.ts
@@ -514,6 +514,9 @@ 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",
diff --git a/packages/app/src/i18n/ru.ts b/packages/app/src/i18n/ru.ts
index e83ce37618c5..698c8db5819e 100644
--- a/packages/app/src/i18n/ru.ts
+++ b/packages/app/src/i18n/ru.ts
@@ -517,6 +517,9 @@ 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": "Системные уведомления",
diff --git a/packages/app/src/i18n/th.ts b/packages/app/src/i18n/th.ts
index 2be19d15b174..161f37f3ba2e 100644
--- a/packages/app/src/i18n/th.ts
+++ b/packages/app/src/i18n/th.ts
@@ -516,6 +516,9 @@ 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": "การแจ้งเตือนระบบ",
diff --git a/packages/app/src/i18n/zh.ts b/packages/app/src/i18n/zh.ts
index a48f9e549415..a2931cf98c81 100644
--- a/packages/app/src/i18n/zh.ts
+++ b/packages/app/src/i18n/zh.ts
@@ -548,6 +548,9 @@ 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": "系统通知",
diff --git a/packages/app/src/i18n/zht.ts b/packages/app/src/i18n/zht.ts
index 60363fc99eff..cae0c75b46c4 100644
--- a/packages/app/src/i18n/zht.ts
+++ b/packages/app/src/i18n/zht.ts
@@ -545,6 +545,9 @@ 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": "系統通知",
diff --git a/packages/desktop/AGENTS.md b/packages/desktop/AGENTS.md
new file mode 100644
index 000000000000..3839db1a9041
--- /dev/null
+++ b/packages/desktop/AGENTS.md
@@ -0,0 +1,4 @@
+# Desktop package notes
+
+- Never call `invoke` manually in this package.
+- Use the generated bindings in `packages/desktop/src/bindings.ts` for core commands/events.
diff --git a/packages/desktop/src-tauri/src/cli.rs b/packages/desktop/src-tauri/src/cli.rs
index 98c38677b4f2..6882d369e935 100644
--- a/packages/desktop/src-tauri/src/cli.rs
+++ b/packages/desktop/src-tauri/src/cli.rs
@@ -3,8 +3,12 @@ use tauri_plugin_shell::{
ShellExt,
process::{Command, CommandChild, CommandEvent},
};
+use tauri_plugin_store::StoreExt;
-use crate::{LogState, constants::MAX_LOG_ENTRIES};
+use crate::{
+ LogState,
+ constants::{MAX_LOG_ENTRIES, SETTINGS_STORE, WSL_ENABLED_KEY},
+};
const CLI_INSTALL_DIR: &str = ".opencode/bin";
const CLI_BINARY_NAME: &str = "opencode";
@@ -21,7 +25,7 @@ pub struct Config {
}
pub async fn get_config(app: &AppHandle) -> Option {
- create_command(app, "debug config")
+ create_command(app, "debug config", &[])
.output()
.await
.inspect_err(|e| eprintln!("Failed to read OC config: {e}"))
@@ -150,25 +154,106 @@ fn get_user_shell() -> String {
std::env::var("SHELL").unwrap_or_else(|_| "/bin/sh".to_string())
}
-pub fn create_command(app: &tauri::AppHandle, args: &str) -> Command {
+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 {
let state_dir = app
.path()
.resolve("", BaseDirectory::AppLocalData)
.expect("Failed to resolve app local data dir");
- #[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 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) {
+ println!("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 {
let sidecar = get_sidecar_path(app);
let shell = get_user_shell();
@@ -178,14 +263,14 @@ pub fn create_command(app: &tauri::AppHandle, args: &str) -> Command {
format!("\"{}\" {}", sidecar.display(), args)
};
- 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])
- };
+ let mut cmd = app.shell().command(&shell).args(["-il", "-c", &cmd]);
+
+ for (key, value) in envs {
+ cmd = cmd.env(key, value);
+ }
+
+ cmd
+ }
}
pub fn serve(app: &AppHandle, hostname: &str, port: u32, password: &str) -> CommandChild {
@@ -194,12 +279,16 @@ pub fn serve(app: &AppHandle, hostname: &str, port: u32, password: &str) -> Comm
println!("spawning sidecar on port {port}");
+ let envs = [
+ ("OPENCODE_SERVER_USERNAME", "opencode".to_string()),
+ ("OPENCODE_SERVER_PASSWORD", password.to_string()),
+ ];
+
let (mut rx, child) = create_command(
app,
format!("serve --hostname {hostname} --port {port}").as_str(),
+ &envs,
)
- .env("OPENCODE_SERVER_USERNAME", "opencode")
- .env("OPENCODE_SERVER_PASSWORD", password)
.spawn()
.expect("Failed to spawn opencode");
diff --git a/packages/desktop/src-tauri/src/constants.rs b/packages/desktop/src-tauri/src/constants.rs
index ac3e1d02adb6..cdf05fb458b1 100644
--- a/packages/desktop/src-tauri/src/constants.rs
+++ b/packages/desktop/src-tauri/src/constants.rs
@@ -2,6 +2,7 @@ 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 const MAX_LOG_ENTRIES: usize = 200;
diff --git a/packages/desktop/src-tauri/src/lib.rs b/packages/desktop/src-tauri/src/lib.rs
index 82f0441ad3eb..5c3915e81a8a 100644
--- a/packages/desktop/src-tauri/src/lib.rs
+++ b/packages/desktop/src-tauri/src/lib.rs
@@ -52,6 +52,13 @@ enum InitStep {
Done,
}
+#[derive(serde::Deserialize, specta::Type)]
+#[serde(rename_all = "snake_case")]
+enum WslPathMode {
+ Windows,
+ Linux,
+}
+
struct InitState {
current: watch::Receiver,
}
@@ -392,32 +399,50 @@ fn check_linux_app(app_name: &str) -> bool {
return true;
}
+#[tauri::command]
+#[specta::specta]
+fn wsl_path(path: String, mode: Option) -> Result {
+ 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 = tauri_specta::Builder::::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);
+ let builder = make_specta_builder();
#[cfg(debug_assertions)] // <- Only export on non-release builds
- builder
- .export(
- specta_typescript::Typescript::default(),
- "../src/bindings.ts",
- )
- .expect("Failed to export typescript bindings");
+ export_types(&builder);
#[cfg(all(target_os = "macos", not(debug_assertions)))]
let _ = std::process::Command::new("killall")
@@ -476,6 +501,44 @@ pub fn run() {
});
}
+fn make_specta_builder() -> tauri_specta::Builder {
+ tauri_specta::Builder::::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) {
+ 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;
diff --git a/packages/desktop/src-tauri/src/server.rs b/packages/desktop/src-tauri/src/server.rs
index 2a78411a43a4..8113fc7e3109 100644
--- a/packages/desktop/src-tauri/src/server.rs
+++ b/packages/desktop/src-tauri/src/server.rs
@@ -8,9 +8,20 @@ use tokio::task::JoinHandle;
use crate::{
cli,
- constants::{DEFAULT_SERVER_URL_KEY, SETTINGS_STORE},
+ constants::{DEFAULT_SERVER_URL_KEY, SETTINGS_STORE, WSL_ENABLED_KEY},
};
+#[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