harness-base: generic bash-env.sh + _bashEnvFragments accumulator (mara on #779)
mara: 'if we replace it with one thing, that should be named more generic so we dont have to change it for future additions'. extract the BASH_ENV plumbing into a shared shape: - new internal option `hyperhive._bashEnvFragments` (types.lines) accumulates shell snippets across feature modules. - file path is now `/etc/hyperhive/bash-env.sh` (was the cargo-specific bash-cargo-short.sh). - the file + BASH_ENV + interactiveShellInit are gated on `_bashEnvFragments != """ so a fully feature-disabled agent has no overhead. cargo function moves to a `lib.mkIf cargo.shortMessages` contribution to `_bashEnvFragments` — same behaviour, no rename when the next hook (nix-env helper, claude-cmd helpers, whatever) lands.
This commit is contained in:
parent
5f61528133
commit
ea5f70629c
1 changed files with 90 additions and 59 deletions
|
|
@ -537,6 +537,30 @@ in
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# 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. Loaded via
|
||||||
|
# `$BASH_ENV` for non-interactive shells (claude's `Bash` tool
|
||||||
|
# runs `bash -c`) and via `programs.bash.interactiveShellInit`
|
||||||
|
# for interactive shells. Generic by design (mara on #779) so
|
||||||
|
# future hooks don't need to either 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 {
|
options.hyperhive.cargo.shortMessages = lib.mkOption {
|
||||||
type = lib.types.bool;
|
type = lib.types.bool;
|
||||||
default = true;
|
default = true;
|
||||||
|
|
@ -550,12 +574,12 @@ in
|
||||||
the response window with per-crate progress lines that
|
the response window with per-crate progress lines that
|
||||||
carry no signal beyond the warning/error summary (#777).
|
carry no signal beyond the warning/error summary (#777).
|
||||||
|
|
||||||
Implementation: a `cargo` shell function defined in
|
Implementation: contributes a `cargo` shell function to
|
||||||
`/etc/hyperhive/bash-cargo-short.sh`. Loaded via `BASH_ENV`
|
`/etc/hyperhive/bash-env.sh` (see `hyperhive._bashEnvFragments`).
|
||||||
for non-interactive shells (`bash -c` — what the claude
|
Loaded via `BASH_ENV` for non-interactive shells (`bash -c` —
|
||||||
`Bash` tool runs) and sourced from `programs.bash.interactiveShellInit`
|
what the claude `Bash` tool runs) and sourced from
|
||||||
for interactive shells (operator pokes around inside the
|
`programs.bash.interactiveShellInit` for interactive shells.
|
||||||
container). The function:
|
The function:
|
||||||
|
|
||||||
- handles the `+toolchain` selector prefix (`cargo +nightly
|
- handles the `+toolchain` selector prefix (`cargo +nightly
|
||||||
build` works);
|
build` works);
|
||||||
|
|
@ -746,50 +770,55 @@ in
|
||||||
source = config.hyperhive.icon;
|
source = config.hyperhive.icon;
|
||||||
};
|
};
|
||||||
|
|
||||||
# Cargo `--message-format short` injector (#777). Sourced from
|
# Cargo `--message-format short` injector (#777). Contributes a
|
||||||
# BASH_ENV in non-interactive shells AND interactiveShellInit
|
# `cargo` shell function to `hyperhive._bashEnvFragments`; the
|
||||||
# so both claude's `Bash` tool and operator SSH sessions get
|
# bash-env infrastructure below packages that into a single file
|
||||||
# the same compact compile output. `command cargo …` falls back
|
# sourced by both non-interactive and interactive shells.
|
||||||
# to the un-wrapped binary in PATH (the rust toolchain's cargo
|
# `command cargo …` falls back to the un-wrapped binary in PATH
|
||||||
# — either from `environment.systemPackages` or from whatever
|
# (the rust toolchain's cargo — either from `environment.systemPackages`
|
||||||
# `nix develop` shell the agent's working in).
|
# or from whatever `nix develop` shell the agent's working in).
|
||||||
environment.etc."hyperhive/bash-cargo-short.sh" =
|
hyperhive._bashEnvFragments = lib.mkIf config.hyperhive.cargo.shortMessages ''
|
||||||
lib.mkIf config.hyperhive.cargo.shortMessages
|
# Auto-injects --message-format short on cargo compile
|
||||||
{
|
# subcommands so per-crate progress lines don't flood
|
||||||
text = ''
|
# claude's context (#777). Bypassed when the caller
|
||||||
# Auto-injects --message-format short on cargo compile
|
# already passes --message-format (any form).
|
||||||
# subcommands so per-crate progress lines don't flood
|
cargo() {
|
||||||
# claude's context (#777). Bypassed when the caller
|
# Strip leading +toolchain selectors (cargo +nightly …).
|
||||||
# already passes --message-format (any form).
|
local pre=()
|
||||||
cargo() {
|
while [ "''${1:0:1}" = "+" ] && [ -n "''${1:-}" ]; do
|
||||||
# Strip leading +toolchain selectors (cargo +nightly …).
|
pre+=("$1")
|
||||||
local pre=()
|
shift
|
||||||
while [ "''${1:0:1}" = "+" ] && [ -n "''${1:-}" ]; do
|
done
|
||||||
pre+=("$1")
|
case "''${1:-}" in
|
||||||
shift
|
build|check|clippy|test|run|doc|bench|install|rustc|fix)
|
||||||
done
|
local sub="$1"
|
||||||
case "''${1:-}" in
|
shift
|
||||||
build|check|clippy|test|run|doc|bench|install|rustc|fix)
|
local arg
|
||||||
local sub="$1"
|
for arg in "$@"; do
|
||||||
shift
|
case "$arg" in
|
||||||
local arg
|
--message-format|--message-format=*)
|
||||||
for arg in "$@"; do
|
command cargo "''${pre[@]}" "$sub" "$@"
|
||||||
case "$arg" in
|
return $?
|
||||||
--message-format|--message-format=*)
|
|
||||||
command cargo "''${pre[@]}" "$sub" "$@"
|
|
||||||
return $?
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
command cargo "''${pre[@]}" "$sub" --message-format short "$@"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
command cargo "''${pre[@]}" "$@"
|
|
||||||
;;
|
;;
|
||||||
esac
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
environment.etc."hyperhive/bash-allow.json".text =
|
environment.etc."hyperhive/bash-allow.json".text =
|
||||||
builtins.toJSON config.hyperhive.allowedBashPatterns;
|
builtins.toJSON config.hyperhive.allowedBashPatterns;
|
||||||
|
|
@ -853,23 +882,25 @@ in
|
||||||
// lib.optionalAttrs (config.hyperhive.forge.skipNotifyReasons != [ ]) {
|
// lib.optionalAttrs (config.hyperhive.forge.skipNotifyReasons != [ ]) {
|
||||||
HIVE_FORGE_NOTIFY_SKIP_REASONS = lib.concatStringsSep "," config.hyperhive.forge.skipNotifyReasons;
|
HIVE_FORGE_NOTIFY_SKIP_REASONS = lib.concatStringsSep "," config.hyperhive.forge.skipNotifyReasons;
|
||||||
}
|
}
|
||||||
// lib.optionalAttrs config.hyperhive.cargo.shortMessages {
|
// lib.optionalAttrs (config.hyperhive._bashEnvFragments != "") {
|
||||||
# Non-interactive bash invocations (claude's `Bash` tool runs
|
# Non-interactive bash invocations (claude's `Bash` tool runs
|
||||||
# `bash -c`) source $BASH_ENV at startup — drops the cargo
|
# `bash -c`) source $BASH_ENV at startup — drops every active
|
||||||
# function defined in the file above into scope without
|
# feature hook's snippet into scope without touching
|
||||||
# touching /etc/profile (login-only). Interactive shells
|
# `/etc/profile` (login-only). Interactive shells source the
|
||||||
# source the same file via the interactiveShellInit hook
|
# same file via the `interactiveShellInit` hook below so
|
||||||
# below so behaviour matches across both modes (#777).
|
# behaviour matches across both modes (#777).
|
||||||
BASH_ENV = "/etc/hyperhive/bash-cargo-short.sh";
|
BASH_ENV = "/etc/hyperhive/bash-env.sh";
|
||||||
};
|
};
|
||||||
|
|
||||||
# Interactive shells don't honour BASH_ENV — wire the same file
|
# Interactive shells don't honour BASH_ENV — wire the same file
|
||||||
# in via the bashrc hook so operator SSH sessions get the same
|
# in via the bashrc hook so operator SSH sessions get the same
|
||||||
# short-format cargo output as claude's non-interactive calls.
|
# 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 =
|
programs.bash.interactiveShellInit =
|
||||||
lib.mkIf config.hyperhive.cargo.shortMessages ''
|
lib.mkIf (config.hyperhive._bashEnvFragments != "") ''
|
||||||
if [ -r /etc/hyperhive/bash-cargo-short.sh ]; then
|
if [ -r /etc/hyperhive/bash-env.sh ]; then
|
||||||
. /etc/hyperhive/bash-cargo-short.sh
|
. /etc/hyperhive/bash-env.sh
|
||||||
fi
|
fi
|
||||||
'';
|
'';
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue