rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5 heartwoodda69bd04a21eec4a40e8c923d007be5f9954f3c4
{
"request": "trigger",
"version": 1,
"event_type": "patch",
"repository": {
"id": "rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5",
"name": "heartwood",
"description": "Radicle Heartwood Protocol & Stack",
"private": false,
"default_branch": "master",
"delegates": [
"did:key:z6MksFqXN3Yhqk8pTJdUGLwATkRfQvwZXPqR2qMEhbS9wzpT",
"did:key:z6MktaNvN1KVFMkSRAiN4qK5yvX1zuEEaseeX5sffhzPZRZW",
"did:key:z6MkireRatUThvd3qzfKht1S44wpm4FEWSSa4PRMTSQZ3voM",
"did:key:z6MkgFq6z5fkF2hioLLSNu1zP2qEL1aHXHZzGH1FLFGAnBGz",
"did:key:z6MkkPvBfjP4bQmco5Dm7UGsX2ruDBieEHi8n9DVJWX5sTEz"
]
},
"action": "Created",
"patch": {
"id": "cf7f092c9bc7a5e40808dc2364ff4b3917457188",
"author": {
"id": "did:key:z6MkkPvBfjP4bQmco5Dm7UGsX2ruDBieEHi8n9DVJWX5sTEz",
"alias": "lorenz"
},
"title": "term, cli: `winsplit` over `shlex` on Windows",
"state": {
"status": "open",
"conflicts": []
},
"before": "1cab036c331f5ac071f002504c44b01e95b8f25a",
"after": "da69bd04a21eec4a40e8c923d007be5f9954f3c4",
"commits": [
"da69bd04a21eec4a40e8c923d007be5f9954f3c4"
],
"target": "82ad52b169ff5ce2f81440f79e2325afae39c1ab",
"labels": [],
"assignees": [],
"revisions": [
{
"id": "cf7f092c9bc7a5e40808dc2364ff4b3917457188",
"author": {
"id": "did:key:z6MkkPvBfjP4bQmco5Dm7UGsX2ruDBieEHi8n9DVJWX5sTEz",
"alias": "lorenz"
},
"description": "Command line parsing differs on Windows vs. POSIX compliant operating\nsystems. Thus, use the drop-in replacement `winsplit` to split command\narguments when building for Windows.",
"base": "1cab036c331f5ac071f002504c44b01e95b8f25a",
"oid": "da69bd04a21eec4a40e8c923d007be5f9954f3c4",
"timestamp": 1770627209
}
]
}
}
{
"response": "triggered",
"run_id": {
"id": "b8fd9cfb-5d23-4402-a6de-92e69a292988"
},
"info_url": "https://cci.rad.levitte.org//b8fd9cfb-5d23-4402-a6de-92e69a292988.html"
}
Started at: 2026-02-09 10:12:09.144212+01:00
Commands:
$ rad clone rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5 .
✓ Creating checkout in ./...
✓ Remote cloudhead@z6MksFqXN3Yhqk8pTJdUGLwATkRfQvwZXPqR2qMEhbS9wzpT added
✓ Remote-tracking branch cloudhead@z6MksFqXN3Yhqk8pTJdUGLwATkRfQvwZXPqR2qMEhbS9wzpT/master created for z6MksFqXN3Yhqk8pTJdUGLwATkRfQvwZXPqR2qMEhbS9wzpT
✓ Remote cloudhead@z6MktaNvN1KVFMkSRAiN4qK5yvX1zuEEaseeX5sffhzPZRZW added
✓ Remote-tracking branch cloudhead@z6MktaNvN1KVFMkSRAiN4qK5yvX1zuEEaseeX5sffhzPZRZW/master created for z6MktaNvN1KVFMkSRAiN4qK5yvX1zuEEaseeX5sffhzPZRZW
✓ Remote fintohaps@z6MkireRatUThvd3qzfKht1S44wpm4FEWSSa4PRMTSQZ3voM added
✓ Remote-tracking branch fintohaps@z6MkireRatUThvd3qzfKht1S44wpm4FEWSSa4PRMTSQZ3voM/master created for z6MkireRatUThvd3qzfKht1S44wpm4FEWSSa4PRMTSQZ3voM
✓ Remote erikli@z6MkgFq6z5fkF2hioLLSNu1zP2qEL1aHXHZzGH1FLFGAnBGz added
✓ Remote-tracking branch erikli@z6MkgFq6z5fkF2hioLLSNu1zP2qEL1aHXHZzGH1FLFGAnBGz/master created for z6MkgFq6z5fkF2hioLLSNu1zP2qEL1aHXHZzGH1FLFGAnBGz
✓ Remote lorenz@z6MkkPvBfjP4bQmco5Dm7UGsX2ruDBieEHi8n9DVJWX5sTEz added
✓ Remote-tracking branch lorenz@z6MkkPvBfjP4bQmco5Dm7UGsX2ruDBieEHi8n9DVJWX5sTEz/master created for z6MkkPvBfjP4bQmco5Dm7UGsX2ruDBieEHi8n9DVJWX5sTEz
✓ Repository successfully cloned under /opt/radcis/ci.rad.levitte.org/cci/state/b8fd9cfb-5d23-4402-a6de-92e69a292988/w/
╭────────────────────────────────────╮
│ heartwood │
│ Radicle Heartwood Protocol & Stack │
│ 136 issues · 26 patches │
╰────────────────────────────────────╯
Run `cd ./.` to go to the repository directory.
Exit code: 0
$ rad patch checkout cf7f092c9bc7a5e40808dc2364ff4b3917457188
✓ Switched to branch patch/cf7f092 at revision cf7f092
✓ Branch patch/cf7f092 setup to track rad/patches/cf7f092c9bc7a5e40808dc2364ff4b3917457188
Exit code: 0
$ git config advice.detachedHead false
Exit code: 0
$ git checkout da69bd04a21eec4a40e8c923d007be5f9954f3c4
HEAD is now at da69bd04 term, cli: `winsplit` over `shlex` on Windows
Exit code: 0
$ rad patch show cf7f092c9bc7a5e40808dc2364ff4b3917457188 -p
╭────────────────────────────────────────────────────────────────────────╮
│ Title term, cli: `winsplit` over `shlex` on Windows │
│ Patch cf7f092c9bc7a5e40808dc2364ff4b3917457188 │
│ Author lorenz z6MkkPv…WX5sTEz │
│ Head da69bd04a21eec4a40e8c923d007be5f9954f3c4 │
│ Base 1cab036c331f5ac071f002504c44b01e95b8f25a │
│ Branches patch/cf7f092 │
│ Commits ahead 1, behind 3 │
│ Status open │
│ │
│ Command line parsing differs on Windows vs. POSIX compliant operating │
│ systems. Thus, use the drop-in replacement `winsplit` to split command │
│ arguments when building for Windows. │
├────────────────────────────────────────────────────────────────────────┤
│ da69bd0 term, cli: `winsplit` over `shlex` on Windows │
├────────────────────────────────────────────────────────────────────────┤
│ ● Revision cf7f092 @ da69bd0 by lorenz z6MkkPv…WX5sTEz 18 minutes ago │
╰────────────────────────────────────────────────────────────────────────╯
commit da69bd04a21eec4a40e8c923d007be5f9954f3c4
Author: Lorenz Leutgeb <lorenz.leutgeb@radicle.xyz>
Date: Mon Feb 9 09:48:52 2026 +0100
term, cli: `winsplit` over `shlex` on Windows
Command line parsing differs on Windows vs. POSIX compliant operating
systems. Thus, use the drop-in replacement `winsplit` to split command
arguments when building for Windows.
diff --git a/Cargo.lock b/Cargo.lock
index 1adcab8e1..954b67d3e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2888,6 +2888,7 @@ dependencies = [
"tree-sitter-rust",
"tree-sitter-toml-ng",
"tree-sitter-typescript",
+ "winsplit",
"zeroize",
]
@@ -3200,6 +3201,7 @@ dependencies = [
"thiserror 2.0.17",
"unicode-display-width",
"unicode-segmentation",
+ "winsplit",
"zeroize",
]
@@ -5106,6 +5108,12 @@ dependencies = [
"windows",
]
+[[package]]
+name = "winsplit"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3ab703352da6a72f35c39a533526393725640575bb211f61987a2748323ad956"
+
[[package]]
name = "wit-bindgen-rt"
version = "0.39.0"
diff --git a/Cargo.toml b/Cargo.toml
index e4a84362b..7c0ac0cc4 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -69,6 +69,7 @@ sqlite = "0.32.0"
tempfile = "3.3.0"
thiserror = { version = "2", default-features = false }
winpipe = "0.1.1"
+winsplit = "0.1.0"
zeroize = "1.5.7"
# Crates from the "radicle-git" workspace. These should be synced manually.
diff --git a/crates/radicle-cli-test/src/lib.rs b/crates/radicle-cli-test/src/lib.rs
index fafe944bb..165a82048 100644
--- a/crates/radicle-cli-test/src/lib.rs
+++ b/crates/radicle-cli-test/src/lib.rs
@@ -10,6 +10,11 @@ use snapbox::cmd::{Command, OutputAssert};
use snapbox::{Assert, Substitutions};
use thiserror::Error;
+#[cfg(unix)]
+use shlex::split;
+#[cfg(windows)]
+use winsplit::split;
+
/// Used to ensure the build task is only run once.
static BUILD: sync::Once = sync::Once::new();
@@ -347,7 +352,7 @@ impl TestFormula {
content.push('\n');
} else if let Some(line) = line.strip_prefix('$') {
let line = line.trim();
- let parts = shlex::split(line).ok_or(Error::Parse)?;
+ let parts = split(line).ok_or(Error::Parse)?;
let (cmd, args) = parts.split_first().ok_or(Error::Parse)?;
test.assertions.push(Assertion {
diff --git a/crates/radicle-cli/Cargo.toml b/crates/radicle-cli/Cargo.toml
index e147155d2..33f541cfe 100644
--- a/crates/radicle-cli/Cargo.toml
+++ b/crates/radicle-cli/Cargo.toml
@@ -33,7 +33,6 @@ radicle-term = { workspace = true }
schemars = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
-shlex = { workspace = true }
tempfile = { workspace = true }
thiserror = { workspace = true, default-features = true }
timeago = { version = "0.4.2", default-features = false }
@@ -53,6 +52,12 @@ tree-sitter-toml-ng = "0.6.0"
tree-sitter-typescript = "0.23.2"
zeroize = { workspace = true }
+[target.'cfg(unix)'.dependencies]
+shlex = { workspace = true }
+
+[target.'cfg(windows)'.dependencies]
+winsplit = { workspace = true }
+
[dev-dependencies]
pretty_assertions = { workspace = true }
radicle = { workspace = true, features = ["test"] }
diff --git a/crates/radicle-cli/src/pager.rs b/crates/radicle-cli/src/pager.rs
index 35bf358ba..7f8b7866c 100644
--- a/crates/radicle-cli/src/pager.rs
+++ b/crates/radicle-cli/src/pager.rs
@@ -1,6 +1,11 @@
use std::io;
use std::process::{Command, Stdio};
+#[cfg(unix)]
+use shlex::split;
+#[cfg(windows)]
+use winsplit::split;
+
use radicle_term::element;
use radicle_term::{Constraint, Element};
@@ -21,7 +26,7 @@ pub fn run(elem: impl Element) -> io::Result<()> {
let Some(pager) = radicle::profile::env::pager() else {
return elem.write(Constraint::UNBOUNDED);
};
- let Some(parts) = shlex::split(&pager) else {
+ let Some(parts) = split(&pager) else {
return elem.write(Constraint::UNBOUNDED);
};
let Some((program, args)) = parts.split_first() else {
diff --git a/crates/radicle-term/Cargo.toml b/crates/radicle-term/Cargo.toml
index a128c0bb0..cb33f5213 100644
--- a/crates/radicle-term/Cargo.toml
+++ b/crates/radicle-term/Cargo.toml
@@ -25,12 +25,15 @@ unicode-display-width = "0.3.0"
unicode-segmentation = "1.7.1"
zeroize = { workspace = true }
git2 = { workspace = true, optional = true }
-shlex = { workspace = true }
[target.'cfg(unix)'.dependencies]
crossbeam-channel = { workspace = true }
libc = { workspace = true }
radicle-signals = { workspace = true }
+shlex = { workspace = true }
+
+[target.'cfg(windows)'.dependencies]
+winsplit = { workspace = true }
[dev-dependencies]
pretty_assertions = { workspace = true }
diff --git a/crates/radicle-term/src/editor.rs b/crates/radicle-term/src/editor.rs
index 4b4d4fd09..23514e6b2 100644
--- a/crates/radicle-term/src/editor.rs
+++ b/crates/radicle-term/src/editor.rs
@@ -5,6 +5,11 @@ use std::path::{Path, PathBuf};
use std::process;
use std::{env, fs, io};
+#[cfg(windows)]
+use winsplit::split;
+#[cfg(unix)]
+use shlex::split;
+
/// Allows for text input in the configured editor.
pub struct Editor {
path: PathBuf,
@@ -110,7 +115,7 @@ impl Editor {
"editor not configured: the `EDITOR` environment variable is not set",
));
};
- let Some(parts) = shlex::split(cmd.to_string_lossy().as_ref()) else {
+ let Some(parts) = split(cmd.to_string_lossy().as_ref()) else {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
format!("invalid editor command {cmd:?}"),
Exit code: 0
shell: 'export RUSTDOCFLAGS=''-D warnings'' cargo --version rustc --version cargo fmt --check cargo clippy --all-targets --workspace -- --deny warnings cargo build --all-targets --workspace cargo doc --workspace --no-deps --all-features cargo test --workspace --no-fail-fast '
Commands:
$ podman run --name b8fd9cfb-5d23-4402-a6de-92e69a292988 -v /opt/radcis/ci.rad.levitte.org/cci/state/b8fd9cfb-5d23-4402-a6de-92e69a292988/s:/b8fd9cfb-5d23-4402-a6de-92e69a292988/s:ro -v /opt/radcis/ci.rad.levitte.org/cci/state/b8fd9cfb-5d23-4402-a6de-92e69a292988/w:/b8fd9cfb-5d23-4402-a6de-92e69a292988/w -w /b8fd9cfb-5d23-4402-a6de-92e69a292988/w -v /opt/radcis/ci.rad.levitte.org/.radicle:/${id}/.radicle:ro -e RAD_HOME=/${id}/.radicle rust:trixie bash /b8fd9cfb-5d23-4402-a6de-92e69a292988/s/script.sh
+ export 'RUSTDOCFLAGS=-D warnings'
+ RUSTDOCFLAGS='-D warnings'
+ cargo --version
info: syncing channel updates for '1.90-x86_64-unknown-linux-gnu'
info: latest update on 2025-09-18, rust version 1.90.0 (1159e78c4 2025-09-14)
info: downloading component 'cargo'
info: downloading component 'clippy'
info: downloading component 'rust-docs'
info: downloading component 'rust-src'
info: downloading component 'rust-std'
info: downloading component 'rustc'
info: downloading component 'rustfmt'
info: installing component 'cargo'
info: installing component 'clippy'
info: installing component 'rust-docs'
info: installing component 'rust-src'
info: installing component 'rust-std'
info: installing component 'rustc'
info: installing component 'rustfmt'
cargo 1.90.0 (840b83a10 2025-07-30)
+ rustc --version
rustc 1.90.0 (1159e78c4 2025-09-14)
+ cargo fmt --check
Diff in /b8fd9cfb-5d23-4402-a6de-92e69a292988/w/crates/radicle-term/src/editor.rs:5:
use std::process;
use std::{env, fs, io};
-#[cfg(windows)]
-use winsplit::split;
#[cfg(unix)]
use shlex::split;
+#[cfg(windows)]
+use winsplit::split;
/// Allows for text input in the configured editor.
pub struct Editor {
Exit code: 1
{
"response": "finished",
"result": "failure"
}