Backport: Agentic Shell Command Execution (v1.0.0 → v1.0.8) #66
38
scripts/download-kubectl.sh
Executable file
38
scripts/download-kubectl.sh
Executable file
@ -0,0 +1,38 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
KUBECTL_VERSION="v1.30.0"
|
||||
BINARIES_DIR="src-tauri/binaries"
|
||||
|
||||
echo "Downloading kubectl binaries version ${KUBECTL_VERSION}..."
|
||||
|
||||
mkdir -p "$BINARIES_DIR"
|
||||
|
||||
# Download for all platforms
|
||||
# Tauri uses this structure: binaries/kubectl-{target-triple} or kubectl-{target-triple}.exe
|
||||
echo "Downloading kubectl for Linux x86_64..."
|
||||
curl -L -o "$BINARIES_DIR/kubectl-x86_64-unknown-linux-gnu" \
|
||||
"https://dl.k8s.io/release/$KUBECTL_VERSION/bin/linux/amd64/kubectl"
|
||||
|
||||
echo "Downloading kubectl for Linux aarch64..."
|
||||
curl -L -o "$BINARIES_DIR/kubectl-aarch64-unknown-linux-gnu" \
|
||||
"https://dl.k8s.io/release/$KUBECTL_VERSION/bin/linux/arm64/kubectl"
|
||||
|
||||
echo "Downloading kubectl for macOS x86_64..."
|
||||
curl -L -o "$BINARIES_DIR/kubectl-x86_64-apple-darwin" \
|
||||
"https://dl.k8s.io/release/$KUBECTL_VERSION/bin/darwin/amd64/kubectl"
|
||||
|
||||
echo "Downloading kubectl for macOS aarch64..."
|
||||
curl -L -o "$BINARIES_DIR/kubectl-aarch64-apple-darwin" \
|
||||
"https://dl.k8s.io/release/$KUBECTL_VERSION/bin/darwin/arm64/kubectl"
|
||||
|
||||
echo "Downloading kubectl for Windows x86_64..."
|
||||
curl -L -o "$BINARIES_DIR/kubectl-x86_64-pc-windows-gnu.exe" \
|
||||
"https://dl.k8s.io/release/$KUBECTL_VERSION/bin/windows/amd64/kubectl.exe"
|
||||
|
||||
# Make binaries executable (not needed for Windows .exe)
|
||||
chmod +x "$BINARIES_DIR"/kubectl-*-linux-* "$BINARIES_DIR"/kubectl-*-darwin
|
||||
|
||||
echo "kubectl binaries downloaded successfully to $BINARIES_DIR"
|
||||
echo "Total size:"
|
||||
du -sh "$BINARIES_DIR"
|
||||
3
src-tauri/Cargo.lock
generated
3
src-tauri/Cargo.lock
generated
@ -6370,6 +6370,7 @@ dependencies = [
|
||||
"flate2",
|
||||
"futures",
|
||||
"hex",
|
||||
"http 1.4.0",
|
||||
"infer 0.15.0",
|
||||
"lazy_static",
|
||||
"lopdf",
|
||||
@ -6391,7 +6392,7 @@ dependencies = [
|
||||
"tauri-plugin-http",
|
||||
"tauri-plugin-shell",
|
||||
"tauri-plugin-stronghold",
|
||||
"thiserror 1.0.69",
|
||||
"thiserror 2.0.18",
|
||||
"tokio",
|
||||
"tokio-test",
|
||||
"tracing",
|
||||
|
||||
@ -30,7 +30,7 @@ docx-rs = "0.4"
|
||||
sha2 = { version = "0.10", features = ["std"] }
|
||||
hex = "0.4"
|
||||
anyhow = "1"
|
||||
thiserror = "1"
|
||||
thiserror = "2"
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
@ -53,6 +53,7 @@ rmcp = { version = "1.7.0", features = [
|
||||
"transport-child-process",
|
||||
"transport-streamable-http-client-reqwest",
|
||||
] }
|
||||
http = "1.4"
|
||||
flate2 = { version = "1", features = ["rust_backend"] }
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
@ -333,6 +333,7 @@ pub async fn initiate_oauth(
|
||||
app_data_dir,
|
||||
integration_webviews,
|
||||
mcp_connections,
|
||||
pending_approvals: Arc::new(tokio::sync::Mutex::new(std::collections::HashMap::new())),
|
||||
};
|
||||
while let Some(callback) = callback_rx.recv().await {
|
||||
tracing::info!("Received OAuth callback for state: {}", callback.state);
|
||||
|
||||
@ -95,6 +95,189 @@ pub fn get_install_instructions(platform: &str) -> InstallGuide {
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper to find Ollama binary in common locations
|
||||
fn find_ollama_binary() -> Option<std::path::PathBuf> {
|
||||
let common_paths = [
|
||||
"/usr/local/bin/ollama",
|
||||
"/opt/homebrew/bin/ollama",
|
||||
"/usr/bin/ollama",
|
||||
"/home/linuxbrew/.linuxbrew/bin/ollama",
|
||||
];
|
||||
|
||||
for path in &common_paths {
|
||||
let p = std::path::Path::new(path);
|
||||
if p.exists() {
|
||||
return Some(p.to_path_buf());
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to which/where command
|
||||
let which_cmd = if cfg!(target_os = "windows") {
|
||||
"where"
|
||||
} else {
|
||||
"which"
|
||||
};
|
||||
|
||||
std::process::Command::new(which_cmd)
|
||||
.arg("ollama")
|
||||
.output()
|
||||
.ok()
|
||||
.and_then(|output| {
|
||||
if output.status.success() {
|
||||
String::from_utf8(output.stdout)
|
||||
.ok()
|
||||
.map(|s| std::path::PathBuf::from(s.trim()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Attempt to start Ollama service if installed but not running
|
||||
pub async fn start_ollama_service() -> anyhow::Result<bool> {
|
||||
let status = check_ollama().await?;
|
||||
|
||||
// If already running, nothing to do
|
||||
if status.running {
|
||||
tracing::info!("Ollama is already running");
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
// If not installed, can't start it
|
||||
if !status.installed {
|
||||
tracing::warn!("Ollama is not installed, cannot auto-start");
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
tracing::info!("Ollama is installed but not running, attempting to start...");
|
||||
|
||||
// Platform-specific start logic
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
// On macOS, try to launch Ollama.app which manages the service
|
||||
let ollama_app = "/Applications/Ollama.app";
|
||||
if std::path::Path::new(ollama_app).exists() {
|
||||
tracing::info!("Launching Ollama.app...");
|
||||
let result = std::process::Command::new("open").arg(ollama_app).spawn();
|
||||
|
||||
match result {
|
||||
Ok(_) => {
|
||||
// Wait a few seconds for Ollama to start
|
||||
tokio::time::sleep(tokio::time::Duration::from_secs(3)).await;
|
||||
|
||||
// Check if it's now running
|
||||
let new_status = check_ollama().await?;
|
||||
if new_status.running {
|
||||
tracing::info!("Ollama started successfully via Ollama.app");
|
||||
return Ok(true);
|
||||
} else {
|
||||
tracing::warn!("Ollama.app launched but service not responding yet");
|
||||
return Ok(false);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!("Failed to launch Ollama.app: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: try direct ollama serve with full path
|
||||
if let Some(ollama_bin) = find_ollama_binary() {
|
||||
tracing::info!(
|
||||
"Attempting to start ollama serve directly at {:?}...",
|
||||
ollama_bin
|
||||
);
|
||||
let result = std::process::Command::new(&ollama_bin)
|
||||
.arg("serve")
|
||||
.stdout(std::process::Stdio::null())
|
||||
.stderr(std::process::Stdio::null())
|
||||
.spawn();
|
||||
|
||||
match result {
|
||||
Ok(_) => {
|
||||
// Wait for service to become available
|
||||
tokio::time::sleep(tokio::time::Duration::from_secs(2)).await;
|
||||
let new_status = check_ollama().await?;
|
||||
Ok(new_status.running)
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!("Failed to start ollama serve: {}", e);
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tracing::error!("Ollama binary not found in PATH or common locations");
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
// On Linux, start ollama serve in background using full path
|
||||
if let Some(ollama_bin) = find_ollama_binary() {
|
||||
tracing::info!("Starting ollama serve at {:?}...", ollama_bin);
|
||||
let result = std::process::Command::new(&ollama_bin)
|
||||
.arg("serve")
|
||||
.stdout(std::process::Stdio::null())
|
||||
.stderr(std::process::Stdio::null())
|
||||
.spawn();
|
||||
|
||||
match result {
|
||||
Ok(_) => {
|
||||
tokio::time::sleep(tokio::time::Duration::from_secs(2)).await;
|
||||
let new_status = check_ollama().await?;
|
||||
if new_status.running {
|
||||
tracing::info!("Ollama started successfully");
|
||||
Ok(true)
|
||||
} else {
|
||||
tracing::warn!("ollama serve started but not responding yet");
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!("Failed to start ollama serve: {}", e);
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tracing::error!("Ollama binary not found");
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
// On Windows, Ollama runs as a service, check if we can start it
|
||||
tracing::info!("Attempting to start Ollama on Windows...");
|
||||
if let Some(ollama_bin) = find_ollama_binary() {
|
||||
let result = std::process::Command::new(&ollama_bin)
|
||||
.arg("serve")
|
||||
.spawn();
|
||||
|
||||
match result {
|
||||
Ok(_) => {
|
||||
tokio::time::sleep(tokio::time::Duration::from_secs(2)).await;
|
||||
let new_status = check_ollama().await?;
|
||||
Ok(new_status.running)
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!("Failed to start Ollama: {}", e);
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tracing::error!("Ollama binary not found");
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "macos", target_os = "linux", target_os = "windows")))]
|
||||
{
|
||||
tracing::warn!("Auto-start not supported on this platform");
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user