chore: bump version to 11.1.0
This commit is contained in:
Generated
+1
-1
@@ -1989,7 +1989,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pi-natives"
|
||||
version = "11.0.3"
|
||||
version = "11.1.0"
|
||||
dependencies = [
|
||||
"arboard",
|
||||
"brush-builtins",
|
||||
|
||||
+1
-1
@@ -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"]
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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<Result<ExecutionResult, error::Error>>;
|
||||
pub(crate) type JobResult = (Job, Result<ExecutionResult, error::Error>);
|
||||
|
||||
@@ -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<OwnedHandle> {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<dyn futures::Future<Output = Result<std::process::Output, std::io::Error>> + Send + Sync>,
|
||||
>;
|
||||
|
||||
/// Tracks a child process being awaited.
|
||||
pub struct ChildProcess {
|
||||
/// If available, the process ID of the child.
|
||||
pid: Option<sys::process::ProcessId>,
|
||||
/// 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<OwnedHandle>,
|
||||
/// 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<sys::process::ProcessId>, 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<OwnedHandle> {
|
||||
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<Result<std::process::Output, error::Error>> {
|
||||
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<OwnedHandle> {
|
||||
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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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::<traps::TrapSignal>() 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::<traps::TrapSignal>() else {
|
||||
return;
|
||||
};
|
||||
for pid in pids {
|
||||
let _ = sys::signal::kill_process(pid, signal);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user