Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
39af2bad5d | ||
|
|
ba5a0e1a66 | ||
|
|
64eddfd0b6 | ||
|
|
fa944d1213 |
6 changed files with 132 additions and 2 deletions
|
|
@ -236,6 +236,12 @@
|
||||||
# nix/reference-docs.nix. (`docs` above is the auto-generated
|
# nix/reference-docs.nix. (`docs` above is the auto-generated
|
||||||
# nix-options reference, a different artifact.)
|
# nix-options reference, a different artifact.)
|
||||||
reference-docs = pkgs.callPackage ./nix/reference-docs.nix { };
|
reference-docs = pkgs.callPackage ./nix/reference-docs.nix { };
|
||||||
|
# XDG icon set + .desktop entries for hyperhive processes.
|
||||||
|
# Narrow input: only the branding SVG, so unrelated source changes
|
||||||
|
# don't bust this derivation's cache.
|
||||||
|
xdg-icons = pkgs.callPackage ./nix/packages/hive-xdg-icons.nix {
|
||||||
|
hyperhiveSvg = ./branding/hyperhive.svg;
|
||||||
|
};
|
||||||
# Pre-built per-container system closures. Exposed as packages
|
# Pre-built per-container system closures. Exposed as packages
|
||||||
# so operators can `nix build .#agent-base-toplevel` (or wire
|
# so operators can `nix build .#agent-base-toplevel` (or wire
|
||||||
# them into their host system closure via the
|
# them into their host system closure via the
|
||||||
|
|
@ -298,6 +304,7 @@
|
||||||
hyperhivePackage = system: self.packages.${system}.default;
|
hyperhivePackage = system: self.packages.${system}.default;
|
||||||
hyperhiveFrontend = system: self.packages.${system}.frontend;
|
hyperhiveFrontend = system: self.packages.${system}.frontend;
|
||||||
hyperhiveAssets = system: self.packages.${system}.assets;
|
hyperhiveAssets = system: self.packages.${system}.assets;
|
||||||
|
hyperhiveXdgIcons = system: self.packages.${system}.xdg-icons;
|
||||||
hyperhiveFlake = "${hyperhiveFlakeSource}";
|
hyperhiveFlake = "${hyperhiveFlakeSource}";
|
||||||
# Narrow docs/ source, threaded as its own meta-flake input so
|
# Narrow docs/ source, threaded as its own meta-flake input so
|
||||||
# doc edits don't re-hash the whole flake source.
|
# doc edits don't re-hash the whole flake source.
|
||||||
|
|
|
||||||
|
|
@ -172,7 +172,11 @@ async fn exec(req: PrivRequest, writer: &mut OwnedWriteHalf) -> Result<(String,
|
||||||
|
|
||||||
PrivRequest::KillContainer { ref name } => {
|
PrivRequest::KillContainer { ref name } => {
|
||||||
validate_container_name(name)?;
|
validate_container_name(name)?;
|
||||||
container_run(&["kill", &container_system_name(name)]).await
|
// nixos-container has no kill verb. Use machinectl to send SIGKILL
|
||||||
|
// to all processes in the container — the right semantics for a
|
||||||
|
// forced shutdown after a graceful stop has already been attempted.
|
||||||
|
let machine = container_system_name(name);
|
||||||
|
machinectl_run(&["kill", &machine, "--signal=SIGKILL"]).await
|
||||||
}
|
}
|
||||||
|
|
||||||
PrivRequest::UpdateContainer { ref name, stream } => {
|
PrivRequest::UpdateContainer { ref name, stream } => {
|
||||||
|
|
@ -1026,6 +1030,34 @@ async fn container_run(args: &[&str]) -> Result<(String, String)> {
|
||||||
Ok((stdout, stderr))
|
Ok((stdout, stderr))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Invoke `machinectl` with the given args, log output to journald.
|
||||||
|
/// Used for operations that nixos-container doesn't expose (e.g. sending
|
||||||
|
/// signals to running containers).
|
||||||
|
async fn machinectl_run(args: &[&str]) -> Result<(String, String)> {
|
||||||
|
let out = Command::new("machinectl")
|
||||||
|
.args(args)
|
||||||
|
.output()
|
||||||
|
.await
|
||||||
|
.context("invoke machinectl")?;
|
||||||
|
let stdout = String::from_utf8_lossy(&out.stdout).into_owned();
|
||||||
|
let stderr = String::from_utf8_lossy(&out.stderr).into_owned();
|
||||||
|
for line in stdout.lines() {
|
||||||
|
tracing::info!(target: "machinectl", "{line}");
|
||||||
|
}
|
||||||
|
for line in stderr.lines() {
|
||||||
|
tracing::warn!(target: "machinectl", "{line}");
|
||||||
|
}
|
||||||
|
if !out.status.success() {
|
||||||
|
bail!(
|
||||||
|
"machinectl {} failed ({}): {}",
|
||||||
|
args.join(" "),
|
||||||
|
out.status,
|
||||||
|
stderr.trim()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Ok((stdout, stderr))
|
||||||
|
}
|
||||||
|
|
||||||
/// Invoke `nixos-container` with the given args and forward output lines
|
/// Invoke `nixos-container` with the given args and forward output lines
|
||||||
/// to the caller as `PrivEvent::Line` messages in real time, logging each
|
/// to the caller as `PrivEvent::Line` messages in real time, logging each
|
||||||
/// line to journald as it arrives. Returns `(String::new(), String::new())`
|
/// line to journald as it arrives. Returns `(String::new(), String::new())`
|
||||||
|
|
|
||||||
|
|
@ -230,7 +230,8 @@ pub enum PrivRequest {
|
||||||
/// `nixos-container stop <name>`
|
/// `nixos-container stop <name>`
|
||||||
StopContainer { name: String },
|
StopContainer { name: String },
|
||||||
|
|
||||||
/// `nixos-container kill <name>`
|
/// `machinectl kill <name> --signal=SIGKILL` — force-kills all processes
|
||||||
|
/// in the container. nixos-container has no kill verb.
|
||||||
KillContainer { name: String },
|
KillContainer { name: String },
|
||||||
|
|
||||||
/// `nixos-container update <name> --flake <flake_ref>`
|
/// `nixos-container update <name> --flake <flake_ref>`
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,7 @@ let
|
||||||
hyperhiveAssets = _system: pkgs.emptyDirectory;
|
hyperhiveAssets = _system: pkgs.emptyDirectory;
|
||||||
hyperhiveFlake = "";
|
hyperhiveFlake = "";
|
||||||
hyperhiveDocs = "";
|
hyperhiveDocs = "";
|
||||||
|
hyperhiveXdgIcons = _system: pkgs.emptyFile;
|
||||||
agentBaseToplevel = pkgs.emptyFile;
|
agentBaseToplevel = pkgs.emptyFile;
|
||||||
managerToplevel = pkgs.emptyFile;
|
managerToplevel = pkgs.emptyFile;
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
hyperhiveAssets,
|
hyperhiveAssets,
|
||||||
hyperhiveFlake,
|
hyperhiveFlake,
|
||||||
hyperhiveDocs,
|
hyperhiveDocs,
|
||||||
|
hyperhiveXdgIcons,
|
||||||
agentBaseToplevel,
|
agentBaseToplevel,
|
||||||
managerToplevel,
|
managerToplevel,
|
||||||
}:
|
}:
|
||||||
|
|
@ -794,6 +795,9 @@ in
|
||||||
environment.systemPackages = [
|
environment.systemPackages = [
|
||||||
cfg.package
|
cfg.package
|
||||||
pkgs.git
|
pkgs.git
|
||||||
|
# XDG icons + .desktop entries so desktop environments can match
|
||||||
|
# hyperhive processes to their icon (task managers, CPU monitors, etc.).
|
||||||
|
(hyperhiveXdgIcons pkgs.stdenv.hostPlatform.system)
|
||||||
];
|
];
|
||||||
|
|
||||||
# Serve config at a stable /etc path so hive-c0re's ExecStart
|
# Serve config at a stable /etc path so hive-c0re's ExecStart
|
||||||
|
|
|
||||||
85
nix/packages/hive-xdg-icons.nix
Normal file
85
nix/packages/hive-xdg-icons.nix
Normal file
|
|
@ -0,0 +1,85 @@
|
||||||
|
{
|
||||||
|
stdenv,
|
||||||
|
librsvg,
|
||||||
|
# Absolute path to the hyperhive.svg source so this derivation's input
|
||||||
|
# hash is narrow: a change to any other source file does NOT bust it.
|
||||||
|
hyperhiveSvg,
|
||||||
|
}:
|
||||||
|
|
||||||
|
# XDG icon set + .desktop entries for hyperhive processes so desktop
|
||||||
|
# environments can match running processes to icons (task managers, CPU
|
||||||
|
# monitors, etc.).
|
||||||
|
#
|
||||||
|
# Output layout:
|
||||||
|
# $out/share/icons/hicolor/<N>x<N>/apps/hyperhive.png (N = 16,32,48,64,128,256)
|
||||||
|
# $out/share/pixmaps/hyperhive.png (48px fallback)
|
||||||
|
# $out/share/applications/hive-c0re.desktop
|
||||||
|
# $out/share/applications/hive-ag3nt.desktop
|
||||||
|
stdenv.mkDerivation {
|
||||||
|
pname = "hive-xdg-icons";
|
||||||
|
version = "0.1.0";
|
||||||
|
|
||||||
|
# No source tree — everything is built from the single SVG path.
|
||||||
|
dontUnpack = true;
|
||||||
|
|
||||||
|
nativeBuildInputs = [ librsvg ];
|
||||||
|
|
||||||
|
buildPhase = ''
|
||||||
|
runHook preBuild
|
||||||
|
mkdir -p icons
|
||||||
|
for size in 16 32 48 64 128 256; do
|
||||||
|
rsvg-convert --width "$size" --height "$size" \
|
||||||
|
-o "icons/hyperhive-''${size}.png" \
|
||||||
|
${hyperhiveSvg}
|
||||||
|
done
|
||||||
|
runHook postBuild
|
||||||
|
'';
|
||||||
|
|
||||||
|
installPhase = ''
|
||||||
|
runHook preInstall
|
||||||
|
# Per-size hicolor tree
|
||||||
|
for size in 16 32 48 64 128 256; do
|
||||||
|
mkdir -p "$out/share/icons/hicolor/''${size}x''${size}/apps"
|
||||||
|
cp "icons/hyperhive-''${size}.png" \
|
||||||
|
"$out/share/icons/hicolor/''${size}x''${size}/apps/hyperhive.png"
|
||||||
|
done
|
||||||
|
# Flat pixmaps fallback (48px)
|
||||||
|
mkdir -p "$out/share/pixmaps"
|
||||||
|
cp icons/hyperhive-48.png "$out/share/pixmaps/hyperhive.png"
|
||||||
|
|
||||||
|
# .desktop entries — NoDisplay so they don't show up in app launchers
|
||||||
|
# but are still discovered by process-to-icon matchers (GNOME, etc.).
|
||||||
|
mkdir -p "$out/share/applications"
|
||||||
|
cat > "$out/share/applications/hive-c0re.desktop" <<EOF
|
||||||
|
[Desktop Entry]
|
||||||
|
Type=Application
|
||||||
|
Name=hyperhive core
|
||||||
|
GenericName=hive-c0re
|
||||||
|
Comment=hyperhive host daemon — container lifecycle, broker, operator dashboard
|
||||||
|
Exec=hive-c0re serve
|
||||||
|
Icon=hyperhive
|
||||||
|
Categories=System;
|
||||||
|
NoDisplay=true
|
||||||
|
StartupNotify=false
|
||||||
|
EOF
|
||||||
|
cat > "$out/share/applications/hive-ag3nt.desktop" <<EOF
|
||||||
|
[Desktop Entry]
|
||||||
|
Type=Application
|
||||||
|
Name=hyperhive agent
|
||||||
|
GenericName=hive-ag3nt
|
||||||
|
Comment=hyperhive per-agent harness (claude turn loop + MCP server)
|
||||||
|
Exec=hive serve
|
||||||
|
Icon=hyperhive
|
||||||
|
Categories=System;
|
||||||
|
NoDisplay=true
|
||||||
|
StartupNotify=false
|
||||||
|
EOF
|
||||||
|
runHook postInstall
|
||||||
|
'';
|
||||||
|
|
||||||
|
dontFixup = true;
|
||||||
|
|
||||||
|
meta = {
|
||||||
|
description = "XDG icon set and .desktop entries for hyperhive processes";
|
||||||
|
};
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue