diff --git a/hive-c0re/src/forge/users.rs b/hive-c0re/src/forge/users.rs index 0cf33712..23ce88ac 100644 --- a/hive-c0re/src/forge/users.rs +++ b/hive-c0re/src/forge/users.rs @@ -24,11 +24,36 @@ use crate::paths::FORGE_CORE_TOKEN as CORE_TOKEN_PATH; // in `crate::paths` — one-shot guards: the upload/align runs once, the // marker is written, subsequent startups skip. Delete one to force its // step to re-run. -// Avatar PNGs are loaded at runtime from -// `$HIVE_ASSETS_DIR/branding/{hyperhive,agent-configs}.png` via the -// helpers in `hive_sh4re::assets`. The `agent-configs.png` is -// rendered from its SVG during the `hyperhive-assets` derivation's -// build. +// Avatar PNG paths are resolved by `core_avatar_png_path` / +// `config_org_avatar_png_path` below — only-used-here, so they live +// in this module rather than the shared `hive_sh4re::assets` helpers +// (which stay for paths every crate needs, e.g. `branding_svg`). + +/// `$HIVE_ASSETS_DIR/branding/hyperhive.png` — the core mark, +/// rasterised. Not independently configurable (unlike the org avatar +/// below) — override the whole `services.hyperhive.c0re.assets` +/// package to change it. +fn core_avatar_png_path() -> std::path::PathBuf { + let dir = std::env::var("HIVE_ASSETS_DIR").expect( + "HIVE_ASSETS_DIR is unset — hive-c0re.nix sets it unconditionally, \ + so this process was started outside the NixOS module", + ); + std::path::PathBuf::from(dir).join("branding/hyperhive.png") +} + +/// Path to the `agent-configs` org's avatar PNG. Independently +/// configurable via `services.hyperhive.c0re.orgAvatarPng` — the nix +/// module resolves `HIVE_ORG_AVATAR_PNG` to that option's value, or +/// the bundled `agent-configs.png` from `assets` when unset, so an +/// operator can override just this image without replacing the whole +/// `assets` package. +fn config_org_avatar_png_path() -> std::path::PathBuf { + std::path::PathBuf::from(std::env::var("HIVE_ORG_AVATAR_PNG").expect( + "HIVE_ORG_AVATAR_PNG is unset — hive-c0re.nix sets it unconditionally \ + (from services.hyperhive.c0re.orgAvatarPng or the bundled default), \ + so this process was started outside the NixOS module", + )) +} /// Per-agent token scopes (broad-but-not-admin) for tokens hive-c0re /// mints itself on the **internal** forge. See `docs/forge.md::Token /// scopes` for the per-scope rationale. Not `pub(super)` — external @@ -400,7 +425,7 @@ pub(super) async fn ensure_core_avatar(token: &str) -> Result<()> { if marker.exists() { return Ok(()); } - let png_path = hive_sh4re::assets::core_avatar_png(); + let png_path = core_avatar_png_path(); let png_bytes = tokio::fs::read(&png_path) .await .with_context(|| format!("read core avatar PNG from {}", png_path.display()))?; @@ -432,7 +457,7 @@ pub(super) async fn ensure_config_org_avatar(token: &str) -> Result<()> { if marker.exists() { return Ok(()); } - let png_path = hive_sh4re::assets::config_org_avatar_png(); + let png_path = config_org_avatar_png_path(); let png_bytes = tokio::fs::read(&png_path) .await .with_context(|| format!("read {CONFIG_ORG} avatar PNG from {}", png_path.display()))?; diff --git a/hive-sh4re/src/assets.rs b/hive-sh4re/src/assets.rs index 53cbff74..7db91b07 100644 --- a/hive-sh4re/src/assets.rs +++ b/hive-sh4re/src/assets.rs @@ -50,23 +50,6 @@ pub fn branding_svg() -> PathBuf { dir().join("branding/hyperhive.svg") } -/// `$HIVE_ASSETS_DIR/branding/hyperhive.png` — the same mark -/// rasterised, used by `hive-c0re::forge::push_avatar` to upload -/// the forge org avatar. -#[must_use] -pub fn core_avatar_png() -> PathBuf { - dir().join("branding/hyperhive.png") -} - -/// `$HIVE_ASSETS_DIR/branding/agent-configs.png` — secondary org -/// mark for the `agent-configs/` mirror org. Rendered from -/// `agent-configs.svg` at asset-build time (was rendered in -/// `hive-c0re/build.rs`). -#[must_use] -pub fn config_org_avatar_png() -> PathBuf { - dir().join("branding/agent-configs.png") -} - /// `$HIVE_ASSETS_DIR/prompts/system.md` — the claude system prompt /// template. `hive-agent::prompt::render` filters the role markers /// inside it per agent / manager flavor. diff --git a/nix/host-modules/hive-c0re/environment.nix b/nix/host-modules/hive-c0re/environment.nix index 66973cdb..453e7cca 100644 --- a/nix/host-modules/hive-c0re/environment.nix +++ b/nix/host-modules/hive-c0re/environment.nix @@ -39,8 +39,17 @@ in HIVE_AGENT_FRONTEND_DIR = "${cfg.servedFrontend}/agent"; # Path to the static runtime asset tree (branding + claude # prompts). `hive_sh4re::assets::*` reads paths underneath. - # `forge.rs` reads the avatar PNGs from here on startup. + # `forge/users.rs` reads the core avatar PNG from here on startup. HIVE_ASSETS_DIR = "${cfg.assets}/share/hyperhive"; + # `agent-configs` org avatar PNG — independently overridable via + # `orgAvatarPng` without replacing the whole `assets` package. + # Falls back to the bundled PNG under HIVE_ASSETS_DIR when unset. + # Read by `forge::users::config_org_avatar_png_path`. + HIVE_ORG_AVATAR_PNG = + if cfg.orgAvatarPng != null then + "${cfg.orgAvatarPng}" + else + "${cfg.assets}/share/hyperhive/branding/agent-configs.png"; # Whether this hive runs ruthless — no root/manager agent at all # (`auto_update::ensure_root_agent`). Default false = root # auto-managed; true makes the sweep a no-op. diff --git a/nix/host-modules/hive-c0re/options.nix b/nix/host-modules/hive-c0re/options.nix index bd10cecd..b69482f9 100644 --- a/nix/host-modules/hive-c0re/options.nix +++ b/nix/host-modules/hive-c0re/options.nix @@ -55,6 +55,19 @@ rust derivation. ''; }; + orgAvatarPng = lib.mkOption { + type = lib.types.nullOr lib.types.path; + default = null; + description = '' + PNG uploaded once as the `agent-configs` Forgejo org's avatar + (`forge::users::ensure_config_org_avatar`, one-shot, + marker-guarded — delete `forge/agent-configs-avatar-set` under + the state dir to force a re-upload after changing this). + Defaults (`null`) to the bundled `agent-configs.png` from + `assets`. Set this to override just the org avatar without + replacing the whole `assets` package. + ''; + }; xdgIcons = lib.mkOption { type = lib.types.package; defaultText = lib.literalExpression "hyperhive.packages.\${system}.xdg-icons";