feat(#2659): serve hive-bash-mcp over persistent streamable-http, drop stdio bridge

This commit is contained in:
damocles 2026-07-23 17:34:02 +02:00 committed by mara
commit c4fcf7fbf1
26 changed files with 376 additions and 574 deletions

View file

@ -63,9 +63,9 @@ struct RunningHandle {
}
/// Global registry of running tasks (id → handle). Populated by `run_task`
/// for the duration of execution and read by [`kill_task`] from the socket
/// dispatch path — a separate async context from the runner loop, so a
/// shared global (rather than the loop-local `claimed` set) is needed.
/// for the duration of execution and read by [`kill_task`] from the MCP
/// tool-call handler — a separate async context from the runner loop, so
/// a shared global (rather than the loop-local `claimed` set) is needed.
fn running() -> &'static Mutex<HashMap<String, RunningHandle>> {
static RUNNING: OnceLock<Mutex<HashMap<String, RunningHandle>>> = OnceLock::new();
RUNNING.get_or_init(|| Mutex::new(HashMap::new()))
@ -308,29 +308,6 @@ pub fn submit_task(cmd: String, timeout_secs: Option<u64>, name: Option<String>)
Ok(id)
}
/// Return all tasks currently in `Pending` or `Running` state.
#[must_use]
pub fn active_tasks() -> Vec<TaskFile> {
let Ok(rd) = std::fs::read_dir(paths::tasks_dir()) else {
return Vec::new();
};
let mut out = Vec::new();
for entry in rd.flatten() {
let path = entry.path();
if path.extension().and_then(|e| e.to_str()) != Some("json") {
continue;
}
let Some(id) = path.file_stem().and_then(|s| s.to_str()).map(str::to_owned) else {
continue;
};
let Some(task) = read_task(&id) else { continue };
if matches!(task.status, TaskStatus::Pending | TaskStatus::Running) {
out.push(task);
}
}
out
}
/// Inline wait: poll `read_task(id)` until terminal state or deadline.
/// Returns the final task on success, or `None` if it never completed.
///
@ -554,7 +531,7 @@ async fn run_task(mut task: TaskFile, socket: &Path) {
let err_path = paths::task_err(&id);
// Register a kill handle for the duration of execution so `kill_task`
// (called from the socket dispatch path) can signal this task.
// (called from the MCP tool-call handler) can signal this task.
let cancel = Arc::new(Notify::new());
let force = Arc::new(AtomicBool::new(false));
running().lock().unwrap().insert(