Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ff3317eb20 | ||
|
|
2d97401fc0 |
3 changed files with 17 additions and 7 deletions
|
|
@ -151,7 +151,7 @@ fn render_bash_status(id: &str, resp: Result<DaemonResponse>, waited: bool) -> S
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, JsonSchema)]
|
#[derive(Debug, Deserialize, JsonSchema)]
|
||||||
struct BashRunArgs {
|
struct BashRunArgs {
|
||||||
/// Shell command to run (passed to `sh -c`).
|
/// Shell command to run (passed to `bash -c`).
|
||||||
cmd: String,
|
cmd: String,
|
||||||
/// Timeout in seconds. Defaults to `None` (no timeout) — task runs until
|
/// Timeout in seconds. Defaults to `None` (no timeout) — task runs until
|
||||||
/// natural exit. Pass an explicit value to kill the task after N seconds
|
/// natural exit. Pass an explicit value to kill the task after N seconds
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
//! Bash subprocess runner: spawns `sh -c <cmd>` tasks, writes status
|
//! Bash subprocess runner: spawns `bash -c <cmd>` tasks, writes status
|
||||||
//! files under `harness/bash-tasks/`, and fires hyperhive wake signals
|
//! files under `harness/bash-tasks/`, and fires hyperhive wake signals
|
||||||
//! on completion. Mirrors the logic previously embedded in `hive-ag3nt`.
|
//! on completion. Mirrors the logic previously embedded in `hive-ag3nt`.
|
||||||
//!
|
//!
|
||||||
|
|
@ -400,8 +400,13 @@ async fn run_task(mut task: TaskFile, socket: &Path) {
|
||||||
send_wake(socket, &id, &summary, Some((out_snippet, err_snippet))).await;
|
send_wake(socket, &id, &summary, Some((out_snippet, err_snippet))).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Run `sh -c cmd`, streaming output to files. Returns `(exit_code, timed_out)`.
|
/// Run `bash -c cmd`, streaming output to files. Returns `(exit_code, timed_out)`.
|
||||||
/// `timeout_secs = None` means no timeout — run until natural exit.
|
/// `timeout_secs = None` means no timeout — run until natural exit.
|
||||||
|
///
|
||||||
|
/// Tasks run under `bash`, not `sh`: on NixOS `/bin/sh` is bash in POSIX
|
||||||
|
/// mode, which disables bashisms (arrays, `[[ … ]]`, `local`, process
|
||||||
|
/// substitution, …). Agents write bash, so we invoke `bash` (via
|
||||||
|
/// `/usr/bin/env bash`).
|
||||||
async fn exec_cmd(
|
async fn exec_cmd(
|
||||||
cmd: &str,
|
cmd: &str,
|
||||||
out_path: &Path,
|
out_path: &Path,
|
||||||
|
|
@ -411,8 +416,13 @@ async fn exec_cmd(
|
||||||
use tokio::process::Command;
|
use tokio::process::Command;
|
||||||
// SAFETY: `nice` is async-signal-safe and modifies only the calling
|
// SAFETY: `nice` is async-signal-safe and modifies only the calling
|
||||||
// process's scheduling priority before exec. No allocations, no locks.
|
// process's scheduling priority before exec. No allocations, no locks.
|
||||||
let mut cmd_builder = Command::new("sh");
|
// `/usr/bin/env bash` rather than a bare `bash`: `/usr/bin/env` is at a
|
||||||
|
// fixed absolute path (coreutils, present on NixOS), and it resolves
|
||||||
|
// `bash` via PATH — the same controlled PATH the daemon's systemd unit
|
||||||
|
// sets. Avoids hardcoding a nix store / generation path in the binary.
|
||||||
|
let mut cmd_builder = Command::new("/usr/bin/env");
|
||||||
cmd_builder
|
cmd_builder
|
||||||
|
.arg("bash")
|
||||||
.arg("-c")
|
.arg("-c")
|
||||||
.arg(cmd)
|
.arg(cmd)
|
||||||
.stdout(std::process::Stdio::piped())
|
.stdout(std::process::Stdio::piped())
|
||||||
|
|
|
||||||
|
|
@ -1419,14 +1419,14 @@ in
|
||||||
systemd.services.hive-bash-daemon = {
|
systemd.services.hive-bash-daemon = {
|
||||||
description = "bash task runner daemon for hive-bash-mcp";
|
description = "bash task runner daemon for hive-bash-mcp";
|
||||||
wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
# The daemon runs every bash task via `Command::new("sh")` and the
|
# The daemon runs every bash task via `Command::new("bash")` and the
|
||||||
# commands themselves (hive-forge, git, jq, …) resolve from PATH.
|
# commands themselves (hive-forge, git, jq, …) resolve from PATH.
|
||||||
# Pre-split this ran inside hive-ag3nt.service and inherited the
|
# Pre-split this ran inside hive-ag3nt.service and inherited the
|
||||||
# agent's PATH; the standalone daemon needs the same or `sh` itself
|
# agent's PATH; the standalone daemon needs the same or `bash` itself
|
||||||
# isn't found (spawn fails with ENOENT, the task is marked done in
|
# isn't found (spawn fails with ENOENT, the task is marked done in
|
||||||
# 0s with no output / no .out/.err). Mirror the harness unit's PATH:
|
# 0s with no output / no .out/.err). Mirror the harness unit's PATH:
|
||||||
# NixOS appends `/bin` to each entry → /run/wrappers/bin (setuid
|
# NixOS appends `/bin` to each entry → /run/wrappers/bin (setuid
|
||||||
# sudo) + /run/current-system/sw/bin (sh, coreutils, hive-forge, …).
|
# sudo) + /run/current-system/sw/bin (bash, coreutils, hive-forge, …).
|
||||||
path = [
|
path = [
|
||||||
"/run/wrappers"
|
"/run/wrappers"
|
||||||
"/run/current-system/sw"
|
"/run/current-system/sw"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue