From 5823900439746597990a228d843c63ef4650acda Mon Sep 17 00:00:00 2001 From: bherbruck Date: Thu, 15 Oct 2026 17:22:28 -0400 Subject: [PATCH 1/3] Release 0.13.0 (#1506) Version 0.13.0, plus the Windows 32-bit and macOS release-build fixes from #1513. Co-Authored-By: Claude Opus 5.5 --- Cargo.lock | 30 ++++++++++++++--------------- Cargo.toml | 2 +- apps/solidcraft/src/native_frame.rs | 8 +++++--- packaging/macos/package.sh | 4 +++- 4 files changed, 24 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ed1428ef..0e4b61c2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3704,7 +3704,7 @@ dependencies = [ [[package]] name = "solidcraft" -version = "0.12.0" +version = "0.13.0" dependencies = [ "block2 0.6.2", "eframe", @@ -3733,7 +3733,7 @@ dependencies = [ [[package]] name = "solidcraft-cli" -version = "0.12.0" +version = "0.13.0" dependencies = [ "serde_json", "solidcraft-engine", @@ -3742,7 +3742,7 @@ dependencies = [ [[package]] name = "solidcraft-derive" -version = "0.12.0" +version = "0.13.0" dependencies = [ "proc-macro2", "quote", @@ -3751,7 +3751,7 @@ dependencies = [ [[package]] name = "solidcraft-doc" -version = "0.12.0" +version = "0.13.0" dependencies = [ "log", "serde", @@ -3768,7 +3768,7 @@ dependencies = [ [[package]] name = "solidcraft-engine" -version = "0.12.0" +version = "0.13.0" dependencies = [ "log", "serde", @@ -3784,7 +3784,7 @@ dependencies = [ [[package]] name = "solidcraft-geom" -version = "0.12.0" +version = "0.13.0" dependencies = [ "serde", "serde_json", @@ -3793,7 +3793,7 @@ dependencies = [ [[package]] name = "solidcraft-gpu" -version = "0.12.0" +version = "0.13.0" dependencies = [ "log", "naga", @@ -3806,7 +3806,7 @@ dependencies = [ [[package]] name = "solidcraft-io" -version = "0.12.0" +version = "0.13.0" dependencies = [ "quick-xml", "serde", @@ -3821,7 +3821,7 @@ dependencies = [ [[package]] name = "solidcraft-kernel" -version = "0.12.0" +version = "0.13.0" dependencies = [ "log", "rayon", @@ -3839,7 +3839,7 @@ dependencies = [ [[package]] name = "solidcraft-mcp" -version = "0.12.0" +version = "0.13.0" dependencies = [ "serde_json", "solidcraft-engine", @@ -3847,7 +3847,7 @@ dependencies = [ [[package]] name = "solidcraft-render" -version = "0.12.0" +version = "0.13.0" dependencies = [ "image", "moxcms", @@ -3860,7 +3860,7 @@ dependencies = [ [[package]] name = "solidcraft-sketch" -version = "0.12.0" +version = "0.13.0" dependencies = [ "serde", "serde_json", @@ -3871,7 +3871,7 @@ dependencies = [ [[package]] name = "solidcraft-ui-egui" -version = "0.12.0" +version = "0.13.0" dependencies = [ "egui", "egui-wgpu", @@ -3892,7 +3892,7 @@ dependencies = [ [[package]] name = "solidcraft-web" -version = "0.12.0" +version = "0.13.0" dependencies = [ "eframe", "egui", @@ -5381,7 +5381,7 @@ checksum = "e450f9b2ed1dff33c94c12589a87338689467b9c4f5d8a5710bd09a847d2c8a7" [[package]] name = "xtask" -version = "0.12.0" +version = "0.13.0" dependencies = [ "serde_json", "sha2", diff --git a/Cargo.toml b/Cargo.toml index c3af526a..a35256e3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ members = ["crates/*", "apps/*", "xtask"] exclude = ["vendor"] [workspace.package] -version = "0.12.0" +version = "0.13.0" edition = "2024" license = "MIT OR Apache-2.0" rust-version = "1.95" diff --git a/apps/solidcraft/src/native_frame.rs b/apps/solidcraft/src/native_frame.rs index 9bac6d4e..d6fb5117 100644 --- a/apps/solidcraft/src/native_frame.rs +++ b/apps/solidcraft/src/native_frame.rs @@ -48,11 +48,13 @@ pub fn install(window: &impl HasWindowHandle) -> bool { // SAFETY: `hwnd` is the live window eframe just created on this thread; `frame_proc` has the // WNDPROC signature and stays valid for the life of the process. SetWindowLongPtrW returns // the previous procedure, which `frame_proc` calls for every other message. - let previous = unsafe { SetWindowLongPtrW(hwnd, GWLP_WNDPROC, frame_proc as *const () as isize) }; + let previous = unsafe { SetWindowLongPtrW(hwnd, GWLP_WNDPROC, frame_proc as *const () as isize as _) }; + // `as _`: on 32-bit Windows SetWindowLongPtrW is SetWindowLongW, which takes and + // returns i32. if previous == 0 { return false; } - PREVIOUS.store(previous, Ordering::SeqCst); + PREVIOUS.store(previous as _, Ordering::SeqCst); true } @@ -97,7 +99,7 @@ unsafe extern "system" fn frame_proc(hwnd: HWND, msg: u32, wparam: WPARAM, lpara // Hand the window back to winit's procedure for its last message. if prev.is_some() { // SAFETY: restores the procedure this window had before `install`. - unsafe { SetWindowLongPtrW(hwnd, GWLP_WNDPROC, PREVIOUS.load(Ordering::SeqCst)) }; + unsafe { SetWindowLongPtrW(hwnd, GWLP_WNDPROC, PREVIOUS.load(Ordering::SeqCst) as _) }; } call_previous() } diff --git a/packaging/macos/package.sh b/packaging/macos/package.sh index 06881f4e..08112bb9 100755 --- a/packaging/macos/package.sh +++ b/packaging/macos/package.sh @@ -73,7 +73,9 @@ copy_docs "$APP/Contents/Resources/Licenses" sed -e "s/@VERSION@/$VERSION/g" -e "s/@SHORT_VERSION@/$SHORT_VERSION/g" "$ROOT/assets/platforms/macos/Info.plist.in" >"$APP/Contents/Info.plist" plutil -lint "$APP/Contents/Info.plist" printf 'APPL????' >"$APP/Contents/PkgInfo" -# Ad-hoc signature over the whole bundle (Apple silicon refuses unsigned code). +# Ad-hoc signature over the whole bundle (Apple silicon refuses unsigned code). Nested code is +# signed first: the bundle signature refuses an unsigned helper in Contents/MacOS. +codesign --force --sign - --timestamp=none --identifier "$MACOS_BUNDLE_ID-cli" "$APP/Contents/MacOS/solidcraft-cli" codesign --force --sign - --timestamp=none "$APP" codesign --verify --strict --deep --verbose=2 "$APP" test -x "$APP/Contents/MacOS/solidcraft-cli" || { echo "solidcraft-cli is missing from $APP" >&2; exit 1; } From 20442eecd3c81c543eae5672955626c87035d874 Mon Sep 17 00:00:00 2001 From: bherbruck Date: Thu, 15 Oct 2026 21:49:46 +0000 Subject: [PATCH 2/3] Agent chat on Windows: start npm agents through their .cmd shim npm puts a Unix shell script with the bare name (codex-acp, claude-code-acp, gemini) beside the .cmd shim. The lookup tried the bare name first, so every npm-installed agent failed with "not a valid Win32 application (os error 193)". Windows now only considers .exe/.cmd/.bat, and a command saved with the bare path runs the shim beside it. Co-Authored-By: Claude Opus 5.5 (cherry picked from commit 60ea8c69d26e21bea09bd6239313d43f5af112b3) --- crates/ui-egui/src/agent_chat/discover.rs | 42 +++++++++++++++++++++-- crates/ui-egui/src/agent_chat/process.rs | 5 ++- 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/crates/ui-egui/src/agent_chat/discover.rs b/crates/ui-egui/src/agent_chat/discover.rs index fcd09660..24fffffa 100644 --- a/crates/ui-egui/src/agent_chat/discover.rs +++ b/crates/ui-egui/src/agent_chat/discover.rs @@ -184,13 +184,30 @@ pub fn search_dirs() -> Vec { dirs } -/// The first `program` in `dirs` (on Windows also with `.exe`/`.cmd`). +/// The first `program` in `dirs` (on Windows with `.exe`/`.cmd`/`.bat`). pub fn find_in(program: &str, dirs: &[PathBuf]) -> Option { - let names: Vec = - if cfg!(windows) { ["", ".exe", ".cmd", ".bat"].iter().map(|e| format!("{program}{e}")).collect() } else { vec![program.to_string()] }; + let names = names_for(program, cfg!(windows)); dirs.iter().flat_map(|d| names.iter().map(move |n| d.join(n))).find(|p| p.is_file()) } +/// The file names `program` can have. On Windows only ones it can run: npm puts a Unix shell +/// script with the bare name next to the `.cmd` shim, and starting that fails with "not a valid +/// Win32 application". +fn names_for(program: &str, windows: bool) -> Vec { + if windows { [".exe", ".cmd", ".bat"].iter().map(|e| format!("{program}{e}")).collect() } else { vec![program.to_string()] } +} + +/// A Windows command saved without an extension (`…\npm\codex-acp`, from an older version's +/// lookup): the `.exe`/`.cmd`/`.bat` beside it, if there is one. +pub fn runnable_sibling(program: &Path) -> Option { + if program.extension().is_some() { + return None; + } + let dir = program.parent()?; + let name = program.file_name()?.to_str()?; + names_for(name, true).into_iter().map(|n| dir.join(n)).find(|p| p.is_file()) +} + /// `program --version`'s first line, or `None` after `limit` (the probe is then stopped). fn version(program: &Path, limit: Duration) -> Option { let mut cmd = if cfg!(windows) && program.extension().is_some_and(|e| e.eq_ignore_ascii_case("cmd") || e.eq_ignore_ascii_case("bat")) { @@ -279,6 +296,25 @@ mod tests { let _ = std::fs::remove_dir_all(root); } + #[test] + fn on_windows_only_runnable_shims_are_candidates() { + // npm's bare `codex-acp` is a shell script; Windows can't start it (os error 193). + assert_eq!(names_for("codex-acp", true), ["codex-acp.exe", "codex-acp.cmd", "codex-acp.bat"]); + assert_eq!(names_for("codex-acp", false), ["codex-acp"]); + } + + #[test] + fn a_saved_bare_npm_path_runs_its_cmd_shim() { + let root = std::env::temp_dir().join(format!("sc-agent-shim-{}", std::process::id())); + std::fs::create_dir_all(&root).unwrap(); + std::fs::write(root.join("codex-acp"), "#!/bin/sh").unwrap(); + std::fs::write(root.join("codex-acp.cmd"), "@echo off").unwrap(); + assert_eq!(runnable_sibling(&root.join("codex-acp")), Some(root.join("codex-acp.cmd"))); + assert_eq!(runnable_sibling(&root.join("codex-acp.cmd")), None); + assert_eq!(runnable_sibling(&root.join("gemini")), None); + let _ = std::fs::remove_dir_all(root); + } + #[test] fn the_version_number_is_picked_out_of_the_line() { assert_eq!(version_of("@agentclientprotocol/codex-acp 2.2.2"), "2.2.2"); diff --git a/crates/ui-egui/src/agent_chat/process.rs b/crates/ui-egui/src/agent_chat/process.rs index 4fc64484..e7049972 100644 --- a/crates/ui-egui/src/agent_chat/process.rs +++ b/crates/ui-egui/src/agent_chat/process.rs @@ -51,8 +51,11 @@ impl ProcessHandle { } } -/// On Windows, npm installs `.cmd` shims, which only `cmd.exe` runs. +/// On Windows, npm installs `.cmd` shims, which only `cmd.exe` runs. A command saved as the bare +/// npm path (a shell script there) runs the shim beside it. fn command_for(program: &str) -> Command { + let shim = if cfg!(windows) { super::discover::runnable_sibling(std::path::Path::new(program)) } else { None }; + let program = shim.as_deref().and_then(|p| p.to_str()).unwrap_or(program); let lower = program.to_ascii_lowercase(); if cfg!(windows) && (lower.ends_with(".cmd") || lower.ends_with(".bat")) { let mut c = Command::new("cmd"); From 800ea40c0daf0c1704652672cde160095091d788 Mon Sep 17 00:00:00 2001 From: bherbruck Date: Thu, 15 Oct 2026 21:56:35 +0000 Subject: [PATCH 3/3] Release 0.13.1 Co-Authored-By: Claude Opus 5.5 --- Cargo.lock | 30 +++++++++++++++--------------- Cargo.toml | 2 +- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0e4b61c2..634ae318 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3704,7 +3704,7 @@ dependencies = [ [[package]] name = "solidcraft" -version = "0.13.0" +version = "0.13.1" dependencies = [ "block2 0.6.2", "eframe", @@ -3733,7 +3733,7 @@ dependencies = [ [[package]] name = "solidcraft-cli" -version = "0.13.0" +version = "0.13.1" dependencies = [ "serde_json", "solidcraft-engine", @@ -3742,7 +3742,7 @@ dependencies = [ [[package]] name = "solidcraft-derive" -version = "0.13.0" +version = "0.13.1" dependencies = [ "proc-macro2", "quote", @@ -3751,7 +3751,7 @@ dependencies = [ [[package]] name = "solidcraft-doc" -version = "0.13.0" +version = "0.13.1" dependencies = [ "log", "serde", @@ -3768,7 +3768,7 @@ dependencies = [ [[package]] name = "solidcraft-engine" -version = "0.13.0" +version = "0.13.1" dependencies = [ "log", "serde", @@ -3784,7 +3784,7 @@ dependencies = [ [[package]] name = "solidcraft-geom" -version = "0.13.0" +version = "0.13.1" dependencies = [ "serde", "serde_json", @@ -3793,7 +3793,7 @@ dependencies = [ [[package]] name = "solidcraft-gpu" -version = "0.13.0" +version = "0.13.1" dependencies = [ "log", "naga", @@ -3806,7 +3806,7 @@ dependencies = [ [[package]] name = "solidcraft-io" -version = "0.13.0" +version = "0.13.1" dependencies = [ "quick-xml", "serde", @@ -3821,7 +3821,7 @@ dependencies = [ [[package]] name = "solidcraft-kernel" -version = "0.13.0" +version = "0.13.1" dependencies = [ "log", "rayon", @@ -3839,7 +3839,7 @@ dependencies = [ [[package]] name = "solidcraft-mcp" -version = "0.13.0" +version = "0.13.1" dependencies = [ "serde_json", "solidcraft-engine", @@ -3847,7 +3847,7 @@ dependencies = [ [[package]] name = "solidcraft-render" -version = "0.13.0" +version = "0.13.1" dependencies = [ "image", "moxcms", @@ -3860,7 +3860,7 @@ dependencies = [ [[package]] name = "solidcraft-sketch" -version = "0.13.0" +version = "0.13.1" dependencies = [ "serde", "serde_json", @@ -3871,7 +3871,7 @@ dependencies = [ [[package]] name = "solidcraft-ui-egui" -version = "0.13.0" +version = "0.13.1" dependencies = [ "egui", "egui-wgpu", @@ -3892,7 +3892,7 @@ dependencies = [ [[package]] name = "solidcraft-web" -version = "0.13.0" +version = "0.13.1" dependencies = [ "eframe", "egui", @@ -5381,7 +5381,7 @@ checksum = "e450f9b2ed1dff33c94c12589a87338689467b9c4f5d8a5710bd09a847d2c8a7" [[package]] name = "xtask" -version = "0.13.0" +version = "0.13.1" dependencies = [ "serde_json", "sha2", diff --git a/Cargo.toml b/Cargo.toml index a35256e3..a091f727 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ members = ["crates/*", "apps/*", "xtask"] exclude = ["vendor"] [workspace.package] -version = "0.13.0" +version = "0.13.1" edition = "2024" license = "MIT OR Apache-2.0" rust-version = "1.95"