chore: bump version to 9.6.3

This commit is contained in:
can1357
2026-02-01 10:28:33 +01:00
parent c52968a2f3
commit b10adb92cb
13 changed files with 69 additions and 69 deletions
Generated
+1 -1
View File
@@ -790,7 +790,7 @@ dependencies = [
[[package]]
name = "pi-natives"
version = "9.6.2"
version = "9.6.3"
dependencies = [
"bstr",
"globset",
+1 -1
View File
@@ -3,7 +3,7 @@ members = ["crates/*"]
resolver = "3"
[workspace.package]
version = "9.6.2"
version = "9.6.3"
edition = "2024"
license = "MIT"
authors = ["Can Boluk"]
+7 -7
View File
@@ -22,7 +22,7 @@
},
"packages/agent": {
"name": "@oh-my-pi/pi-agent-core",
"version": "9.6.2",
"version": "9.6.3",
"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": "9.6.2",
"version": "9.6.3",
"bin": {
"pi-ai": "./src/cli.ts",
},
@@ -65,7 +65,7 @@
},
"packages/coding-agent": {
"name": "@oh-my-pi/pi-coding-agent",
"version": "9.6.2",
"version": "9.6.3",
"bin": {
"omp": "src/cli.ts",
},
@@ -100,7 +100,7 @@
},
"packages/natives": {
"name": "@oh-my-pi/pi-natives",
"version": "9.6.2",
"version": "9.6.3",
"dependencies": {
"@oh-my-pi/pi-utils": "workspace:*",
},
@@ -128,7 +128,7 @@
},
"packages/stats": {
"name": "@oh-my-pi/omp-stats",
"version": "9.6.2",
"version": "9.6.3",
"bin": {
"omp-stats": "./src/index.ts",
},
@@ -148,7 +148,7 @@
},
"packages/tui": {
"name": "@oh-my-pi/pi-tui",
"version": "9.6.2",
"version": "9.6.3",
"dependencies": {
"@oh-my-pi/pi-natives": "workspace:*",
"@types/mime-types": "^3.0.1",
@@ -163,7 +163,7 @@
},
"packages/utils": {
"name": "@oh-my-pi/pi-utils",
"version": "9.6.2",
"version": "9.6.3",
"dependencies": {
"winston": "^3.19.0",
"winston-daily-rotate-file": "^5.0.0",
+46 -47
View File
@@ -8,6 +8,8 @@
//! - Ellipsis decoded lazily
//! - truncateToWidth returns the original `JsString` when possible
use std::cell::RefCell;
use napi::{JsString, bindgen_prelude::*};
use napi_derive::napi;
use unicode_segmentation::UnicodeSegmentation;
@@ -293,7 +295,7 @@ fn ansi_seq_len_u16(data: &[u16], pos: usize) -> Option<usize> {
// '[' CSI
for (i, b) in data[pos + 2..].iter().enumerate() {
if (0x40..=0x7e).contains(b) {
return Some(i + 1 - pos);
return Some(i + 3);
}
}
None
@@ -302,10 +304,10 @@ fn ansi_seq_len_u16(data: &[u16], pos: usize) -> Option<usize> {
// ']' OSC
for (i, &b) in data[pos + 2..].iter().enumerate() {
if b == 0x07 {
return Some(i + 1 - pos);
return Some(i + 3);
}
if b == ESC && data.get(i + 1) == Some(&0x5c) {
return Some(i + 2 - pos);
if b == ESC && data.get(pos + 2 + i + 1) == Some(&0x5c) {
return Some(i + 4);
}
}
None
@@ -353,13 +355,17 @@ fn grapheme_width_str(g: &str) -> usize {
UnicodeWidthStr::width(g)
}
thread_local! {
static SCRATCH: RefCell<String> = const { RefCell::new(String::new()) };
}
/// Iterate graphemes in a UTF-16 segment with:
/// - ASCII fast path (no UTF-8 conversion)
/// - non-ASCII slow path using a reused scratch String
///
/// Callback returns `true` to continue, `false` to stop early.
#[inline]
fn for_each_grapheme_u16<F>(segment: &[u16], scratch: &mut String, mut f: F) -> bool
fn for_each_grapheme_u16<F>(segment: &[u16], mut f: F) -> bool
where
F: FnMut(&[u16], usize) -> bool,
{
@@ -378,31 +384,33 @@ where
}
// Slow path: decode into scratch once, reuse allocation
scratch.clear();
scratch.reserve(segment.len());
SCRATCH.with_borrow_mut(|scratch| {
scratch.clear();
scratch.reserve(segment.len());
for r in std::char::decode_utf16(segment.iter().copied()) {
scratch.push(r.unwrap_or('\u{FFFD}'));
}
let mut utf16_pos = 0usize;
for g in scratch.graphemes(true) {
let w = grapheme_width_str(g);
let g_u16_len: usize = g.chars().map(|c| c.len_utf16()).sum();
let u16_slice = &segment[utf16_pos..utf16_pos + g_u16_len];
utf16_pos += g_u16_len;
if !f(u16_slice, w) {
return false;
for r in std::char::decode_utf16(segment.iter().copied()) {
scratch.push(r.unwrap_or('\u{FFFD}'));
}
}
true
let mut utf16_pos = 0usize;
for g in scratch.graphemes(true) {
let w = grapheme_width_str(g);
let g_u16_len: usize = g.chars().map(|c| c.len_utf16()).sum();
let u16_slice = &segment[utf16_pos..utf16_pos + g_u16_len];
utf16_pos += g_u16_len;
if !f(u16_slice, w) {
return false;
}
}
true
})
}
/// Visible width, with early-exit if width exceeds `limit`.
fn visible_width_u16_up_to(data: &[u16], limit: usize, scratch: &mut String) -> (usize, bool) {
fn visible_width_u16_up_to(data: &[u16], limit: usize) -> (usize, bool) {
let mut width = 0usize;
let mut i = 0usize;
@@ -424,7 +432,7 @@ fn visible_width_u16_up_to(data: &[u16], limit: usize, scratch: &mut String) ->
}
let seg = &data[start..i];
let ok = for_each_grapheme_u16(seg, scratch, |_, w| {
let ok = for_each_grapheme_u16(seg, |_, w| {
width += w;
width <= limit
});
@@ -436,8 +444,8 @@ fn visible_width_u16_up_to(data: &[u16], limit: usize, scratch: &mut String) ->
(width, width > limit)
}
fn visible_width_u16(data: &[u16], scratch: &mut String) -> usize {
visible_width_u16_up_to(data, usize::MAX, scratch).0
fn visible_width_u16(data: &[u16]) -> usize {
visible_width_u16_up_to(data, usize::MAX).0
}
// ============================================================================
@@ -462,10 +470,8 @@ pub fn truncate_to_width(
let text_u16 = text.into_utf16()?;
let text = text_u16.as_slice();
let mut scratch = String::new();
// Fast path: early-exit width check
let (text_w, exceeded) = visible_width_u16_up_to(text, max_width, &mut scratch);
let (text_w, exceeded) = visible_width_u16_up_to(text, max_width);
if !exceeded {
if !pad {
// Return original JsString handle: zero output allocation.
@@ -501,7 +507,7 @@ pub fn truncate_to_width(
if target_w == 0 {
let mut out = Vec::with_capacity(ellipsis.len().min(max_width * 2));
let mut w = 0usize;
let _ = for_each_grapheme_u16(ellipsis, &mut scratch, |gu16, gw| {
let _ = for_each_grapheme_u16(ellipsis, |gu16, gw| {
if w + gw > max_width {
return false;
}
@@ -543,7 +549,7 @@ pub fn truncate_to_width(
}
let seg = &text[start..i];
let keep_going = for_each_grapheme_u16(seg, &mut scratch, |gu16, gw| {
let keep_going = for_each_grapheme_u16(seg, |gu16, gw| {
if w + gw > target_w {
return false;
}
@@ -594,8 +600,6 @@ fn slice_with_width_impl(
// store pending ANSI ranges (pos,len) to avoid copying until needed
let mut pending_ansi: Vec<(usize, usize)> = Vec::new();
let mut scratch = String::new();
while i < line.len() && current_col < end_col {
if line[i] == ESC {
if let Some(len) = ansi_seq_len_u16(line, i) {
@@ -621,7 +625,7 @@ fn slice_with_width_impl(
}
let seg = &line[start..i];
let _ = for_each_grapheme_u16(seg, &mut scratch, |gu16, gw| {
let _ = for_each_grapheme_u16(seg, |gu16, gw| {
if current_col >= end_col {
return false;
}
@@ -704,8 +708,6 @@ fn extract_segments_impl(
let mut after_started = false;
let mut state = AnsiState::new();
let mut scratch = String::new();
while i < line.len() {
let done = if after_len == 0 {
current_col >= before_end
@@ -750,7 +752,7 @@ fn extract_segments_impl(
}
let seg = &line[start..i];
let _ = for_each_grapheme_u16(seg, &mut scratch, |gu16, gw| {
let _ = for_each_grapheme_u16(seg, |gu16, gw| {
let done_inner = if after_len == 0 {
current_col >= before_end
} else {
@@ -825,8 +827,7 @@ pub fn extract_segments(
#[napi(js_name = "visibleWidth")]
pub fn visible_width_napi(text: JsString) -> Result<u32> {
let text_u16 = text.into_utf16()?;
let mut scratch = String::new();
Ok(clamp_u32(visible_width_u16(text_u16.as_slice(), &mut scratch)))
Ok(clamp_u32(visible_width_u16(text_u16.as_slice())))
}
#[cfg(test)]
@@ -839,11 +840,10 @@ mod tests {
#[test]
fn test_visible_width() {
let mut scratch = String::new();
assert_eq!(visible_width_u16(&to_u16("hello"), &mut scratch), 5);
assert_eq!(visible_width_u16(&to_u16("\x1b[31mhello\x1b[0m"), &mut scratch), 5);
assert_eq!(visible_width_u16(&to_u16("\x1b[38;5;196mred\x1b[0m"), &mut scratch), 3);
assert_eq!(visible_width_u16(&to_u16("a\tb"), &mut scratch), 1 + TAB_WIDTH + 1);
assert_eq!(visible_width_u16(&to_u16("hello")), 5);
assert_eq!(visible_width_u16(&to_u16("\x1b[31mhello\x1b[0m")), 5);
assert_eq!(visible_width_u16(&to_u16("\x1b[38;5;196mred\x1b[0m")), 3);
assert_eq!(visible_width_u16(&to_u16("a\tb")), 1 + TAB_WIDTH + 1);
}
#[test]
@@ -881,8 +881,7 @@ mod tests {
#[test]
fn test_early_exit() {
let data = to_u16(&"a]b".repeat(1000));
let mut scratch = String::new();
let (w, exceeded) = visible_width_u16_up_to(&data, 10, &mut scratch);
let (w, exceeded) = visible_width_u16_up_to(&data, 10);
assert!(exceeded);
assert!(w > 10);
}
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@oh-my-pi/pi-agent-core",
"version": "9.6.2",
"version": "9.6.3",
"description": "General-purpose agent with transport abstraction, state management, and attachment support",
"type": "module",
"main": "./src/index.ts",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@oh-my-pi/pi-ai",
"version": "9.6.2",
"version": "9.6.3",
"description": "Unified LLM API with automatic model discovery and provider configuration",
"type": "module",
"main": "./src/index.ts",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@oh-my-pi/pi-coding-agent",
"version": "9.6.2",
"version": "9.6.3",
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
"type": "module",
"ompConfig": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@oh-my-pi/pi-natives",
"version": "9.6.2",
"version": "9.6.3",
"description": "Native Rust functionality via N-API",
"type": "module",
"main": "./src/index.ts",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@oh-my-pi/omp-stats",
"version": "9.6.2",
"version": "9.6.3",
"description": "Local observability dashboard for pi AI usage statistics",
"type": "module",
"main": "./src/index.ts",
-4
View File
@@ -57,10 +57,6 @@ function bunStringWidth(str: string): number {
if (str.includes("\t")) {
clean = clean.replace(/\t/g, " ");
}
if (clean.includes("\x1b")) {
clean = clean.replace(/\x1b\[[0-9;]*[mGKHJ]/g, "");
clean = clean.replace(/\x1b\]8;;[^\x07]*\x07/g, "");
}
return Bun.stringWidth(clean);
}
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@oh-my-pi/pi-tui",
"version": "9.6.2",
"version": "9.6.3",
"description": "Terminal User Interface library with differential rendering for efficient text-based applications",
"type": "module",
"main": "./src/index.ts",
+7 -2
View File
@@ -25,8 +25,8 @@ export function getSegmenter(): Intl.Segmenter {
}
// Cache for non-ASCII strings
const WIDTH_CACHE_SIZE = 512;
const widthCache = new Map<string, number>();
//const WIDTH_CACHE_SIZE = 512;
//const widthCache = new Map<string, number>();
/**
* Calculate the visible width of a string in terminal columns.
@@ -60,7 +60,11 @@ export function visibleWidth(str: string): number {
if (str.length === 0) {
return 0;
}
return visibleWidthRaw(str);
// === Disabled cache ===
/*
// Check cache
const cached = widthCache.get(str);
if (cached !== undefined) {
@@ -77,6 +81,7 @@ export function visibleWidth(str: string): number {
widthCache.set(str, width);
return width;
*/
}
const WRAP_OPTIONS = { wordWrap: true, hard: true, trim: false } as const;
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@oh-my-pi/pi-utils",
"version": "9.6.2",
"version": "9.6.3",
"description": "Shared utilities for pi packages",
"type": "module",
"main": "./src/index.ts",