Move the bash-task on-disk schema (TaskFile + TaskStatus) into hive-sh4re, the shared wire-types crate, and re-export them from hive-bash-mcp::protocol so existing in-crate imports keep compiling. This gives hive-ag3nt's agent web UI a canonical type to deserialize when reading the bash-tasks dir for a running-tasks panel, instead of a parallel struct that would silently drift from the daemon's persisted format. Both crates already depend on hive-sh4re, so no new dependency edges.
102 lines
4.1 KiB
Rust
102 lines
4.1 KiB
Rust
//! Wire types for the unix socket protocol between `hive-bash-daemon`
|
|
//! and `hive-bash-mcp`. One JSON request line in, one JSON response line
|
|
//! out per connection. Connections are short-lived (per tool call).
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Task state (shared between runner and protocol)
|
|
// ---------------------------------------------------------------------------
|
|
|
|
// `TaskFile` + `TaskStatus` are the bash-task on-disk schema. They live in
|
|
// `hive-sh4re` (the shared wire-types crate) so the agent web UI in
|
|
// `hive-ag3nt` can deserialize the same canonical type when reading the
|
|
// tasks dir for its running-tasks panel — no parallel copy to drift. Both
|
|
// are re-exported here so existing `crate::protocol::{TaskFile, TaskStatus}`
|
|
// imports across this crate keep compiling unchanged.
|
|
pub use hive_sh4re::{TaskFile, TaskStatus};
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Request / response
|
|
// ---------------------------------------------------------------------------
|
|
|
|
/// Requests the MCP bridge sends to the daemon.
|
|
#[derive(Debug, Serialize, Deserialize)]
|
|
#[serde(tag = "kind", rename_all = "snake_case")]
|
|
pub enum DaemonRequest {
|
|
/// Liveness probe — fast round-trip that doesn't touch any subprocess.
|
|
Ping,
|
|
|
|
/// Submit a new bash task. Returns the task ID on success.
|
|
/// `wait_seconds`: optional inline poll (capped at 30s); when the
|
|
/// task finishes within the window the response carries the full
|
|
/// status payload. When it doesn't, the response carries just the
|
|
/// task ID so the caller can check back with `BashStatus`.
|
|
BashRun {
|
|
cmd: String,
|
|
#[serde(default)]
|
|
timeout_secs: Option<u64>,
|
|
/// Inline wait cap: 30s. Pass `None` or `0` to get the
|
|
/// task-started-id response immediately.
|
|
#[serde(default)]
|
|
wait_seconds: Option<u64>,
|
|
/// Optional caller-chosen task name, used as the task id (so it
|
|
/// flows into the wake `from`, status lookups, and the loose-ends
|
|
/// summary). Must be filesystem-safe. Reusable once any prior task
|
|
/// of the same name has finished; rejected while one is still
|
|
/// running. `None` falls back to the auto-generated id.
|
|
#[serde(default)]
|
|
name: Option<String>,
|
|
},
|
|
|
|
/// Query the current status of a task. Returns the full `TaskFile`
|
|
/// (formatted as text by the bridge). `wait_seconds`: optional
|
|
/// inline poll (capped at 30s) — daemon returns as soon as the
|
|
/// task reaches a terminal state or the window expires.
|
|
BashStatus {
|
|
id: String,
|
|
#[serde(default)]
|
|
wait_seconds: Option<u64>,
|
|
},
|
|
|
|
/// Return all tasks currently in `Pending` or `Running` state.
|
|
/// Used by the harness `get_loose_ends` to surface active
|
|
/// background work.
|
|
ActiveTasks,
|
|
|
|
/// Kill a running (or still-pending) task. `force = false` sends
|
|
/// `SIGINT` to the task's process group (graceful — the process can
|
|
/// clean up); `force = true` sends `SIGKILL` (immediate). Signalling
|
|
/// the whole process group reaps `sh -c` plus any children it spawned,
|
|
/// so a runaway grandchild (e.g. `cargo`/`nix`) is actually stopped.
|
|
BashKill {
|
|
id: String,
|
|
#[serde(default)]
|
|
force: bool,
|
|
},
|
|
}
|
|
|
|
/// Response shape from the daemon. `Ok` carries a JSON payload; `Error`
|
|
/// carries a human-readable message.
|
|
#[derive(Debug, Serialize, Deserialize)]
|
|
#[serde(tag = "kind", rename_all = "snake_case")]
|
|
pub enum DaemonResponse {
|
|
Ok { payload: serde_json::Value },
|
|
Error { message: String },
|
|
}
|
|
|
|
impl DaemonResponse {
|
|
/// Build an Ok response from any serialisable value.
|
|
pub fn ok<T: Serialize>(payload: &T) -> Self {
|
|
let payload = serde_json::to_value(payload)
|
|
.unwrap_or_else(|e| serde_json::json!({ "serialise_error": e.to_string() }));
|
|
Self::Ok { payload }
|
|
}
|
|
|
|
/// Build an Error response from any `Display` value.
|
|
pub fn error(msg: impl std::fmt::Display) -> Self {
|
|
Self::Error {
|
|
message: msg.to_string(),
|
|
}
|
|
}
|
|
}
|