diff --git a/src/apps/cli/src/dispatch/mod.rs b/src/apps/cli/src/dispatch/mod.rs index 982b28fa22..fa9e568885 100644 --- a/src/apps/cli/src/dispatch/mod.rs +++ b/src/apps/cli/src/dispatch/mod.rs @@ -6,12 +6,12 @@ mod worker; mod workspace; use std::path::{Path, PathBuf}; -use std::process::Command; use anyhow::{anyhow, bail, Context, Result}; use bitfun_core::infrastructure::ai::AIClientFactory; use bitfun_core::service::config::{AuthConfig, GlobalConfig}; use bitfun_core::service::git::trust; +use bitfun_services_core::process_manager; use serde::de::DeserializeOwned; use protocol::{ @@ -853,7 +853,7 @@ fn classify_repository_probe(result: Result) -> /// below matches Git's English prose, and a localized host would otherwise make /// an ownership rejection unrecognizable. fn git_probe(workspace: &Path, args: &[&str]) -> Result { - let output = Command::new("git") + let output = process_manager::create_command("git") .env("LC_ALL", "C") .arg("-C") .arg(workspace) diff --git a/src/apps/cli/src/dispatch/workspace.rs b/src/apps/cli/src/dispatch/workspace.rs index 465dccf592..eda060fbc2 100644 --- a/src/apps/cli/src/dispatch/workspace.rs +++ b/src/apps/cli/src/dispatch/workspace.rs @@ -20,6 +20,7 @@ use std::time::{Duration, Instant}; use anyhow::{bail, Context, Result}; use base64::Engine as _; use bitfun_services_core::dispatch_workspace::sha256_file; +use bitfun_services_core::process_manager; use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256}; @@ -1573,7 +1574,7 @@ fn commit_exists(repo: &Path, commit: &str) -> Result { } fn git_command(dir: &Path) -> Command { - let mut command = Command::new("git"); + let mut command = process_manager::create_command("git"); command .current_dir(dir) // A detached dispatch worker has nobody to answer a credential or diff --git a/src/apps/cli/src/modes/chat/external_editor.rs b/src/apps/cli/src/modes/chat/external_editor.rs index 68127af24d..ec27b3901d 100644 --- a/src/apps/cli/src/modes/chat/external_editor.rs +++ b/src/apps/cli/src/modes/chat/external_editor.rs @@ -208,7 +208,7 @@ fn editor_process( command: &EditorCommand, path: &std::path::Path, ) -> Result { - let mut process = Command::new(&command.program); + let mut process = bitfun_core::util::process_manager::create_command(&command.program); process.args(&command.args).arg(path); Ok(process) } @@ -235,7 +235,7 @@ fn editor_process( } values.push(quote_windows_batch_value(path.as_os_str())?); let command_line = values.join(" "); - let mut process = Command::new("cmd.exe"); + let mut process = bitfun_core::util::process_manager::create_command("cmd.exe"); process.args(["/d", "/v:off", "/s", "/c"]); // cmd.exe requires an extra outer quote pair when the command itself // begins with a quoted executable path. raw_arg is intentional here: @@ -243,7 +243,7 @@ fn editor_process( process.raw_arg(format!("\"{command_line}\"")); Ok(process) } else { - let mut process = Command::new(&command.program); + let mut process = bitfun_core::util::process_manager::create_command(&command.program); process.args(&command.args).arg(path); Ok(process) } diff --git a/src/apps/cli/src/modes/exec/verification.rs b/src/apps/cli/src/modes/exec/verification.rs index 027e03a952..70122980ca 100644 --- a/src/apps/cli/src/modes/exec/verification.rs +++ b/src/apps/cli/src/modes/exec/verification.rs @@ -63,11 +63,11 @@ pub(super) async fn run_verifier( retries_used: u32, ) -> VerifyOutcome { let mut process = if cfg!(windows) { - let mut process = tokio::process::Command::new("cmd"); + let mut process = bitfun_services_core::process_manager::create_tokio_command("cmd"); process.arg("/C").arg(command); process } else { - let mut process = tokio::process::Command::new("sh"); + let mut process = bitfun_services_core::process_manager::create_tokio_command("sh"); process.arg("-c").arg(command); process }; diff --git a/src/apps/desktop/src/api/dispatch_host.rs b/src/apps/desktop/src/api/dispatch_host.rs index 71ebb3775e..cc13b3ef34 100644 --- a/src/apps/desktop/src/api/dispatch_host.rs +++ b/src/apps/desktop/src/api/dispatch_host.rs @@ -10,7 +10,6 @@ use std::time::Duration; use anyhow::{anyhow, Context}; use serde_json::Value; use tokio::io::AsyncWriteExt; -use tokio::process::Command; const TARGET_COMMAND_TIMEOUT: Duration = Duration::from_secs(110); const MAX_TARGET_RESPONSE_BYTES: usize = 4 * 1024 * 1024; @@ -53,7 +52,7 @@ fn target_cli_verb(command: &str) -> Option<&'static str> { async fn invoke_cli(executable: &Path, verb: &str, args: Value) -> anyhow::Result { let request = serde_json::to_vec(&args).context("serialize target dispatch request")?; - let mut child = Command::new(executable) + let mut child = bitfun_core::util::process_manager::create_tokio_command(executable) .arg("dispatch") .arg(verb) .stdin(std::process::Stdio::piped()) diff --git a/src/crates/services/services-integrations/src/workspace_search/auto_index.rs b/src/crates/services/services-integrations/src/workspace_search/auto_index.rs index 3444438f99..6ab9d889a6 100644 --- a/src/crates/services/services-integrations/src/workspace_search/auto_index.rs +++ b/src/crates/services/services-integrations/src/workspace_search/auto_index.rs @@ -1,6 +1,8 @@ use std::path::{Path, PathBuf}; +#[cfg(test)] use std::process::Command; +use bitfun_services_core::process_manager; use tokio::task::spawn_blocking; pub(crate) const DEFAULT_AUTO_INDEX_MIN_FILES: usize = 2_000; @@ -99,7 +101,7 @@ fn git_ls_files_indexable_count( policy: AutoIndexPolicy, carried: usize, ) -> Result { - let output = Command::new("git") + let output = process_manager::create_command("git") .arg("ls-files") .args(selectors) .arg("-z") @@ -128,7 +130,7 @@ fn git_ls_files_indexable_count( } fn git_worktree_root(repo_root: &Path) -> Result { - let output = Command::new("git") + let output = process_manager::create_command("git") .args(["rev-parse", "--show-toplevel"]) .current_dir(repo_root) .output() @@ -146,7 +148,7 @@ fn git_worktree_root(repo_root: &Path) -> Result { } let worktree_root = dunce::canonicalize(root) .map_err(|error| format!("cannot canonicalize Git worktree root: {error}"))?; - let head = Command::new("git") + let head = process_manager::create_command("git") .args(["rev-parse", "--verify", "HEAD^{commit}"]) .current_dir(&worktree_root) .output()