134 lines
5.4 KiB
Nix
134 lines
5.4 KiB
Nix
# Shell-environment feature hooks: the `_bashEnvFragments`
|
|
# accumulator, the `/etc/hyperhive/bash-env.sh` file it renders to,
|
|
# and the cargo `--message-format short` injector that contributes to
|
|
# it. Loaded via `$BASH_ENV` for non-interactive shells (claude's
|
|
# `Bash` tool runs `bash -c`) and via `programs.bash` for interactive
|
|
# ones.
|
|
{
|
|
lib,
|
|
config,
|
|
...
|
|
}:
|
|
{
|
|
# Internal accumulator for shell snippets that should land in
|
|
# `/etc/hyperhive/bash-env.sh`. Per-feature hooks set this via
|
|
# `lib.mkIf` gated on their own option; the lines type merges
|
|
# all contributions across modules into one file. Generic by
|
|
# design so future hooks don't need to rename this file or
|
|
# invent a parallel dispatcher.
|
|
options.hyperhive._bashEnvFragments = lib.mkOption {
|
|
type = lib.types.lines;
|
|
default = "";
|
|
internal = true;
|
|
description = ''
|
|
Shell snippets concatenated into `/etc/hyperhive/bash-env.sh`.
|
|
Feature hooks contribute via `lib.mkIf` gated on their own
|
|
option. When empty, the file isn't created, `BASH_ENV` stays
|
|
unset, and the interactive bashrc hook is omitted — zero cost
|
|
when no feature is on. Internal — set indirectly via the
|
|
per-feature options that own the gate (e.g.
|
|
`hyperhive.cargo.shortMessages`).
|
|
'';
|
|
};
|
|
|
|
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.
|
|
|
|
Implementation: contributes a `cargo` shell function to
|
|
`/etc/hyperhive/bash-env.sh` (see `hyperhive._bashEnvFragments`).
|
|
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.
|
|
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).
|
|
'';
|
|
};
|
|
|
|
config = {
|
|
# Cargo `--message-format short` injector. `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).
|
|
hyperhive._bashEnvFragments = lib.mkIf config.hyperhive.cargo.shortMessages ''
|
|
# Auto-injects --message-format short on cargo compile
|
|
# subcommands so per-crate progress lines don't flood
|
|
# claude's context. 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
|
|
}
|
|
'';
|
|
|
|
# Single bash-env file with all configured shell fragments.
|
|
# Wiring is gated on at least one fragment being active so a
|
|
# fully feature-disabled agent has neither the file nor the
|
|
# `BASH_ENV` / interactive sourcing — zero cost in that case.
|
|
environment.etc."hyperhive/bash-env.sh" = lib.mkIf (config.hyperhive._bashEnvFragments != "") {
|
|
text = config.hyperhive._bashEnvFragments;
|
|
};
|
|
|
|
# Non-interactive bash invocations (claude's `Bash` tool runs
|
|
# `bash -c`) source $BASH_ENV at startup — drops every active
|
|
# feature hook's snippet into scope without touching
|
|
# `/etc/profile` (login-only).
|
|
environment.variables = lib.mkIf (config.hyperhive._bashEnvFragments != "") {
|
|
BASH_ENV = "/etc/hyperhive/bash-env.sh";
|
|
};
|
|
|
|
# Interactive shells don't honour BASH_ENV — wire the same file
|
|
# in via the bashrc hook so operator SSH sessions get the same
|
|
# hook surface as claude's non-interactive calls. Gated on at
|
|
# least one fragment being active so we don't write a no-op
|
|
# source line into `/etc/bashrc` on fully-feature-disabled agents.
|
|
programs.bash.interactiveShellInit = lib.mkIf (config.hyperhive._bashEnvFragments != "") ''
|
|
if [ -r /etc/hyperhive/bash-env.sh ]; then
|
|
. /etc/hyperhive/bash-env.sh
|
|
fi
|
|
'';
|
|
};
|
|
}
|