hive-bash-mcp: drop the command from the running-task todo entirely

Per mara: just show the task name, don't show any command — if an
agent doesn't name a task itself it still gets the id back in the
run tool's own result, so the todo doesn't need to repeat it. Drops
short_cmd_label (and its tests) added in the previous commit; the
summary is now just "bash task `<id>` running".
This commit is contained in:
iris 2026-08-14 02:11:52 +02:00 committed by mara
commit 90cd602d4e

View file

@ -517,34 +517,6 @@ fn poll_once(socket: &Path, claimed: &Arc<Mutex<HashSet<String>>>) {
// Task execution
// ---------------------------------------------------------------------------
/// Max characters kept from the command's first line when building the
/// "running" todo summary (see `short_cmd_label`).
const CMD_LABEL_MAX_CHARS: usize = 100;
/// Build a short, single-line label for `cmd` to use in the "running"
/// todo summary. `cmd` can be an entire multi-line script (heredocs are
/// a common agent pattern) — embedding it whole balloons the todo body
/// in every UI that renders it, so this keeps only the first non-blank
/// line, char-truncated to `CMD_LABEL_MAX_CHARS`, with a trailing `…`
/// whenever either the line itself was cut or more lines follow. The
/// full command is still on disk in the task file for `status`/`view`.
fn short_cmd_label(cmd: &str) -> String {
let mut lines = cmd.lines().map(str::trim).filter(|l| !l.is_empty());
let first = lines.next().unwrap_or("");
let more_lines = lines.next().is_some();
let char_truncated = first.chars().count() > CMD_LABEL_MAX_CHARS;
let label: String = if char_truncated {
first.chars().take(CMD_LABEL_MAX_CHARS).collect()
} else {
first.to_owned()
};
if char_truncated || more_lines {
format!("{label}")
} else {
label
}
}
async fn run_task(mut task: TaskFile, socket: &Path) {
let id = task.id.clone();
tracing::info!(id = %id, cmd = %task.cmd, "bash_runner: starting task");
@ -554,12 +526,15 @@ async fn run_task(mut task: TaskFile, socket: &Path) {
if let Err(e) = write_task(&task) {
tracing::warn!(id = %id, error = ?e, "bash_runner: write running state failed");
}
upsert_bash_todo(
socket,
&id,
format!("bash task `{id}` running: `{}`", short_cmd_label(&task.cmd)),
)
.await;
// No command text in the summary: `id` is already the human-chosen
// `name` when the caller passed one, and even the auto-generated
// hex id was already returned to the agent in the `run` tool's own
// result — the todo only needs to say which task, not repeat the
// command. An unbounded raw command (e.g. a multi-line heredoc
// script) would balloon every UI that renders todo summaries; the
// full command stays on disk in the task file for `status`/`view`
// instead.
upsert_bash_todo(socket, &id, format!("bash task `{id}` running")).await;
// Best-effort: tally the normalised command head for the /stats
// "favorite tools" view. Counted once per execution, regardless of
// exit status. Never fails the task.
@ -858,43 +833,10 @@ fn done_summary(id: &str, summary: &str, output: Option<(bool, bool)>) -> String
#[cfg(test)]
mod tests {
use super::{CMD_LABEL_MAX_CHARS, short_cmd_label, validate_task_name};
use super::validate_task_name;
use crate::test_util::with_harness_dir;
use hive_types::Ident;
#[test]
fn short_cmd_label_short_single_line_is_unchanged() {
assert_eq!(short_cmd_label("echo hi"), "echo hi");
}
#[test]
fn short_cmd_label_trims_and_skips_leading_blank_lines() {
assert_eq!(short_cmd_label("\n\n echo hi \nmore stuff"), "echo hi…");
}
#[test]
fn short_cmd_label_flags_multiline_even_when_first_line_is_short() {
// The whole point: a short first line followed by a long heredoc
// body must still read as truncated, not as the complete command.
let cmd = "cat > script.sh <<'SH'\n#!/usr/bin/env bash\necho hi\nSH\n";
let label = short_cmd_label(cmd);
assert_eq!(label, "cat > script.sh <<'SH'…");
}
#[test]
fn short_cmd_label_char_truncates_a_long_single_line() {
let long = "x".repeat(CMD_LABEL_MAX_CHARS + 50);
let label = short_cmd_label(&long);
assert_eq!(label.chars().count(), CMD_LABEL_MAX_CHARS + 1); // +1 for the `…`
assert!(label.ends_with('…'));
}
#[test]
fn short_cmd_label_handles_empty_command() {
assert_eq!(short_cmd_label(""), "");
assert_eq!(short_cmd_label(" \n \n"), "");
}
#[test]
fn accepts_ident_names() {
for ok in ["build", "ci-check", "t1", "task-123", "abc"] {