Skip to content
Open
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: 5 additions & 1 deletion src-tauri/src/shared/settings_core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use tokio::sync::Mutex;
use crate::codex::config as codex_config;
use crate::storage::write_settings;
use crate::types::AppSettings;
use crate::utils::normalize_windows_namespace_path;

fn normalize_personality(value: &str) -> Option<&'static str> {
match value.trim() {
Expand Down Expand Up @@ -40,10 +41,13 @@ pub(crate) async fn get_app_settings_core(app_settings: &Mutex<AppSettings>) ->
}

pub(crate) async fn update_app_settings_core(
settings: AppSettings,
mut settings: AppSettings,
app_settings: &Mutex<AppSettings>,
settings_path: &PathBuf,
) -> Result<AppSettings, String> {
settings.global_worktrees_folder = settings
.global_worktrees_folder
.map(|path| normalize_windows_namespace_path(&path));
let _ = codex_config::write_collaboration_modes_enabled(settings.collaboration_modes_enabled);
let _ = codex_config::write_steer_enabled(settings.steer_enabled);
let _ = codex_config::write_unified_exec_enabled(settings.unified_exec_enabled);
Expand Down
16 changes: 12 additions & 4 deletions src-tauri/src/shared/workspaces_core/crud_persistence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,12 @@ use crate::shared::process_core::kill_child_process_tree;
use crate::shared::{git_core, worktree_core};
use crate::storage::write_workspaces;
use crate::types::{AppSettings, WorkspaceEntry, WorkspaceInfo, WorkspaceKind, WorkspaceSettings};
use crate::utils::normalize_windows_namespace_path;

use super::connect::{kill_session_by_id, take_live_shared_session, workspace_session_spawn_lock};
use super::helpers::{normalize_setup_script, normalize_workspace_path_input};
use super::helpers::{
normalize_setup_script, normalize_workspace_path_input, workspace_path_to_string,
};

pub(crate) async fn add_workspace_core<F, Fut>(
path: String,
Expand All @@ -33,7 +36,7 @@ where
if !normalized_path.is_dir() {
return Err("Workspace path must be a folder.".to_string());
}
let path = normalized_path.to_string_lossy().to_string();
let path = workspace_path_to_string(&normalized_path);

let name = PathBuf::from(&path)
.file_name()
Expand Down Expand Up @@ -154,6 +157,7 @@ where
let destination_path =
worktree_core::build_clone_destination_path(&copies_folder_path, &copy_name);
let destination_path_string = destination_path.to_string_lossy().to_string();
let stored_destination_path = workspace_path_to_string(&destination_path);

if let Err(error) = git_core::run_git_command(
&copies_folder_path,
Expand Down Expand Up @@ -189,7 +193,7 @@ where
let entry = WorkspaceEntry {
id: Uuid::new_v4().to_string(),
name: copy_name,
path: destination_path_string,
path: stored_destination_path,
kind: WorkspaceKind::Main,
parent_id: None,
worktree: None,
Expand Down Expand Up @@ -342,6 +346,7 @@ where
}

let clone_path_string = clone_path.to_string_lossy().to_string();
let stored_clone_path = workspace_path_to_string(&clone_path);
if let Err(error) =
git_core::run_git_command(&destination_parent, &["clone", &url, &clone_path_string]).await
{
Expand All @@ -357,7 +362,7 @@ where
let entry = WorkspaceEntry {
id: Uuid::new_v4().to_string(),
name: workspace_name,
path: clone_path_string,
path: stored_clone_path,
kind: WorkspaceKind::Main,
parent_id: None,
worktree: None,
Expand Down Expand Up @@ -553,6 +558,9 @@ where
FutSpawn: Future<Output = Result<Arc<WorkspaceSession>, String>>,
{
settings.worktree_setup_script = normalize_setup_script(settings.worktree_setup_script);
settings.worktrees_folder = settings
.worktrees_folder
.map(|path| normalize_windows_namespace_path(&path));

let (entry_snapshot, previous_worktree_setup_script, child_entries) = {
let mut workspaces = workspaces.lock().await;
Expand Down
16 changes: 15 additions & 1 deletion src-tauri/src/shared/workspaces_core/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use tokio::sync::Mutex;

use crate::backend::app_server::WorkspaceSession;
use crate::types::{WorkspaceEntry, WorkspaceInfo};
use crate::utils::normalize_windows_namespace_path;

pub(crate) const WORKTREE_SETUP_MARKERS_DIR: &str = "worktree-setup";
pub(crate) const WORKTREE_SETUP_MARKER_EXT: &str = "ran";
Expand Down Expand Up @@ -81,6 +82,10 @@ pub(crate) fn normalize_workspace_path_input(path: &str) -> PathBuf {
PathBuf::from(trimmed)
}

pub(crate) fn workspace_path_to_string(path: &PathBuf) -> String {
normalize_windows_namespace_path(&path.to_string_lossy())
}

pub(crate) async fn list_workspaces_core(
workspaces: &Mutex<HashMap<String, WorkspaceEntry>>,
sessions: &Mutex<HashMap<String, Arc<WorkspaceSession>>>,
Expand Down Expand Up @@ -147,7 +152,8 @@ pub(super) fn sort_workspaces(workspaces: &mut [WorkspaceInfo]) {
#[cfg(test)]
mod tests {
use super::{
copy_agents_md_from_parent_to_worktree, normalize_workspace_path_input, AGENTS_MD_FILE_NAME,
copy_agents_md_from_parent_to_worktree, normalize_workspace_path_input,
workspace_path_to_string, AGENTS_MD_FILE_NAME,
};
use std::path::PathBuf;
use std::sync::Mutex;
Expand Down Expand Up @@ -217,4 +223,12 @@ mod tests {
None => std::env::remove_var("HOME"),
}
}

#[test]
fn workspace_path_to_string_strips_windows_namespace_prefixes() {
assert_eq!(
workspace_path_to_string(&PathBuf::from(r"\\?\I:\gpt-projects\CodexMonitor")),
r"I:\gpt-projects\CodexMonitor"
);
}
}
21 changes: 12 additions & 9 deletions src-tauri/src/shared/workspaces_core/worktree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ use crate::types::{

use super::connect::{kill_session_by_id, take_live_shared_session, workspace_session_spawn_lock};
use super::helpers::{
copy_agents_md_from_parent_to_worktree, normalize_setup_script, worktree_setup_marker_path,
AGENTS_MD_FILE_NAME,
copy_agents_md_from_parent_to_worktree, normalize_setup_script, workspace_path_to_string,
worktree_setup_marker_path, AGENTS_MD_FILE_NAME,
};

pub(crate) async fn worktree_setup_status_core(
Expand Down Expand Up @@ -136,14 +136,15 @@ where

// Determine worktree root: per-workspace setting > global setting > default
let worktree_root = if let Some(custom_folder) = &parent_entry.settings.worktrees_folder {
PathBuf::from(custom_folder)
PathBuf::from(workspace_path_to_string(&PathBuf::from(custom_folder)))
} else {
let global_folder = {
let settings = app_settings.lock().await;
settings.global_worktrees_folder.clone()
};
if let Some(global_folder) = global_folder {
PathBuf::from(global_folder).join(&parent_entry.id)
PathBuf::from(workspace_path_to_string(&PathBuf::from(global_folder)))
.join(&parent_entry.id)
} else {
data_dir.join("worktrees").join(&parent_entry.id)
}
Expand All @@ -154,6 +155,7 @@ where
let safe_name = sanitize_worktree_name(&branch);
let worktree_path = unique_worktree_path(&worktree_root, &safe_name)?;
let worktree_path_string = worktree_path.to_string_lossy().to_string();
let stored_worktree_path = workspace_path_to_string(&worktree_path);

let repo_path = PathBuf::from(&parent_entry.path);
let branch_exists = git_branch_exists(&repo_path, &branch).await?;
Expand Down Expand Up @@ -206,7 +208,7 @@ where
let entry = WorkspaceEntry {
id: Uuid::new_v4().to_string(),
name: name.clone().unwrap_or_else(|| branch.clone()),
path: worktree_path_string,
path: stored_worktree_path,
kind: WorkspaceKind::Worktree,
parent_id: Some(parent_entry.id.clone()),
worktree: Some(WorktreeInfo { branch }),
Expand Down Expand Up @@ -409,14 +411,14 @@ where
// Use the same priority logic as add_worktree_core:
// per-workspace setting > global setting > default
let worktree_root = if let Some(custom_folder) = &parent.settings.worktrees_folder {
PathBuf::from(custom_folder)
PathBuf::from(workspace_path_to_string(&PathBuf::from(custom_folder)))
} else {
let global_folder = {
let settings = app_settings.lock().await;
settings.global_worktrees_folder.clone()
};
if let Some(global_folder) = global_folder {
PathBuf::from(global_folder).join(&parent.id)
PathBuf::from(workspace_path_to_string(&PathBuf::from(global_folder))).join(&parent.id)
} else {
data_dir.join("worktrees").join(&parent.id)
}
Expand All @@ -428,12 +430,13 @@ where
let current_path = PathBuf::from(&entry.path);
let next_path = unique_worktree_path_for_rename(&worktree_root, &safe_name, &current_path)?;
let next_path_string = next_path.to_string_lossy().to_string();
let stored_next_path = workspace_path_to_string(&next_path);
let old_path_string = entry.path.clone();

run_git_command(&parent_root, &["branch", "-m", &old_branch, &final_branch]).await?;

let mut moved_worktree = false;
if next_path_string != old_path_string {
if stored_next_path != old_path_string {
if let Err(error) = run_git_command(
&parent_root,
&["worktree", "move", &old_path_string, &next_path_string],
Expand All @@ -454,7 +457,7 @@ where
if entry.name.trim() == old_branch {
entry.name = final_branch.clone();
}
entry.path = next_path_string.clone();
entry.path = stored_next_path.clone();
match entry.worktree.as_mut() {
Some(worktree) => {
worktree.branch = final_branch.clone();
Expand Down
Loading
Loading