Compare commits

...
Author SHA1 Message Date
atlas
39af2bad5d style: nix fmt hive-xdg-icons.nix (treefmt) 2026-07-08 23:37:09 +02:00
atlas
ba5a0e1a66 fix: add hyperhiveXdgIcons stub to nix/docs eval (fixes packages.docs check) 2026-07-08 23:37:09 +02:00
atlas
64eddfd0b6 feat(#2228): add XDG icon set and .desktop entries for hyperhive processes
Adds hive-xdg-icons package (nix/packages/hive-xdg-icons.nix) that
rasterizes the branding SVG to all standard hicolor sizes (16–256px)
and installs /usr/share/pixmaps/hyperhive.png as a flat fallback.
Ships .desktop entries for hive-c0re and hive-ag3nt with NoDisplay=true
so desktop environments can match running processes to their icon without
cluttering the application launcher.

Narrow drv input: only ./branding/hyperhive.svg, so unrelated source
changes don't bust the cache.

Wired into environment.systemPackages in hive-c0re.nix (host side)
so the icons are present wherever hive-c0re is deployed.

Closes #2228
2026-07-08 23:37:09 +02:00
atlas
fa944d1213 fix(#2284): replace nixos-container kill with machinectl kill SIGKILL
nixos-container has no kill verb. The KillContainer priv request was
calling nixos-container kill which always fails. Replace with:

  machinectl kill <name> --signal=SIGKILL

which sends SIGKILL to all processes in the container — the correct
semantics for a forced shutdown (called after graceful stop has been
attempted). Add a machinectl_run helper alongside container_run so
callers stay consistent.
2026-07-08 22:47:36 +02:00
6 changed files with 132 additions and 2 deletions

View file

@ -236,6 +236,12 @@
# nix/reference-docs.nix. (`docs` above is the auto-generated
# nix-options reference, a different artifact.)
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
# so operators can `nix build .#agent-base-toplevel` (or wire
# them into their host system closure via the
@ -298,6 +304,7 @@
hyperhivePackage = system: self.packages.${system}.default;
hyperhiveFrontend = system: self.packages.${system}.frontend;
hyperhiveAssets = system: self.packages.${system}.assets;
hyperhiveXdgIcons = system: self.packages.${system}.xdg-icons;
hyperhiveFlake = "${hyperhiveFlakeSource}";
# Narrow docs/ source, threaded as its own meta-flake input so
# doc edits don't re-hash the whole flake source.

View file

@ -172,7 +172,11 @@ async fn exec(req: PrivRequest, writer: &mut OwnedWriteHalf) -> Result<(String,
PrivRequest::KillContainer { ref 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 } => {
@ -1026,6 +1030,34 @@ async fn container_run(args: &[&str]) -> Result<(String, String)> {
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
/// to the caller as `PrivEvent::Line` messages in real time, logging each
/// line to journald as it arrives. Returns `(String::new(), String::new())`

View file

@ -230,7 +230,8 @@ pub enum PrivRequest {
/// `nixos-container stop <name>`
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 },
/// `nixos-container update <name> --flake <flake_ref>`

View file

@ -48,6 +48,7 @@ let
hyperhiveAssets = _system: pkgs.emptyDirectory;
hyperhiveFlake = "";
hyperhiveDocs = "";
hyperhiveXdgIcons = _system: pkgs.emptyFile;
agentBaseToplevel = pkgs.emptyFile;
managerToplevel = pkgs.emptyFile;
})

View file

@ -4,6 +4,7 @@
hyperhiveAssets,
hyperhiveFlake,
hyperhiveDocs,
hyperhiveXdgIcons,
agentBaseToplevel,
managerToplevel,
}:
@ -794,6 +795,9 @@ in
environment.systemPackages = [
cfg.package
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

View 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";
};
}