diff --git a/nix/templates/harness-base.nix b/nix/templates/harness-base.nix index ae65bc3b..ca02087f 100644 --- a/nix/templates/harness-base.nix +++ b/nix/templates/harness-base.nix @@ -537,6 +537,40 @@ in ''; }; + options.hyperhive.cargo.shortMessages = lib.mkOption { + type = lib.types.bool; + default = true; + example = false; + description = '' + Auto-inject `--message-format short` on cargo compile + subcommands (`build`, `check`, `clippy`, `test`, `run`, + `doc`, `bench`, `install`, `rustc`, `fix`) when claude (or + anything else) invokes `cargo` inside this container. + Saves tokens + context — the verbose default output floods + the response window with per-crate progress lines that + carry no signal beyond the warning/error summary (#777). + + Implementation: a `cargo` shell function defined in + `/etc/hyperhive/bash-cargo-short.sh`. Loaded via `BASH_ENV` + for non-interactive shells (`bash -c` — what the claude + `Bash` tool runs) and sourced from `programs.bash.interactiveShellInit` + for interactive shells (operator pokes around inside the + container). The function: + + - handles the `+toolchain` selector prefix (`cargo +nightly + build` works); + - passes through cleanly when the caller already specified + `--message-format` (any form); + - leaves non-compile subcommands (`new`, `add`, `search`, + third-party `cargo-*` subcommands) untouched so they + don't error on the unknown flag. + + Set to `false` for agents that need full cargo output (e.g. + tooling that parses `--message-format json` programmatically + and doesn't pass the flag explicitly). + ''; + }; + options.hyperhive.autoCompact = lib.mkOption { type = lib.types.bool; default = true; @@ -712,6 +746,51 @@ in source = config.hyperhive.icon; }; + # Cargo `--message-format short` injector (#777). Sourced from + # BASH_ENV in non-interactive shells AND interactiveShellInit + # so both claude's `Bash` tool and operator SSH sessions get + # the same compact compile output. `command cargo …` falls back + # to the un-wrapped binary in PATH (the rust toolchain's cargo + # — either from `environment.systemPackages` or from whatever + # `nix develop` shell the agent's working in). + environment.etc."hyperhive/bash-cargo-short.sh" = + lib.mkIf config.hyperhive.cargo.shortMessages + { + text = '' + # Auto-injects --message-format short on cargo compile + # subcommands so per-crate progress lines don't flood + # claude's context (#777). Bypassed when the caller + # already passes --message-format (any form). + cargo() { + # Strip leading +toolchain selectors (cargo +nightly …). + local pre=() + while [ "''${1:0:1}" = "+" ] && [ -n "''${1:-}" ]; do + pre+=("$1") + shift + done + case "''${1:-}" in + build|check|clippy|test|run|doc|bench|install|rustc|fix) + local sub="$1" + shift + local arg + for arg in "$@"; do + case "$arg" in + --message-format|--message-format=*) + command cargo "''${pre[@]}" "$sub" "$@" + return $? + ;; + esac + done + command cargo "''${pre[@]}" "$sub" --message-format short "$@" + ;; + *) + command cargo "''${pre[@]}" "$@" + ;; + esac + } + ''; + }; + environment.etc."hyperhive/bash-allow.json".text = builtins.toJSON config.hyperhive.allowedBashPatterns; @@ -773,8 +852,27 @@ in } // lib.optionalAttrs (config.hyperhive.forge.skipNotifyReasons != [ ]) { HIVE_FORGE_NOTIFY_SKIP_REASONS = lib.concatStringsSep "," config.hyperhive.forge.skipNotifyReasons; + } + // lib.optionalAttrs config.hyperhive.cargo.shortMessages { + # Non-interactive bash invocations (claude's `Bash` tool runs + # `bash -c`) source $BASH_ENV at startup — drops the cargo + # function defined in the file above into scope without + # touching /etc/profile (login-only). Interactive shells + # source the same file via the interactiveShellInit hook + # below so behaviour matches across both modes (#777). + BASH_ENV = "/etc/hyperhive/bash-cargo-short.sh"; }; + # Interactive shells don't honour BASH_ENV — wire the same file + # in via the bashrc hook so operator SSH sessions get the same + # short-format cargo output as claude's non-interactive calls. + programs.bash.interactiveShellInit = + lib.mkIf config.hyperhive.cargo.shortMessages '' + if [ -r /etc/hyperhive/bash-cargo-short.sh ]; then + . /etc/hyperhive/bash-cargo-short.sh + fi + ''; + boot.isNspawnContainer = true; # Every agent gets flakes + the modern `nix` CLI out of the box.