Skip to main content

recursive/tui/
bash.rs

1use std::path::PathBuf;
2use std::sync::atomic::{AtomicU64, Ordering};
3use std::sync::Arc;
4use std::time::Duration;
5
6use crate::tools::{LocalTransport, RunShell, ToolTransport};
7use crate::ToolRegistry;
8use serde_json::json;
9
10use crate::tui::events::UiEvent;
11
12pub fn build_bash_registry(root: &std::path::Path) -> ToolRegistry {
13    let transport: Arc<dyn ToolTransport> = Arc::new(LocalTransport);
14    ToolRegistry::new(transport).register(Arc::new(
15        RunShell::new(root).with_timeout(Duration::from_secs(300)),
16    ))
17}
18
19pub fn resolve_workspace_root() -> PathBuf {
20    std::env::var("RECURSIVE_WORKSPACE")
21        .map(PathBuf::from)
22        .ok()
23        .or_else(|| std::env::current_dir().ok())
24        .unwrap_or_else(|| PathBuf::from("."))
25}
26
27pub async fn run_bash_command(
28    registry: &ToolRegistry,
29    seq: &AtomicU64,
30    cmd: String,
31    event_tx: &tokio::sync::mpsc::UnboundedSender<UiEvent>,
32) {
33    let n = seq.fetch_add(1, Ordering::Relaxed);
34    let id = format!("ui-bash-{n}");
35    let arguments = json!({ "command": cmd });
36    let arguments_str = arguments.to_string();
37
38    let _ = event_tx.send(UiEvent::ToolCall {
39        id: id.clone(),
40        name: "run_shell".into(),
41        arguments: arguments_str,
42    });
43
44    let (output, success) = match registry.invoke("run_shell", arguments).await {
45        Ok(out) => (out, true),
46        Err(e) => (format!("ERROR: {e}"), false),
47    };
48
49    let _ = event_tx.send(UiEvent::ToolResult {
50        id,
51        name: "run_shell".into(),
52        output,
53        success,
54    });
55}