Enhance tool documentation and add new features
- Added module-level documentation for memory tools (`remember`, `recall`, `forget`) to clarify their purpose. - Improved documentation in `recall.rs` and `remember.rs` to describe the functionality and flow of memory entry operations. - Updated `mod.rs` to include descriptions for the tool trait and execution context. - Enhanced `plan.rs` with detailed comments on plan-mode signaling tools. - Documented text search tools in `search.rs` to explain their functionality. - Improved sequential-thinking tool documentation in `seqthink.rs`. - Added safety filter documentation in `shell_filter` for credential and git operations. - Enhanced utility tools documentation, including `cd`, `dir_cache_update`, and `todowrite`. - Improved rendering documentation in view modules (`chat`, `markdown`, `status`, `workflow`) to clarify rendering flows and purposes.
This commit is contained in:
@@ -1,14 +1,41 @@
|
||||
//! Global registry of running background bash jobs, and control operations
|
||||
//! (output polling, kill) exposed to the rest of the app.
|
||||
//!
|
||||
//! Flow: a process-wide `Mutex<HashMap<String, BashJob>>` (lazily built via
|
||||
//! `OnceLock`) holds every job spawned via `bgbash::job::spawn_bash_job` →
|
||||
//! `bash_output` drains new lines for a given job id → `bash_kill` removes
|
||||
//! a job from the map and signals its child process.
|
||||
//!
|
||||
//! Why: a single static map (rather than storing jobs in `AppStateRest`)
|
||||
//! lets background jobs outlive the borrow of any particular state mutation
|
||||
//! and be looked up by id from tool calls issued at arbitrary points.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Mutex;
|
||||
use std::sync::OnceLock;
|
||||
|
||||
use super::job::BashJob;
|
||||
|
||||
/// Lazily-initialised, process-wide registry of background bash jobs keyed
|
||||
/// by job id.
|
||||
///
|
||||
/// Return: a reference to the static `Mutex<HashMap<...>>`, created on
|
||||
/// first access.
|
||||
pub(crate) fn bash_jobs_map() -> &'static Mutex<HashMap<String, BashJob>> {
|
||||
static JOBS: OnceLock<Mutex<HashMap<String, BashJob>>> = OnceLock::new();
|
||||
JOBS.get_or_init(|| Mutex::new(HashMap::new()))
|
||||
}
|
||||
|
||||
/// Drain any newly available output lines from a background bash job.
|
||||
///
|
||||
/// Flow: look up the job by id → repeatedly call `try_read_line()` until it
|
||||
/// returns `None` → collect into a Vec.
|
||||
///
|
||||
/// Why: non-blocking; a job that hasn't produced new output yields no lines
|
||||
/// rather than blocking the caller.
|
||||
///
|
||||
/// Return: `Some(lines)` if at least one new line was read, `None` if the
|
||||
/// job doesn't exist, the lock is poisoned, or there was nothing new to read.
|
||||
pub fn bash_output(id: &str) -> Option<Vec<String>> {
|
||||
let mut map = bash_jobs_map().lock().ok()?;
|
||||
let job = map.get_mut(id)?;
|
||||
@@ -19,6 +46,16 @@ pub fn bash_output(id: &str) -> Option<Vec<String>> {
|
||||
if lines.is_empty() { None } else { Some(lines) }
|
||||
}
|
||||
|
||||
/// Terminate a running background bash job and remove it from the registry.
|
||||
///
|
||||
/// Flow: remove the job from the map → if it has a valid child PID, send
|
||||
/// `SIGTERM` to it (unix only) → return.
|
||||
///
|
||||
/// Why: removing from the map first means a concurrent lookup can no longer
|
||||
/// see the job even if the signal delivery is delayed.
|
||||
///
|
||||
/// Return: `Ok(())` on success, `Err` if the lock is poisoned or no job
|
||||
/// with that id exists.
|
||||
pub fn bash_kill(id: &str) -> anyhow::Result<()> {
|
||||
let mut map = bash_jobs_map().lock().map_err(|e| anyhow::anyhow!("lock error: {}", e))?;
|
||||
let job = map.remove(id);
|
||||
|
||||
@@ -1,8 +1,24 @@
|
||||
//! Background bash job spawning and non-blocking output polling.
|
||||
//!
|
||||
//! Flow: `spawn_bash_job` forks a detached OS thread that execs the command
|
||||
//! via `sh -c`, streams stdout lines back over an `mpsc` channel, and sends
|
||||
//! an `__exit:<code>` sentinel when the child terminates → callers poll the
|
||||
//! returned `BashJob` with `try_read_line()` to drain output without
|
||||
//! blocking the TUI event loop.
|
||||
//!
|
||||
//! Why: running bash commands on a detached thread with a channel (rather
|
||||
//! than synchronously) lets the TUI stay responsive while long-running
|
||||
//! shell commands execute in the background.
|
||||
|
||||
use std::process::{Command, Stdio};
|
||||
use std::sync::mpsc;
|
||||
use std::thread;
|
||||
use std::io::BufRead;
|
||||
|
||||
/// Handle to a bash command running in a detached background thread.
|
||||
///
|
||||
/// Why: output is streamed over an mpsc channel rather than buffered
|
||||
/// synchronously, so the TUI can poll for new lines without blocking.
|
||||
pub struct BashJob {
|
||||
pub id: String,
|
||||
pub child_pid: u32,
|
||||
@@ -10,6 +26,21 @@ pub struct BashJob {
|
||||
pub exit_code: Option<i32>,
|
||||
}
|
||||
|
||||
/// Spawn a shell command in a background thread and return a handle to it.
|
||||
///
|
||||
/// Flow: spawn a thread → thread execs `sh -c <command>` with piped
|
||||
/// stdout/stderr → thread sends the child PID back over a channel →
|
||||
/// thread streams stdout lines to `output_tx` → on exit, sends an
|
||||
/// `__exit:<code>` sentinel line.
|
||||
///
|
||||
/// Why: the PID is sent back before the command finishes so `bash_kill` can
|
||||
/// terminate it mid-run; sentinel-prefixed strings (`__error:`, `__exit:`)
|
||||
/// let `try_read_line` distinguish control messages from real output on the
|
||||
/// same channel without a separate enum.
|
||||
///
|
||||
/// Return: a `BashJob` with a freshly generated id, the child PID (0 if the
|
||||
/// spawn failed before the PID was sent), and the receiving end of the
|
||||
/// output channel.
|
||||
pub fn spawn_bash_job(command: String) -> BashJob {
|
||||
let id = uuid::Uuid::new_v4().to_string();
|
||||
let (output_tx, output_rx) = mpsc::channel::<String>();
|
||||
@@ -57,6 +88,15 @@ pub fn spawn_bash_job(command: String) -> BashJob {
|
||||
}
|
||||
|
||||
impl BashJob {
|
||||
/// Non-blocking poll for the next output line from the job's channel.
|
||||
///
|
||||
/// Flow: try_recv the channel → if it's an `__exit:<code>` sentinel,
|
||||
/// record `exit_code` and return `None` instead of surfacing it as
|
||||
/// output → otherwise return the line.
|
||||
///
|
||||
/// Return: `Some(line)` for real output, `None` if there's nothing
|
||||
/// available yet or the job just finished (exit code recorded as a
|
||||
/// side effect).
|
||||
pub fn try_read_line(&mut self) -> Option<String> {
|
||||
match self.output_rx.try_recv() {
|
||||
Ok(line) => {
|
||||
|
||||
@@ -1,2 +1,5 @@
|
||||
//! Background bash: run shell commands off the main thread, poll their
|
||||
//! output non-blockingly, and terminate them on demand.
|
||||
|
||||
pub mod control;
|
||||
pub mod job;
|
||||
|
||||
Reference in New Issue
Block a user