feat(tui): add usage overlay and sidebar for displaying usage statistics and tasks
feat(tui): implement status bar with connection and turn state indicators feat(tui): create workflow panel for agent status and progress visualization feat(web): introduce web frontend interface with static file serving feat(ws): add WebSocket interface for real-time communication and session management
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
//! Background bash job — spawns a `bash -c` subprocess and tracks its life.
|
||||
|
||||
use std::process::{Child, Command, Stdio};
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
/// A handle to a spawned background bash job.
|
||||
pub struct BashJob {
|
||||
pub id: String,
|
||||
pub command: String,
|
||||
pub process: Mutex<Option<Child>>,
|
||||
pub cancelled: AtomicBool,
|
||||
}
|
||||
|
||||
/// Spawn a background bash job and return a handle.
|
||||
///
|
||||
/// The job runs until completion or until `cancel()` is called.
|
||||
pub fn spawn_bash_job(cmd: String) -> Arc<BashJob> {
|
||||
let child = Command::new("bash")
|
||||
.arg("-c")
|
||||
.arg(&cmd)
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
.spawn()
|
||||
.ok();
|
||||
|
||||
let job = Arc::new(BashJob {
|
||||
id: uuid::Uuid::new_v4().to_string(),
|
||||
command: cmd,
|
||||
process: Mutex::new(child),
|
||||
cancelled: AtomicBool::new(false),
|
||||
});
|
||||
|
||||
// Spawn a monitor thread (in production this would use an async task)
|
||||
let job_clone = Arc::clone(&job);
|
||||
std::thread::spawn(move || {
|
||||
let mut guard = job_clone.process.lock().unwrap();
|
||||
if let Some(ref mut child) = *guard {
|
||||
let _ = child.wait();
|
||||
}
|
||||
});
|
||||
|
||||
job
|
||||
}
|
||||
|
||||
impl BashJob {
|
||||
pub fn cancel(&self) {
|
||||
self.cancelled.store(true, Ordering::SeqCst);
|
||||
if let Ok(mut guard) = self.process.lock() {
|
||||
if let Some(ref mut child) = *guard {
|
||||
let _ = child.kill();
|
||||
let _ = child.wait();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_running(&self) -> bool {
|
||||
if self.cancelled.load(Ordering::SeqCst) {
|
||||
return false;
|
||||
}
|
||||
let Ok(mut guard) = self.process.lock() else {
|
||||
return false;
|
||||
};
|
||||
guard.as_mut().map_or(false, |c| {
|
||||
matches!(c.try_wait(), Ok(None))
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user