@@ -46280,7 +46280,7 @@ fn doctor_probe_mutation_lock(data_dir: &Path) -> DoctorMutationLockObservation
4628046280 let _ = fs2::FileExt::unlock(&file);
4628146281 DoctorMutationLockObservation::Available { path, metadata }
4628246282 }
46283- Err(err) if err.kind() == std::io::ErrorKind::WouldBlock => {
46283+ Err(err) if doctor_lock_probe_error_is_active(&err) => {
4628446284 DoctorMutationLockObservation::Active { path, metadata }
4628546285 }
4628646286 Err(err) => DoctorMutationLockObservation::Unavailable {
@@ -46290,6 +46290,21 @@ fn doctor_probe_mutation_lock(data_dir: &Path) -> DoctorMutationLockObservation
4629046290 }
4629146291}
4629246292
46293+ fn doctor_lock_probe_error_is_active(err: &std::io::Error) -> bool {
46294+ if err.kind() == std::io::ErrorKind::WouldBlock {
46295+ return true;
46296+ }
46297+
46298+ #[cfg(windows)]
46299+ {
46300+ err.raw_os_error() == Some(33)
46301+ }
46302+ #[cfg(not(windows))]
46303+ {
46304+ false
46305+ }
46306+ }
46307+
4629346308fn doctor_acquire_mutation_lock(
4629446309 data_dir: &Path,
4629546310 db_path: &Path,
@@ -46323,7 +46338,7 @@ fn doctor_acquire_mutation_lock(
4632346338
4632446339 if let Err(err) = fs2::FileExt::try_lock_exclusive(&file) {
4632546340 let metadata = doctor_read_lock_metadata(&file);
46326- if err.kind() == std::io::ErrorKind::WouldBlock {
46341+ if doctor_lock_probe_error_is_active(&err) {
4632746342 return Err(DoctorMutationLockObservation::Active { path, metadata });
4632846343 }
4632946344 return Err(DoctorMutationLockObservation::Unavailable {
@@ -46387,7 +46402,7 @@ fn doctor_acquire_existing_mutation_lock_without_metadata(
4638746402
4638846403 if let Err(err) = fs2::FileExt::try_lock_exclusive(&file) {
4638946404 let metadata = doctor_read_lock_metadata(&file);
46390- if err.kind() == std::io::ErrorKind::WouldBlock {
46405+ if doctor_lock_probe_error_is_active(&err) {
4639146406 return Err(DoctorMutationLockObservation::Active { path, metadata });
4639246407 }
4639346408 return Err(DoctorMutationLockObservation::Unavailable {
@@ -52931,9 +52946,22 @@ fn sync_file(path: &Path, label: &str) -> Result<(), String> {
5293152946 path.display()
5293252947 ));
5293352948 }
52934- std::fs::File::open(path)
52935- .and_then(|file| file.sync_all())
52936- .map_err(|err| format!("failed to sync {label} {}: {err}", path.display()))
52949+
52950+ #[cfg(windows)]
52951+ {
52952+ std::fs::OpenOptions::new()
52953+ .read(true)
52954+ .write(true)
52955+ .open(path)
52956+ .and_then(|file| file.sync_all())
52957+ .map_err(|err| format!("failed to sync {label} {}: {err}", path.display()))
52958+ }
52959+ #[cfg(not(windows))]
52960+ {
52961+ std::fs::File::open(path)
52962+ .and_then(|file| file.sync_all())
52963+ .map_err(|err| format!("failed to sync {label} {}: {err}", path.display()))
52964+ }
5293752965}
5293852966
5293952967fn sync_directory(path: &Path) -> Result<(), String> {
@@ -52943,9 +52971,17 @@ fn sync_directory(path: &Path) -> Result<(), String> {
5294352971 path.display()
5294452972 ));
5294552973 }
52946- std::fs::File::open(path)
52947- .and_then(|file| file.sync_all())
52948- .map_err(|err| format!("failed to sync directory {}: {err}", path.display()))
52974+
52975+ #[cfg(windows)]
52976+ {
52977+ Ok(())
52978+ }
52979+ #[cfg(not(windows))]
52980+ {
52981+ std::fs::File::open(path)
52982+ .and_then(|file| file.sync_all())
52983+ .map_err(|err| format!("failed to sync directory {}: {err}", path.display()))
52984+ }
5294952985}
5295052986
5295152987fn doctor_rename_file(source_path: &Path, target_path: &Path) -> io::Result<()> {
@@ -66972,6 +67008,7 @@ mode=index",
6697267008 fn active_index_run_details_reads_matching_lock_metadata() {
6697367009 let (temp, db_path) = seed_cli_db();
6697467010 let lock_path = temp.path().join("index-run.lock");
67011+ let pid = std::process::id();
6697567012 let mut lock_file = std::fs::OpenOptions::new()
6697667013 .create(true)
6697767014 .truncate(true)
@@ -66983,7 +67020,7 @@ mode=index",
6698367020 writeln!(
6698467021 lock_file,
6698567022 "pid={}\nstarted_at_ms={}\ndb_path={}",
66986- 4242_u32 ,
67023+ pid ,
6698767024 1_733_001_111_000_i64,
6698867025 db_path.display()
6698967026 )
@@ -66992,7 +67029,7 @@ mode=index",
6699267029
6699367030 let details =
6699467031 active_index_run_details(temp.path(), &db_path).expect("matching active index run");
66995- assert_eq!(details.pid, Some(4242 ));
67032+ assert_eq!(details.pid, Some(pid ));
6699667033 assert_eq!(details.started_at_ms, Some(1_733_001_111_000));
6699767034 assert_eq!(details.data_dir, temp.path());
6699867035 assert_eq!(details.db_path, db_path);
@@ -67007,6 +67044,7 @@ mode=index",
6700767044 let (temp, db_path) = seed_cli_db();
6700867045 let other_db_path = temp.path().join("other-agent-search.db");
6700967046 let lock_path = temp.path().join("index-run.lock");
67047+ let pid = std::process::id();
6701067048 let mut lock_file = std::fs::OpenOptions::new()
6701167049 .create(true)
6701267050 .truncate(true)
@@ -67018,7 +67056,7 @@ mode=index",
6701867056 writeln!(
6701967057 lock_file,
6702067058 "pid={}\nstarted_at_ms={}\ndb_path={}",
67021- 31337_u32 ,
67059+ pid ,
6702267060 1_733_001_222_000_i64,
6702367061 other_db_path.display()
6702467062 )
@@ -67027,7 +67065,7 @@ mode=index",
6702767065
6702867066 let details = active_index_run_details(temp.path(), &db_path)
6702967067 .expect("active lock in same data dir should still be reported");
67030- assert_eq!(details.pid, Some(31337 ));
67068+ assert_eq!(details.pid, Some(pid ));
6703167069 assert_eq!(details.db_path, other_db_path);
6703267070 }
6703367071
@@ -67608,6 +67646,8 @@ pub(crate) fn run_doctor_impl(
6760867646 match doctor_acquire_mutation_lock(&data_dir, &db_path) {
6760967647 Ok((guard, observation)) => {
6761067648 _doctor_lock_guard = Some(guard);
67649+ _doctor_db_open_bypass_guard =
67650+ Some(crate::storage::sqlite::enter_doctor_mutation_db_open_bypass());
6761167651 observation
6761267652 }
6761367653 Err(observation) => observation,
@@ -68810,6 +68850,9 @@ pub(crate) fn run_doctor_impl(
6881068850 match doctor_acquire_mutation_lock(&data_dir, &db_path) {
6881168851 Ok((guard, observation)) => {
6881268852 _doctor_lock_guard = Some(guard);
68853+ _doctor_db_open_bypass_guard = Some(
68854+ crate::storage::sqlite::enter_doctor_mutation_db_open_bypass(),
68855+ );
6881368856 operation_state = build_doctor_operation_state_report(
6881468857 &data_dir,
6881568858 &db_path,
@@ -79715,6 +79758,12 @@ pub fn default_data_dir() -> PathBuf {
7971579758 return PathBuf::from(trimmed);
7971679759 }
7971779760 }
79761+ if let Ok(dir) = dotenvy::var("XDG_DATA_HOME") {
79762+ let trimmed = dir.trim();
79763+ if !trimmed.is_empty() {
79764+ return PathBuf::from(trimmed).join("coding-agent-search");
79765+ }
79766+ }
7971879767 directories::ProjectDirs::from("com", "coding-agent-search", "coding-agent-search")
7971979768 .map(|p| p.data_dir().to_path_buf())
7972079769 .or_else(|| dirs::home_dir().map(|h| h.join(".coding-agent-search")))
@@ -81422,6 +81471,7 @@ mod clipboard_helper_tests {
8142281471 /// previous failure mode was a silent success that dropped the
8142381472 /// export on the floor.
8142481473 #[test]
81474+ #[cfg(not(windows))]
8142581475 fn returns_err_when_no_tool_is_available() {
8142681476 // Save and clear PATH so spawn() can't find pbcopy/wl-copy/xclip
8142781477 // /xsel/clip. Restore on exit even if the assertion panics.
0 commit comments