From 38151aec1bcdb58ddcbc36bb188f14dc68896432 Mon Sep 17 00:00:00 2001 From: Matias Galarza Date: Sun, 13 Sep 2026 02:52:32 -0300 Subject: [PATCH 1/3] fix(agent): resolve real HOME path before building shortcut paths /home is a symlink to /var/home on OSTree/atomic distros (Bazzite, Anatase). Steam's sandboxed runtime (pressure-vessel) does not follow that symlink, so a shortcut written under /home/user/... fails to launch: the Steam client logs chdir "/home/user/..." failed, errno 2 and the game never starts, even though the path resolves fine outside the sandbox. Closes #254 --- apps/agents/agent-tauri/src-tauri/src/helpers/paths.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/apps/agents/agent-tauri/src-tauri/src/helpers/paths.rs b/apps/agents/agent-tauri/src-tauri/src/helpers/paths.rs index a651125e..30993b08 100644 --- a/apps/agents/agent-tauri/src-tauri/src/helpers/paths.rs +++ b/apps/agents/agent-tauri/src-tauri/src/helpers/paths.rs @@ -1,8 +1,17 @@ /// Expands `~` in paths to the `$HOME` directory. +/// +/// Canonicalizes `$HOME` first: on OSTree/atomic distros (Bazzite, Anatase) +/// `/home` is a symlink to `/var/home`, and Steam's sandboxed runtime +/// (pressure-vessel) does not resolve it — a shortcut written as +/// `/home/user/...` fails to launch (`chdir` ENOENT) even though the path +/// is valid outside the sandbox. pub(crate) fn expand_path(path: &str) -> String { if path.starts_with("~/") && let Ok(home) = std::env::var("HOME") { + let home = std::fs::canonicalize(&home) + .map(|p| p.to_string_lossy().into_owned()) + .unwrap_or(home); return format!("{}{}", home, &path[1..]); } path.to_string() From bbf1f2e2b8fd2cb4d324de6c3a7e3f41022b9fe3 Mon Sep 17 00:00:00 2001 From: Matias Galarza Date: Sun, 13 Sep 2026 03:54:29 -0300 Subject: [PATCH 2/3] fix(hub-connection): clear pre-existing clippy lint failures result_large_err on WsError::Ws (boxed the tungstenite::Error variant) and for_kv_map in cancel_all_reconnects. Both were failing CI on this branch independently of the shortcut-path fix. --- crates/hub-connection/src/manager.rs | 2 +- crates/hub-connection/src/ws_client.rs | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/crates/hub-connection/src/manager.rs b/crates/hub-connection/src/manager.rs index 6cf596b8..a82b78bb 100644 --- a/crates/hub-connection/src/manager.rs +++ b/crates/hub-connection/src/manager.rs @@ -281,7 +281,7 @@ impl ConnectionManager { cancel_any_reconnect(&self.reconnect_cancel); // Set any Reconnecting agents to Disconnected. let mut states = self.state.write().await; - for (_, state) in states.iter_mut() { + for state in states.values_mut() { if matches!(state, ConnectionState::Reconnecting { .. }) { *state = ConnectionState::Disconnected; } diff --git a/crates/hub-connection/src/ws_client.rs b/crates/hub-connection/src/ws_client.rs index 797ff9a7..1f62bc2f 100644 --- a/crates/hub-connection/src/ws_client.rs +++ b/crates/hub-connection/src/ws_client.rs @@ -23,7 +23,7 @@ use capydeploy_protocol::messages::{ #[derive(Debug, thiserror::Error)] pub enum WsError { #[error("WebSocket error: {0}")] - Ws(#[from] tungstenite::Error), + Ws(#[from] Box), #[error("JSON error: {0}")] Json(#[from] serde_json::Error), @@ -88,7 +88,9 @@ impl WsClient { ws_config.max_message_size = Some(WS_MAX_MESSAGE_SIZE); ws_config.max_frame_size = Some(WS_MAX_MESSAGE_SIZE); let (ws_stream, _) = - tokio_tungstenite::connect_async_with_config(url, Some(ws_config), false).await?; + tokio_tungstenite::connect_async_with_config(url, Some(ws_config), false) + .await + .map_err(Box::new)?; let (write, read) = ws_stream.split(); let (write_tx, write_rx) = mpsc::channel::(256); From eca64e074611d08fe57d91ed539874e365594c24 Mon Sep 17 00:00:00 2001 From: Matias Galarza Date: Sun, 13 Sep 2026 03:59:12 -0300 Subject: [PATCH 3/3] fix(agent-server): box ServerError::WebSocket, same result_large_err lint Same pre-existing clippy failure as hub-connection, missed locally because incremental clippy cache had this crate marked clean from a prior run. Verified this time with a clean --target-dir. --- crates/agent-server/src/lib.rs | 2 +- crates/agent-server/src/server.rs | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/crates/agent-server/src/lib.rs b/crates/agent-server/src/lib.rs index bba53108..ecf53124 100644 --- a/crates/agent-server/src/lib.rs +++ b/crates/agent-server/src/lib.rs @@ -30,7 +30,7 @@ pub enum ServerError { Io(#[from] std::io::Error), #[error("WebSocket error: {0}")] - WebSocket(#[from] tokio_tungstenite::tungstenite::Error), + WebSocket(#[from] Box), #[error("JSON error: {0}")] Json(#[from] serde_json::Error), diff --git a/crates/agent-server/src/server.rs b/crates/agent-server/src/server.rs index 408c9c68..1c70907f 100644 --- a/crates/agent-server/src/server.rs +++ b/crates/agent-server/src/server.rs @@ -166,7 +166,9 @@ impl AgentServer { let mut ws_config = tokio_tungstenite::tungstenite::protocol::WebSocketConfig::default(); ws_config.max_message_size = Some(WS_MAX_MESSAGE_SIZE); ws_config.max_frame_size = Some(WS_MAX_MESSAGE_SIZE); - let ws_stream = accept_async_with_config(stream, Some(ws_config)).await?; + let ws_stream = accept_async_with_config(stream, Some(ws_config)) + .await + .map_err(Box::new)?; tracing::info!(%peer_addr, "WebSocket connection established"); let meta = HubMeta {