Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src-tauri/src/codex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,12 @@ pub(crate) async fn send_user_message(
app: AppHandle,
) -> Result<Value, String> {
if remote_backend::is_remote_mode(&*state).await {
let images = images.map(|paths| {
paths
.into_iter()
.map(remote_backend::normalize_path_for_remote)
.collect::<Vec<_>>()
});
return remote_backend::call_remote(
&*state,
app,
Expand Down
34 changes: 34 additions & 0 deletions src-tauri/src/remote_backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,40 @@ const DISCONNECTED_MESSAGE: &str = "remote backend disconnected";

type PendingMap = HashMap<u64, oneshot::Sender<Result<Value, String>>>;

pub(crate) fn normalize_path_for_remote(path: String) -> String {
let trimmed = path.trim();
if trimmed.is_empty() {
return path;
}

if let Some(normalized) = normalize_wsl_unc_path(trimmed) {
return normalized;
}

path
}

fn normalize_wsl_unc_path(path: &str) -> Option<String> {
let lower = path.to_ascii_lowercase();
let (prefix_len, raw) = if lower.starts_with("\\\\wsl$\\") {
(7, path)
} else if lower.starts_with("\\\\wsl.localhost\\") {
(16, path)
} else {
return None;
};

let remainder = raw.get(prefix_len..)?;
let mut segments = remainder.split('\\').filter(|segment| !segment.is_empty());
segments.next()?;
let joined = segments.collect::<Vec<_>>().join("/");
Some(if joined.is_empty() {
"/".to_string()
} else {
format!("/{joined}")
})
}

#[derive(Clone)]
pub(crate) struct RemoteBackend {
inner: Arc<RemoteBackendInner>,
Expand Down
50 changes: 50 additions & 0 deletions src-tauri/src/workspaces.rs
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,8 @@ pub(crate) async fn add_workspace(
app: AppHandle,
) -> Result<WorkspaceInfo, String> {
if remote_backend::is_remote_mode(&*state).await {
let path = remote_backend::normalize_path_for_remote(path);
let codex_bin = codex_bin.map(remote_backend::normalize_path_for_remote);
let response = remote_backend::call_remote(
&*state,
Comment on lines 518 to 522

Choose a reason for hiding this comment

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

P2 Badge Keep local workspace cache in sync in remote mode

In remote mode this early return skips updating state.workspaces, but git commands like get_git_status (src-tauri/src/git.rs) still resolve workspaces from that local cache. After adding a workspace in remote mode, those commands will now return “workspace not found,” so the git status/diff UI won’t refresh for the new workspace. Consider mirroring the remote response into state.workspaces (or proxying git commands) so the local cache stays consistent.

Useful? React with 👍 / 👎.

app,
Expand Down Expand Up @@ -719,6 +721,17 @@ pub(crate) async fn add_worktree(
state: State<'_, AppState>,
app: AppHandle,
) -> Result<WorkspaceInfo, String> {
if remote_backend::is_remote_mode(&*state).await {
let response = remote_backend::call_remote(
&*state,
app,
"add_worktree",
json!({ "parentId": parent_id, "branch": branch }),
)
.await?;
return serde_json::from_value(response).map_err(|err| err.to_string());
}

let branch = branch.trim();
if branch.is_empty() {
return Err("Branch name is required.".to_string());
Expand Down Expand Up @@ -812,7 +825,13 @@ pub(crate) async fn add_worktree(
pub(crate) async fn remove_workspace(
id: String,
state: State<'_, AppState>,
app: AppHandle,
) -> Result<(), String> {
if remote_backend::is_remote_mode(&*state).await {
remote_backend::call_remote(&*state, app, "remove_workspace", json!({ "id": id })).await?;
return Ok(());
}

let (entry, child_worktrees) = {
let workspaces = state.workspaces.lock().await;
let entry = workspaces
Expand Down Expand Up @@ -880,7 +899,13 @@ pub(crate) async fn remove_workspace(
pub(crate) async fn remove_worktree(
id: String,
state: State<'_, AppState>,
app: AppHandle,
) -> Result<(), String> {
if remote_backend::is_remote_mode(&*state).await {
remote_backend::call_remote(&*state, app, "remove_worktree", json!({ "id": id })).await?;
return Ok(());
}

let (entry, parent) = {
let workspaces = state.workspaces.lock().await;
let entry = workspaces
Expand Down Expand Up @@ -1333,7 +1358,19 @@ pub(crate) async fn update_workspace_settings(
id: String,
settings: WorkspaceSettings,
state: State<'_, AppState>,
app: AppHandle,
) -> Result<WorkspaceInfo, String> {
if remote_backend::is_remote_mode(&*state).await {
let response = remote_backend::call_remote(
&*state,
app,
"update_workspace_settings",
json!({ "id": id, "settings": settings }),
)
.await?;
return serde_json::from_value(response).map_err(|err| err.to_string());
}

let (entry_snapshot, list) = {
let mut workspaces = state.workspaces.lock().await;
let entry_snapshot = apply_workspace_settings_update(&mut workspaces, &id, settings)?;
Expand Down Expand Up @@ -1361,7 +1398,20 @@ pub(crate) async fn update_workspace_codex_bin(
id: String,
codex_bin: Option<String>,
state: State<'_, AppState>,
app: AppHandle,
) -> Result<WorkspaceInfo, String> {
if remote_backend::is_remote_mode(&*state).await {
let codex_bin = codex_bin.map(remote_backend::normalize_path_for_remote);
let response = remote_backend::call_remote(
&*state,
app,
"update_workspace_codex_bin",
json!({ "id": id, "codex_bin": codex_bin }),
)
.await?;
return serde_json::from_value(response).map_err(|err| err.to_string());
}

let (entry_snapshot, list) = {
let mut workspaces = state.workspaces.lock().await;
let entry_snapshot = match workspaces.get_mut(&id) {
Expand Down
Loading