hive-bash-mcp: add kill tool to stop a running or pending bash task
This commit is contained in:
parent
e1b7f7cbec
commit
b16629801b
4 changed files with 291 additions and 60 deletions
|
|
@ -145,6 +145,26 @@ fn render_bash_status(id: &str, resp: Result<DaemonResponse>, waited: bool) -> S
|
|||
}
|
||||
}
|
||||
|
||||
/// Turn a `DaemonResponse` from a `BashKill` call into the string claude sees.
|
||||
fn render_bash_kill(resp: Result<DaemonResponse>) -> String {
|
||||
match resp {
|
||||
Ok(DaemonResponse::Ok { payload }) => {
|
||||
let id = payload["id"].as_str().unwrap_or("unknown");
|
||||
if payload["was_running"].as_bool().unwrap_or(false) {
|
||||
let sig = payload["signal"].as_str().unwrap_or("SIGINT");
|
||||
format!(
|
||||
"task `{id}`: {sig} sent to its process group; it transitions to `killed` \
|
||||
once the process exits and the usual completion wake fires."
|
||||
)
|
||||
} else {
|
||||
format!("task `{id}` was pending — cancelled before it started.")
|
||||
}
|
||||
}
|
||||
Ok(DaemonResponse::Error { message }) => format!("kill error: {message}"),
|
||||
Err(e) => format!("bash bridge error: {e:#}"),
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// MCP server
|
||||
// ---------------------------------------------------------------------------
|
||||
|
|
@ -196,6 +216,18 @@ struct BashStatusArgs {
|
|||
wait_seconds: Option<u64>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, JsonSchema)]
|
||||
struct BashKillArgs {
|
||||
/// Task ID (from `run`) to kill.
|
||||
id: String,
|
||||
/// `false` (default) sends SIGINT to the task's process group — graceful,
|
||||
/// the process can clean up. `true` sends SIGKILL — immediate. Either way
|
||||
/// the whole process group is signalled, so children of the shell (e.g. a
|
||||
/// `cargo`/`nix` invocation) are stopped too, not just the shell itself.
|
||||
#[serde(default)]
|
||||
force: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct BashMcp;
|
||||
|
||||
|
|
@ -238,8 +270,8 @@ impl BashMcp {
|
|||
|
||||
#[tool(
|
||||
description = "Check the status of a background bash task by its ID (from `run`). \
|
||||
Returns the current status (pending/running/done/timed_out/interrupted), exit code \
|
||||
if finished, and a tail of stdout/stderr. Full output lives in \
|
||||
Returns the current status (pending/running/done/timed_out/interrupted/killed), exit \
|
||||
code if finished, and a tail of stdout/stderr. Full output lives in \
|
||||
`harness/bash-tasks/<id>.out` / `.err`. \
|
||||
Pass `wait_seconds` (capped at 30) to wait inline for the task to finish: when the \
|
||||
task finishes within the window the full status is returned immediately. Useful to \
|
||||
|
|
@ -254,6 +286,23 @@ impl BashMcp {
|
|||
};
|
||||
render_bash_status(&id, round_trip(req).await, waited)
|
||||
}
|
||||
|
||||
#[tool(
|
||||
description = "Kill a background bash task you started (by its ID from `run`). \
|
||||
`force: false` (default) sends SIGINT — graceful, lets the process clean up; \
|
||||
`force: true` sends SIGKILL — immediate. Either way the task's whole process \
|
||||
group is signalled, so a runaway child (cargo/nix/etc.) is stopped too, not just \
|
||||
the shell. A still-pending task is cancelled before it starts. The task ends as \
|
||||
`killed` and fires the usual completion wake. SIGINT relies on the process \
|
||||
honouring it — pass `force` if it won't stop."
|
||||
)]
|
||||
async fn kill(&self, Parameters(args): Parameters<BashKillArgs>) -> String {
|
||||
let req = DaemonRequest::BashKill {
|
||||
id: args.id,
|
||||
force: args.force,
|
||||
};
|
||||
render_bash_kill(round_trip(req).await)
|
||||
}
|
||||
}
|
||||
|
||||
#[tool_handler]
|
||||
|
|
|
|||
Loading…
Reference in a new issue