From d1ccb24e7e025dd037148df229ef608e73e09657 Mon Sep 17 00:00:00 2001 From: can1357 Date: Thu, 5 Feb 2026 08:11:32 +0100 Subject: [PATCH] chore: bump version to 11.1.0 --- Cargo.lock | 2 +- Cargo.toml | 2 +- bun.lock | 14 +- crates/brush-core-vendored/src/jobs.rs | 16 -- crates/brush-core-vendored/src/processes.rs | 143 +++++------------- .../src/sys/stubs/signal.rs | 6 +- crates/brush-core-vendored/src/sys/windows.rs | 2 +- crates/pi-natives/src/shell.rs | 28 ++-- packages/agent/package.json | 2 +- packages/ai/package.json | 2 +- packages/coding-agent/CHANGELOG.md | 2 + packages/coding-agent/package.json | 2 +- packages/natives/package.json | 2 +- packages/stats/package.json | 2 +- packages/tui/package.json | 2 +- packages/utils/package.json | 2 +- 16 files changed, 80 insertions(+), 149 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 27610a6ce..78263d2fb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1989,7 +1989,7 @@ dependencies = [ [[package]] name = "pi-natives" -version = "11.0.3" +version = "11.1.0" dependencies = [ "arboard", "brush-builtins", diff --git a/Cargo.toml b/Cargo.toml index 53a76e24a..28a632e98 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ exclude = ["crates/brush-core-vendored", "crates/brush-builtins-vendored"] resolver = "3" [workspace.package] -version = "11.0.3" +version = "11.1.0" edition = "2024" license = "MIT" authors = ["Can Boluk"] diff --git a/bun.lock b/bun.lock index cda67a0db..c49760e29 100644 --- a/bun.lock +++ b/bun.lock @@ -22,7 +22,7 @@ }, "packages/agent": { "name": "@oh-my-pi/pi-agent-core", - "version": "11.0.3", + "version": "11.1.0", "dependencies": { "@oh-my-pi/pi-ai": "workspace:*", "@oh-my-pi/pi-tui": "workspace:*", @@ -35,7 +35,7 @@ }, "packages/ai": { "name": "@oh-my-pi/pi-ai", - "version": "11.0.3", + "version": "11.1.0", "bin": { "pi-ai": "./src/cli.ts", }, @@ -63,7 +63,7 @@ }, "packages/coding-agent": { "name": "@oh-my-pi/pi-coding-agent", - "version": "11.0.3", + "version": "11.1.0", "bin": { "omp": "src/cli.ts", }, @@ -102,7 +102,7 @@ }, "packages/natives": { "name": "@oh-my-pi/pi-natives", - "version": "11.0.3", + "version": "11.1.0", "dependencies": { "@oh-my-pi/pi-utils": "workspace:*", }, @@ -130,7 +130,7 @@ }, "packages/stats": { "name": "@oh-my-pi/omp-stats", - "version": "11.0.3", + "version": "11.1.0", "bin": { "omp-stats": "./src/index.ts", }, @@ -150,7 +150,7 @@ }, "packages/tui": { "name": "@oh-my-pi/pi-tui", - "version": "11.0.3", + "version": "11.1.0", "dependencies": { "@oh-my-pi/pi-natives": "workspace:*", "@oh-my-pi/pi-utils": "workspace:*", @@ -166,7 +166,7 @@ }, "packages/utils": { "name": "@oh-my-pi/pi-utils", - "version": "11.0.3", + "version": "11.1.0", "dependencies": { "winston": "^3.19.0", "winston-daily-rotate-file": "^5.0.0", diff --git a/crates/brush-core-vendored/src/jobs.rs b/crates/brush-core-vendored/src/jobs.rs index 066b8e199..7a6b8ed69 100644 --- a/crates/brush-core-vendored/src/jobs.rs +++ b/crates/brush-core-vendored/src/jobs.rs @@ -12,9 +12,6 @@ use crate::sys; use crate::trace_categories; use crate::traps; -#[cfg(windows)] -use std::os::windows::io::OwnedHandle; - pub(crate) type JobJoinHandle = tokio::task::JoinHandle>; pub(crate) type JobResult = (Job, Result); @@ -450,17 +447,4 @@ impl Job { self.pgid.or_else(|| self.representative_pid()) } - /// Duplicates process handles for termination on Windows. - #[cfg(windows)] - pub fn duplicate_kill_handles(&self) -> Vec { - let mut handles = Vec::new(); - for task in &self.tasks { - if let JobTask::External(process) = task { - if let Some(handle) = process.duplicate_kill_handle() { - handles.push(handle); - } - } - } - handles - } } diff --git a/crates/brush-core-vendored/src/processes.rs b/crates/brush-core-vendored/src/processes.rs index cd3e6fa27..f395d972f 100644 --- a/crates/brush-core-vendored/src/processes.rs +++ b/crates/brush-core-vendored/src/processes.rs @@ -1,41 +1,21 @@ //! Process management -use futures::FutureExt; use tokio_util::sync::CancellationToken; -#[cfg(windows)] -use std::os::windows::io::{AsRawHandle, OwnedHandle, RawHandle}; - use crate::{error, sys}; -/// A waitable future that will yield the results of a child process's execution. -pub(crate) type WaitableChildProcess = std::pin::Pin< - Box> + Send + Sync>, ->; - /// Tracks a child process being awaited. pub struct ChildProcess { /// If available, the process ID of the child. pid: Option, - /// A waitable future that will yield the results of a child process's execution. - exec_future: WaitableChildProcess, - #[cfg(windows)] - /// Windows handle duplicated from the child process for safe termination. - kill_handle: Option, + /// Child process handle kept alive for cancellation/termination. + child: sys::process::Child, } impl ChildProcess { /// Wraps a child process and its future. pub fn new(pid: Option, child: sys::process::Child) -> Self { - #[cfg(windows)] - let kill_handle = duplicate_handle(child.as_raw_handle()); - - Self { - pid, - exec_future: Box::pin(child.wait_with_output()), - #[cfg(windows)] - kill_handle, - } + Self { pid, child } } /// Returns the process's ID. @@ -43,13 +23,6 @@ impl ChildProcess { self.pid } - /// Duplicates the process handle for termination use on Windows. - #[cfg(windows)] - pub fn duplicate_kill_handle(&self) -> Option { - let handle = self.kill_handle.as_ref()?; - duplicate_handle(handle.as_raw_handle()) - } - /// Waits for the process to exit. /// /// If a cancellation token is provided and triggered, the process will be killed. @@ -72,90 +45,54 @@ impl ChildProcess { #[allow(clippy::ignored_unit_patterns)] loop { - tokio::select! { - output = &mut self.exec_future => { - break Ok(ProcessWaitResult::Completed(output?)) - }, - _ = &mut cancelled => { + let status = { + let wait_future = self.child.wait(); + tokio::pin!(wait_future); + tokio::select! { + status = &mut wait_future => Some(status), + _ = &mut cancelled => None, + _ = sigtstp.recv() => return Ok(ProcessWaitResult::Stopped), + _ = sigchld.recv() => { + if sys::signal::poll_for_stopped_children()? { + return Ok(ProcessWaitResult::Stopped); + } + continue; + }, + _ = sys::signal::await_ctrl_c() => { + // SIGINT got thrown. Handle it and continue looping. The child should + // have received it as well, and either handled it or ended up getting + // terminated (in which case we'll see the child exit). + continue; + }, + } + }; + + return match status { + Some(status) => Ok(ProcessWaitResult::Completed(output_from_status(status?))), + None => { self.kill(); - break Ok(ProcessWaitResult::Cancelled) - }, - _ = sigtstp.recv() => { - break Ok(ProcessWaitResult::Stopped) - }, - _ = sigchld.recv() => { - if sys::signal::poll_for_stopped_children()? { - break Ok(ProcessWaitResult::Stopped); - } - }, - _ = sys::signal::await_ctrl_c() => { - // SIGINT got thrown. Handle it and continue looping. The child should - // have received it as well, and either handled it or ended up getting - // terminated (in which case we'll see the child exit). - }, - } + Ok(ProcessWaitResult::Cancelled) + } + }; } } /// Terminates the process if we have a PID. - fn kill(&self) { - let Some(pid) = self.pid else { return }; - - #[cfg(unix)] - { - let _ = nix::sys::signal::kill(nix::unistd::Pid::from_raw(pid), nix::sys::signal::Signal::SIGKILL); - } - - #[cfg(windows)] - { - use windows_sys::Win32::Foundation::CloseHandle; - use windows_sys::Win32::System::Threading::{OpenProcess, TerminateProcess, PROCESS_TERMINATE}; - - // SAFETY: Windows API calls with proper handle management - unsafe { - #[expect(clippy::cast_sign_loss)] - let handle = OpenProcess(PROCESS_TERMINATE, 0, pid as u32); - if !handle.is_null() { - let _ = TerminateProcess(handle, 1); - CloseHandle(handle); - } - } - } + fn kill(&mut self) { + let _ = self.child.start_kill(); } pub(crate) fn poll(&mut self) -> Option> { - let checkable_future = &mut self.exec_future; - checkable_future - .now_or_never() - .map(|result| result.map_err(Into::into)) + match self.child.try_wait() { + Ok(Some(status)) => Some(Ok(output_from_status(status))), + Ok(None) => None, + Err(err) => Some(Err(err.into())), + } } } -#[cfg(windows)] -fn duplicate_handle(handle: RawHandle) -> Option { - use std::os::windows::io::FromRawHandle; - use windows_sys::Win32::System::Threading::{ - DuplicateHandle, GetCurrentProcess, DUPLICATE_SAME_ACCESS, - }; - - let current = unsafe { GetCurrentProcess() }; - let mut out_handle = std::ptr::null_mut(); - let ok = unsafe { - DuplicateHandle( - current, - handle as _, - current, - &mut out_handle, - 0, - 0, - DUPLICATE_SAME_ACCESS, - ) - }; - if ok == 0 || out_handle.is_null() { - return None; - } - - Some(unsafe { OwnedHandle::from_raw_handle(out_handle) }) +fn output_from_status(status: std::process::ExitStatus) -> std::process::Output { + std::process::Output { status, stdout: Vec::new(), stderr: Vec::new() } } /// Represents the result of waiting for an executing process. diff --git a/crates/brush-core-vendored/src/sys/stubs/signal.rs b/crates/brush-core-vendored/src/sys/stubs/signal.rs index 4dff385c4..e64f3ad45 100644 --- a/crates/brush-core-vendored/src/sys/stubs/signal.rs +++ b/crates/brush-core-vendored/src/sys/stubs/signal.rs @@ -10,10 +10,14 @@ pub enum Signal {} /// Minimal signal representation for Windows. #[cfg(windows)] +#[allow(unnameable_types)] #[derive(Clone, Copy, Eq, Hash, PartialEq)] pub enum Signal { + /// Terminate signal. Terminate, + /// Kill signal. Kill, + /// Interrupt signal. Interrupt, } @@ -83,7 +87,7 @@ pub fn kill_process( let pid = _pid as u32; unsafe { let handle = OpenProcess(PROCESS_TERMINATE, 0, pid); - if handle == 0 { + if handle.is_null() { return Err(error::ErrorKind::FailedToSendSignal.into()); } let ok = TerminateProcess(handle, 1); diff --git a/crates/brush-core-vendored/src/sys/windows.rs b/crates/brush-core-vendored/src/sys/windows.rs index 7256c69b4..9e9300927 100644 --- a/crates/brush-core-vendored/src/sys/windows.rs +++ b/crates/brush-core-vendored/src/sys/windows.rs @@ -7,7 +7,7 @@ pub use crate::sys::stubs::resource; /// Signal processing utilities pub mod signal { - pub(crate) use crate::sys::stubs::signal::*; + pub use crate::sys::stubs::signal::*; pub(crate) use tokio::signal::ctrl_c as await_ctrl_c; } diff --git a/crates/pi-natives/src/shell.rs b/crates/pi-natives/src/shell.rs index a1d0f77d3..85bdf5e0e 100644 --- a/crates/pi-natives/src/shell.rs +++ b/crates/pi-natives/src/shell.rs @@ -12,6 +12,8 @@ //! }); //! ``` +#[cfg(windows)] +use std::collections::HashSet; use std::{ collections::HashMap, fs, @@ -20,8 +22,6 @@ use std::{ sync::Arc, time::Duration, }; -#[cfg(windows)] -use std::{collections::HashSet, os::windows::io::AsRawHandle}; #[cfg(windows)] mod windows; @@ -45,8 +45,6 @@ use tokio::io::AsyncReadExt as _; use tokio_util::sync::CancellationToken; #[cfg(windows)] use windows::configure_windows_path; -#[cfg(windows)] -use windows_sys::Win32::System::Threading::TerminateProcess; use crate::task; @@ -614,20 +612,26 @@ fn terminate_background_jobs(shell: &BrushShell) { if shell.jobs.jobs.is_empty() { return; } - let mut handles = Vec::new(); + let Ok(signal) = "TERM".parse::() else { + return; + }; + let mut pids = Vec::new(); for job in &shell.jobs.jobs { - handles.extend(job.duplicate_kill_handles()); + if let Some(pid) = job.process_group_id().or_else(|| job.representative_pid()) { + let _ = sys::signal::kill_process(pid, signal); + pids.push(pid); + } } - if handles.is_empty() { + if pids.is_empty() { return; } tokio::spawn(async move { time::sleep(Duration::from_millis(500)).await; - for handle in handles { - // SAFETY: OwnedHandle keeps the duplicated handle alive for the duration. - unsafe { - let _ = TerminateProcess(handle.as_raw_handle() as _, 1); - } + let Ok(signal) = "KILL".parse::() else { + return; + }; + for pid in pids { + let _ = sys::signal::kill_process(pid, signal); } }); } diff --git a/packages/agent/package.json b/packages/agent/package.json index e9c332c79..b4a37274c 100644 --- a/packages/agent/package.json +++ b/packages/agent/package.json @@ -1,6 +1,6 @@ { "name": "@oh-my-pi/pi-agent-core", - "version": "11.0.3", + "version": "11.1.0", "description": "General-purpose agent with transport abstraction, state management, and attachment support", "type": "module", "main": "./src/index.ts", diff --git a/packages/ai/package.json b/packages/ai/package.json index 65a594f35..05fa298bd 100644 --- a/packages/ai/package.json +++ b/packages/ai/package.json @@ -1,6 +1,6 @@ { "name": "@oh-my-pi/pi-ai", - "version": "11.0.3", + "version": "11.1.0", "description": "Unified LLM API with automatic model discovery and provider configuration", "type": "module", "main": "./src/index.ts", diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index 6b6f4d0a7..4624ed3f4 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -2,6 +2,8 @@ ## [Unreleased] +## [11.1.0] - 2026-02-05 + ### Added - Added `sortDiagnostics()` utility function to sort diagnostics by severity, location, and message for consistent output ordering diff --git a/packages/coding-agent/package.json b/packages/coding-agent/package.json index 4af1b542b..2f369079d 100644 --- a/packages/coding-agent/package.json +++ b/packages/coding-agent/package.json @@ -1,6 +1,6 @@ { "name": "@oh-my-pi/pi-coding-agent", - "version": "11.0.3", + "version": "11.1.0", "description": "Coding agent CLI with read, bash, edit, write tools and session management", "type": "module", "ompConfig": { diff --git a/packages/natives/package.json b/packages/natives/package.json index abebf48bd..9776bc367 100644 --- a/packages/natives/package.json +++ b/packages/natives/package.json @@ -1,6 +1,6 @@ { "name": "@oh-my-pi/pi-natives", - "version": "11.0.3", + "version": "11.1.0", "description": "Native Rust functionality via N-API", "type": "module", "main": "./src/index.ts", diff --git a/packages/stats/package.json b/packages/stats/package.json index abd04ea2b..41a9a3598 100644 --- a/packages/stats/package.json +++ b/packages/stats/package.json @@ -1,6 +1,6 @@ { "name": "@oh-my-pi/omp-stats", - "version": "11.0.3", + "version": "11.1.0", "description": "Local observability dashboard for pi AI usage statistics", "type": "module", "main": "./src/index.ts", diff --git a/packages/tui/package.json b/packages/tui/package.json index a67e0b35d..e4cdef202 100644 --- a/packages/tui/package.json +++ b/packages/tui/package.json @@ -1,6 +1,6 @@ { "name": "@oh-my-pi/pi-tui", - "version": "11.0.3", + "version": "11.1.0", "description": "Terminal User Interface library with differential rendering for efficient text-based applications", "type": "module", "main": "./src/index.ts", diff --git a/packages/utils/package.json b/packages/utils/package.json index a99fdd810..86dbe7817 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@oh-my-pi/pi-utils", - "version": "11.0.3", + "version": "11.1.0", "description": "Shared utilities for pi packages", "type": "module", "main": "./src/index.ts",