More no-window flags (#7122)
This commit is contained in:
@@ -5,8 +5,10 @@ use goose::recipe::RECIPE_FILE_EXTENSIONS;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use goose::recipe::read_recipe_file_content::RecipeFile;
|
use goose::recipe::read_recipe_file_content::RecipeFile;
|
||||||
|
use goose::subprocess::SubprocessExt;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
@@ -104,6 +106,7 @@ pub fn ensure_gh_authenticated() -> Result<()> {
|
|||||||
// Check authentication status
|
// Check authentication status
|
||||||
let status = Command::new("gh")
|
let status = Command::new("gh")
|
||||||
.args(["auth", "status"])
|
.args(["auth", "status"])
|
||||||
|
.set_no_window()
|
||||||
.status()
|
.status()
|
||||||
.map_err(|_| {
|
.map_err(|_| {
|
||||||
anyhow::anyhow!("Failed to run `gh auth status`. Make sure you have `gh` installed.")
|
anyhow::anyhow!("Failed to run `gh auth status`. Make sure you have `gh` installed.")
|
||||||
@@ -151,6 +154,7 @@ fn ensure_repo_cloned(recipe_repo_full_name: &str) -> Result<PathBuf> {
|
|||||||
let status = Command::new("gh")
|
let status = Command::new("gh")
|
||||||
.args(["repo", "clone", recipe_repo_full_name])
|
.args(["repo", "clone", recipe_repo_full_name])
|
||||||
.current_dir(local_repo_parent_path.clone())
|
.current_dir(local_repo_parent_path.clone())
|
||||||
|
.set_no_window()
|
||||||
.status()
|
.status()
|
||||||
.map_err(|_: std::io::Error| anyhow::anyhow!(error_message.clone()))?;
|
.map_err(|_: std::io::Error| anyhow::anyhow!(error_message.clone()))?;
|
||||||
|
|
||||||
@@ -167,6 +171,7 @@ fn fetch_origin(local_repo_path: &Path) -> Result<()> {
|
|||||||
let status = Command::new("git")
|
let status = Command::new("git")
|
||||||
.args(["fetch", "origin"])
|
.args(["fetch", "origin"])
|
||||||
.current_dir(local_repo_path)
|
.current_dir(local_repo_path)
|
||||||
|
.set_no_window()
|
||||||
.status()
|
.status()
|
||||||
.map_err(|_| anyhow::anyhow!(error_message.clone()))?;
|
.map_err(|_| anyhow::anyhow!(error_message.clone()))?;
|
||||||
|
|
||||||
@@ -190,6 +195,7 @@ fn get_folder_from_github(local_repo_path: &Path, recipe_name: &str) -> Result<P
|
|||||||
.args(["archive", &ref_and_path])
|
.args(["archive", &ref_and_path])
|
||||||
.current_dir(local_repo_path)
|
.current_dir(local_repo_path)
|
||||||
.stdout(Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
|
.set_no_window()
|
||||||
.spawn()?;
|
.spawn()?;
|
||||||
|
|
||||||
let stdout = archive_output
|
let stdout = archive_output
|
||||||
@@ -230,6 +236,7 @@ fn discover_github_recipes(repo: &str) -> Result<Vec<RecipeInfo>> {
|
|||||||
// Get repository contents using GitHub CLI
|
// Get repository contents using GitHub CLI
|
||||||
let output = Command::new("gh")
|
let output = Command::new("gh")
|
||||||
.args(["api", &format!("repos/{}/contents", repo)])
|
.args(["api", &format!("repos/{}/contents", repo)])
|
||||||
|
.set_no_window()
|
||||||
.output()
|
.output()
|
||||||
.map_err(|e| anyhow!("Failed to fetch repository contents using 'gh api' command (executed when GOOSE_RECIPE_GITHUB_REPO is configured). This requires GitHub CLI (gh) to be installed and authenticated. Error: {}", e))?;
|
.map_err(|e| anyhow!("Failed to fetch repository contents using 'gh api' command (executed when GOOSE_RECIPE_GITHUB_REPO is configured). This requires GitHub CLI (gh) to be installed and authenticated. Error: {}", e))?;
|
||||||
|
|
||||||
@@ -269,6 +276,7 @@ fn check_github_directory_for_recipe(repo: &str, dir_name: &str) -> Result<Recip
|
|||||||
// Check directory contents for recipe files
|
// Check directory contents for recipe files
|
||||||
let output = Command::new("gh")
|
let output = Command::new("gh")
|
||||||
.args(["api", &format!("repos/{}/contents/{}", repo, dir_name)])
|
.args(["api", &format!("repos/{}/contents/{}", repo, dir_name)])
|
||||||
|
.set_no_window()
|
||||||
.output()
|
.output()
|
||||||
.map_err(|e| anyhow!("Failed to check directory contents: {}", e))?;
|
.map_err(|e| anyhow!("Failed to check directory contents: {}", e))?;
|
||||||
|
|
||||||
@@ -306,6 +314,7 @@ fn get_github_recipe_info(repo: &str, dir_name: &str, recipe_filename: &str) ->
|
|||||||
"api",
|
"api",
|
||||||
&format!("repos/{}/contents/{}/{}", repo, dir_name, recipe_filename),
|
&format!("repos/{}/contents/{}/{}", repo, dir_name, recipe_filename),
|
||||||
])
|
])
|
||||||
|
.set_no_window()
|
||||||
.output()
|
.output()
|
||||||
.map_err(|e| anyhow!("Failed to get recipe file content: {}", e))?;
|
.map_err(|e| anyhow!("Failed to get recipe file content: {}", e))?;
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ use goose::conversation::message::{
|
|||||||
ActionRequiredData, Message, MessageContent, ToolRequest, ToolResponse,
|
ActionRequiredData, Message, MessageContent, ToolRequest, ToolResponse,
|
||||||
};
|
};
|
||||||
use goose::providers::canonical::maybe_get_canonical_model;
|
use goose::providers::canonical::maybe_get_canonical_model;
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
use goose::subprocess::SubprocessExt;
|
||||||
use goose::utils::safe_truncate;
|
use goose::utils::safe_truncate;
|
||||||
use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
|
use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
|
||||||
use rmcp::model::{CallToolRequestParams, JsonObject, PromptArgument};
|
use rmcp::model::{CallToolRequestParams, JsonObject, PromptArgument};
|
||||||
@@ -179,6 +181,7 @@ pub fn run_status_hook(status: &str) {
|
|||||||
.stdin(std::process::Stdio::null())
|
.stdin(std::process::Stdio::null())
|
||||||
.stdout(std::process::Stdio::null())
|
.stdout(std::process::Stdio::null())
|
||||||
.stderr(std::process::Stdio::null())
|
.stderr(std::process::Stdio::null())
|
||||||
|
.set_no_window()
|
||||||
.status();
|
.status();
|
||||||
|
|
||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use crate::subprocess::SubprocessExt;
|
||||||
use etcetera::{choose_app_strategy, AppStrategy};
|
use etcetera::{choose_app_strategy, AppStrategy};
|
||||||
use indoc::{formatdoc, indoc};
|
use indoc::{formatdoc, indoc};
|
||||||
use reqwest::{Client, Url};
|
use reqwest::{Client, Url};
|
||||||
@@ -710,6 +711,7 @@ impl ComputerControllerServer {
|
|||||||
.arg(&command)
|
.arg(&command)
|
||||||
.env("GOOSE_TERMINAL", "1")
|
.env("GOOSE_TERMINAL", "1")
|
||||||
.env("AGENT", "goose")
|
.env("AGENT", "goose")
|
||||||
|
.set_no_window()
|
||||||
.output()
|
.output()
|
||||||
.await
|
.await
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
@@ -725,6 +727,7 @@ impl ComputerControllerServer {
|
|||||||
.arg(&command)
|
.arg(&command)
|
||||||
.env("GOOSE_TERMINAL", "1")
|
.env("GOOSE_TERMINAL", "1")
|
||||||
.env("AGENT", "goose")
|
.env("AGENT", "goose")
|
||||||
|
.set_no_window()
|
||||||
.output()
|
.output()
|
||||||
.await
|
.await
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use super::SystemAutomation;
|
use super::SystemAutomation;
|
||||||
|
use crate::subprocess::SubprocessExt;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
@@ -13,6 +14,7 @@ impl SystemAutomation for WindowsAutomation {
|
|||||||
.arg(script)
|
.arg(script)
|
||||||
.env("GOOSE_TERMINAL", "1")
|
.env("GOOSE_TERMINAL", "1")
|
||||||
.env("AGENT", "goose")
|
.env("AGENT", "goose")
|
||||||
|
.set_no_window()
|
||||||
.output()?;
|
.output()?;
|
||||||
|
|
||||||
Ok(String::from_utf8_lossy(&output.stdout).into_owned())
|
Ok(String::from_utf8_lossy(&output.stdout).into_owned())
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use crate::subprocess::SubprocessExt;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
@@ -81,12 +82,14 @@ async fn get_windows_path_async(shell: &str) -> Result<String> {
|
|||||||
"pwsh" | "powershell" => {
|
"pwsh" | "powershell" => {
|
||||||
Command::new(shell)
|
Command::new(shell)
|
||||||
.args(["-NoLogo", "-Command", "$env:PATH"])
|
.args(["-NoLogo", "-Command", "$env:PATH"])
|
||||||
|
.set_no_window()
|
||||||
.output()
|
.output()
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
Command::new(shell)
|
Command::new(shell)
|
||||||
.args(["/c", "echo %PATH%"])
|
.args(["/c", "echo %PATH%"])
|
||||||
|
.set_no_window()
|
||||||
.output()
|
.output()
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use crate::subprocess::SubprocessExt;
|
||||||
use std::{env, ffi::OsString, process::Stdio};
|
use std::{env, ffi::OsString, process::Stdio};
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
@@ -111,6 +112,7 @@ pub fn configure_shell_command(
|
|||||||
working_dir: Option<&std::path::Path>,
|
working_dir: Option<&std::path::Path>,
|
||||||
) -> tokio::process::Command {
|
) -> tokio::process::Command {
|
||||||
let mut command_builder = tokio::process::Command::new(&shell_config.executable);
|
let mut command_builder = tokio::process::Command::new(&shell_config.executable);
|
||||||
|
command_builder.set_no_window();
|
||||||
|
|
||||||
if let Some(dir) = working_dir {
|
if let Some(dir) = working_dir {
|
||||||
command_builder.current_dir(dir);
|
command_builder.current_dir(dir);
|
||||||
@@ -177,6 +179,7 @@ pub async fn kill_process_group(
|
|||||||
// Use taskkill to kill the process tree on Windows
|
// Use taskkill to kill the process tree on Windows
|
||||||
let _kill_result = tokio::process::Command::new("taskkill")
|
let _kill_result = tokio::process::Command::new("taskkill")
|
||||||
.args(&["/F", "/T", "/PID", &pid.to_string()])
|
.args(&["/F", "/T", "/PID", &pid.to_string()])
|
||||||
|
.set_no_window()
|
||||||
.output()
|
.output()
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ pub mod computercontroller;
|
|||||||
pub mod developer;
|
pub mod developer;
|
||||||
pub mod mcp_server_runner;
|
pub mod mcp_server_runner;
|
||||||
mod memory;
|
mod memory;
|
||||||
|
pub mod subprocess;
|
||||||
pub mod tutorial;
|
pub mod tutorial;
|
||||||
|
|
||||||
pub use autovisualiser::AutoVisualiserRouter;
|
pub use autovisualiser::AutoVisualiserRouter;
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
use tokio::process::Command;
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
const CREATE_NO_WINDOW_FLAG: u32 = 0x08000000;
|
||||||
|
|
||||||
|
pub trait SubprocessExt {
|
||||||
|
fn set_no_window(&mut self) -> &mut Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SubprocessExt for Command {
|
||||||
|
fn set_no_window(&mut self) -> &mut Self {
|
||||||
|
#[cfg(windows)]
|
||||||
|
{
|
||||||
|
use std::os::windows::process::CommandExt;
|
||||||
|
self.creation_flags(CREATE_NO_WINDOW_FLAG);
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SubprocessExt for std::process::Command {
|
||||||
|
fn set_no_window(&mut self) -> &mut Self {
|
||||||
|
#[cfg(windows)]
|
||||||
|
{
|
||||||
|
use std::os::windows::process::CommandExt;
|
||||||
|
self.creation_flags(CREATE_NO_WINDOW_FLAG);
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,6 +6,8 @@ use tokio::process::Command;
|
|||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
use tracing::{debug, info, warn};
|
use tracing::{debug, info, warn};
|
||||||
|
|
||||||
|
use crate::subprocess::SubprocessExt;
|
||||||
|
|
||||||
use crate::agents::types::SessionConfig;
|
use crate::agents::types::SessionConfig;
|
||||||
use crate::agents::types::{
|
use crate::agents::types::{
|
||||||
RetryConfig, SuccessCheck, DEFAULT_ON_FAILURE_TIMEOUT_SECONDS, DEFAULT_RETRY_TIMEOUT_SECONDS,
|
RetryConfig, SuccessCheck, DEFAULT_ON_FAILURE_TIMEOUT_SECONDS, DEFAULT_RETRY_TIMEOUT_SECONDS,
|
||||||
@@ -243,6 +245,8 @@ pub async fn execute_shell_command(
|
|||||||
cmd
|
cmd
|
||||||
};
|
};
|
||||||
|
|
||||||
|
cmd.set_no_window();
|
||||||
|
|
||||||
let output = cmd
|
let output = cmd
|
||||||
.stdout(Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.stderr(Stdio::piped())
|
.stderr(Stdio::piped())
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ use crate::config::paths::Paths;
|
|||||||
use crate::config::{get_enabled_extensions, Config};
|
use crate::config::{get_enabled_extensions, Config};
|
||||||
use crate::session::session_manager::CURRENT_SCHEMA_VERSION;
|
use crate::session::session_manager::CURRENT_SCHEMA_VERSION;
|
||||||
use crate::session::SessionManager;
|
use crate::session::SessionManager;
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
use crate::subprocess::SubprocessExt;
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@@ -141,6 +143,7 @@ fn get_platform_version() -> Option<String> {
|
|||||||
{
|
{
|
||||||
std::process::Command::new("cmd")
|
std::process::Command::new("cmd")
|
||||||
.args(["/C", "ver"])
|
.args(["/C", "ver"])
|
||||||
|
.set_no_window()
|
||||||
.output()
|
.output()
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|o| String::from_utf8(o.stdout).ok())
|
.and_then(|o| String::from_utf8(o.stdout).ok())
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use crate::subprocess::SubprocessExt;
|
||||||
use chrono;
|
use chrono;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
@@ -134,6 +135,7 @@ impl AzureAuth {
|
|||||||
"--resource",
|
"--resource",
|
||||||
"https://cognitiveservices.azure.com",
|
"https://cognitiveservices.azure.com",
|
||||||
])
|
])
|
||||||
|
.set_no_window()
|
||||||
.output()
|
.output()
|
||||||
.await
|
.await
|
||||||
.map_err(|e| AuthError::TokenExchange(format!("Failed to execute Azure CLI: {}", e)))?;
|
.map_err(|e| AuthError::TokenExchange(format!("Failed to execute Azure CLI: {}", e)))?;
|
||||||
|
|||||||
@@ -3,13 +3,37 @@ use tokio::process::Command;
|
|||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
const CREATE_NO_WINDOW_FLAG: u32 = 0x08000000;
|
const CREATE_NO_WINDOW_FLAG: u32 = 0x08000000;
|
||||||
|
|
||||||
|
pub trait SubprocessExt {
|
||||||
|
fn set_no_window(&mut self) -> &mut Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SubprocessExt for Command {
|
||||||
|
fn set_no_window(&mut self) -> &mut Self {
|
||||||
|
#[cfg(windows)]
|
||||||
|
{
|
||||||
|
use std::os::windows::process::CommandExt;
|
||||||
|
self.creation_flags(CREATE_NO_WINDOW_FLAG);
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SubprocessExt for std::process::Command {
|
||||||
|
fn set_no_window(&mut self) -> &mut Self {
|
||||||
|
#[cfg(windows)]
|
||||||
|
{
|
||||||
|
use std::os::windows::process::CommandExt;
|
||||||
|
self.creation_flags(CREATE_NO_WINDOW_FLAG);
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
pub fn configure_subprocess(command: &mut Command) {
|
pub fn configure_subprocess(command: &mut Command) {
|
||||||
// Isolate subprocess into its own process group so it does not receive
|
// Isolate subprocess into its own process group so it does not receive
|
||||||
// SIGINT when the user presses Ctrl+C in the terminal.
|
// SIGINT when the user presses Ctrl+C in the terminal.
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
command.process_group(0);
|
command.process_group(0);
|
||||||
|
command.set_no_window();
|
||||||
#[cfg(windows)]
|
|
||||||
command.creation_flags(CREATE_NO_WINDOW_FLAG);
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user