diff --git a/apps/purepoint-macos/purepoint-macos/Services/ManifestWatcher.swift b/apps/purepoint-macos/purepoint-macos/Services/ManifestWatcher.swift index 94727b6..0a118a6 100644 --- a/apps/purepoint-macos/purepoint-macos/Services/ManifestWatcher.swift +++ b/apps/purepoint-macos/purepoint-macos/Services/ManifestWatcher.swift @@ -104,8 +104,10 @@ final class ManifestWatcher: @unchecked Sendable { deinit { debounceWork?.cancel() - source?.cancel() - if fileDescriptor >= 0 { + if source != nil { + // Cancel handler will close the fd — do not also close it here. + source?.cancel() + } else if fileDescriptor >= 0 { close(fileDescriptor) } } diff --git a/crates/pu-engine/src/pty_manager.rs b/crates/pu-engine/src/pty_manager.rs index 43ea26f..9830ae0 100644 --- a/crates/pu-engine/src/pty_manager.rs +++ b/crates/pu-engine/src/pty_manager.rs @@ -185,8 +185,14 @@ impl NativePtyHost { unsafe { libc::read(read_fd, tmp.as_mut_ptr() as *mut _, tmp.len()) }; if n > 0 { read_buf.write(&tmp[..n as usize]); + } else if n == 0 { + break; // EOF } else { - break; // EOF or error + let err = std::io::Error::last_os_error(); + if err.kind() == std::io::ErrorKind::Interrupted { + continue; // EINTR — retry + } + break; // Real error } } }); @@ -283,7 +289,11 @@ impl NativePtyHost { libc::write(fd, data[offset..].as_ptr() as *const _, data.len() - offset) }; if n < 0 { - return Err(std::io::Error::last_os_error()); + let err = std::io::Error::last_os_error(); + if err.kind() == std::io::ErrorKind::Interrupted { + continue; // EINTR — retry + } + return Err(err); } offset += n as usize; }