feat(#2014): hivectl open verb + Urls host request for web surfaces
This commit is contained in:
parent
c2ba841932
commit
cae1dd8147
6 changed files with 200 additions and 32 deletions
|
|
@ -36,6 +36,7 @@ This document contains the help content for the `hivectl` command-line program.
|
||||||
* [`hivectl quota limit`↴](#hivectl-quota-limit)
|
* [`hivectl quota limit`↴](#hivectl-quota-limit)
|
||||||
* [`hivectl subvol`↴](#hivectl-subvol)
|
* [`hivectl subvol`↴](#hivectl-subvol)
|
||||||
* [`hivectl subvol upgrade`↴](#hivectl-subvol-upgrade)
|
* [`hivectl subvol upgrade`↴](#hivectl-subvol-upgrade)
|
||||||
|
* [`hivectl open`↴](#hivectl-open)
|
||||||
* [`hivectl completions`↴](#hivectl-completions)
|
* [`hivectl completions`↴](#hivectl-completions)
|
||||||
|
|
||||||
## `hivectl`
|
## `hivectl`
|
||||||
|
|
@ -58,6 +59,7 @@ Sibling to the `hive-c0re` daemon binary. Covers host-side admin operations that
|
||||||
* `restart` — Restart containers hive-wide — `stop` then `start` over the same scope. Bare `hivectl restart` restarts **everything** (all sub-agents plus the ci/forge/gateway/matrix infra containers); the same scope flags as `stop`/`start` narrow it (`--agents`, `--ci`, `--forge`, `--gateway`, `--matrix`, `--agent <name>`). If the stop phase reports a failure the start phase is skipped so the operator can investigate. Requires the hive-c0re daemon
|
* `restart` — Restart containers hive-wide — `stop` then `start` over the same scope. Bare `hivectl restart` restarts **everything** (all sub-agents plus the ci/forge/gateway/matrix infra containers); the same scope flags as `stop`/`start` narrow it (`--agents`, `--ci`, `--forge`, `--gateway`, `--matrix`, `--agent <name>`). If the stop phase reports a failure the start phase is skipped so the operator can investigate. Requires the hive-c0re daemon
|
||||||
* `quota` — Per-agent disk accounting + optional quotas via btrfs qgroups
|
* `quota` — Per-agent disk accounting + optional quotas via btrfs qgroups
|
||||||
* `subvol` — btrfs subvolume management for agent state dirs
|
* `subvol` — btrfs subvolume management for agent state dirs
|
||||||
|
* `open` — Print (and best-effort open in a browser) a hive web surface URL
|
||||||
* `completions` — Generate a shell completion script for `hivectl` and print it to stdout
|
* `completions` — Generate a shell completion script for `hivectl` and print it to stdout
|
||||||
|
|
||||||
###### **Options:**
|
###### **Options:**
|
||||||
|
|
@ -527,6 +529,31 @@ Convert an existing plain-dir agent state root into a btrfs subvolume in place.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## `hivectl open`
|
||||||
|
|
||||||
|
Print (and best-effort open in a browser) a hive web surface URL.
|
||||||
|
|
||||||
|
Resolves the URL from the running daemon (`HostRequest::Urls`), so custom forge / matrix domains work without guessing `forge.<domain>`. Prints the URL unconditionally — the reliable core, since the host is usually headless / driven over SSH where `xdg-open` is a no-op — then tries `xdg-open` as a convenience. Bare `hivectl open` opens the operator dashboard.
|
||||||
|
|
||||||
|
**Usage:** `hivectl open [TARGET]`
|
||||||
|
|
||||||
|
###### **Arguments:**
|
||||||
|
|
||||||
|
* `<TARGET>` — Which surface to open. Defaults to the operator dashboard
|
||||||
|
|
||||||
|
Default value: `home`
|
||||||
|
|
||||||
|
Possible values:
|
||||||
|
- `home`:
|
||||||
|
The operator dashboard (`https://<domain>/`)
|
||||||
|
- `forge`:
|
||||||
|
The forge (Forgejo) web UI
|
||||||
|
- `matrix`:
|
||||||
|
The matrix GUI (fluffychat)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## `hivectl completions`
|
## `hivectl completions`
|
||||||
|
|
||||||
Generate a shell completion script for `hivectl` and print it to stdout.
|
Generate a shell completion script for `hivectl` and print it to stdout.
|
||||||
|
|
|
||||||
|
|
@ -151,3 +151,29 @@ lands in a faithful copy of the agent's environment:
|
||||||
the hyperhive/matrix MCP tools (which `--continue` needs to replay a
|
the hyperhive/matrix MCP tools (which `--continue` needs to replay a
|
||||||
tool-using history), and the role prompt. Each flag is included only
|
tool-using history), and the role prompt. Each flag is included only
|
||||||
when its file exists.
|
when its file exists.
|
||||||
|
|
||||||
|
## Open
|
||||||
|
|
||||||
|
Print (and best-effort open in a browser) one of the hive's web surfaces.
|
||||||
|
Requires the `hive-c0re` daemon to be running.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
hivectl open # operator dashboard (same as `open home`)
|
||||||
|
hivectl open home # operator dashboard (https://<domain>/)
|
||||||
|
hivectl open forge # the forge (Forgejo) web UI
|
||||||
|
hivectl open matrix # the matrix GUI (fluffychat)
|
||||||
|
```
|
||||||
|
|
||||||
|
The URL is resolved from the running daemon (`HostRequest::Urls`), which
|
||||||
|
reads the per-surface public URLs from c0re's service env — so custom
|
||||||
|
forge / matrix domains resolve correctly instead of assuming
|
||||||
|
`forge.<domain>`. The URL is **always printed** (the reliable core, since
|
||||||
|
the host is usually headless / driven over SSH), then `xdg-open` is tried
|
||||||
|
as a convenience — a missing or failing opener is reported as a note, not
|
||||||
|
an error.
|
||||||
|
|
||||||
|
A surface has no URL when it isn't browser-reachable: `home` needs
|
||||||
|
`services.hyperhive.domain`; `forge` needs
|
||||||
|
`services.hyperhive.forge.behindGateway = true`; `matrix` needs
|
||||||
|
`services.hyperhive.matrix.gui.enable = true`. In those cases the command
|
||||||
|
exits with a hint naming the option to set.
|
||||||
|
|
|
||||||
|
|
@ -204,6 +204,19 @@ enum Cmd {
|
||||||
#[command(subcommand)]
|
#[command(subcommand)]
|
||||||
cmd: SubvolCmd,
|
cmd: SubvolCmd,
|
||||||
},
|
},
|
||||||
|
/// Print (and best-effort open in a browser) a hive web surface URL.
|
||||||
|
///
|
||||||
|
/// Resolves the URL from the running daemon (`HostRequest::Urls`), so
|
||||||
|
/// custom forge / matrix domains work without guessing `forge.<domain>`.
|
||||||
|
/// Prints the URL unconditionally — the reliable core, since the host
|
||||||
|
/// is usually headless / driven over SSH where `xdg-open` is a no-op —
|
||||||
|
/// then tries `xdg-open` as a convenience. Bare `hivectl open` opens the
|
||||||
|
/// operator dashboard.
|
||||||
|
Open {
|
||||||
|
/// Which surface to open. Defaults to the operator dashboard.
|
||||||
|
#[arg(value_enum, default_value_t = OpenTarget::Home)]
|
||||||
|
target: OpenTarget,
|
||||||
|
},
|
||||||
/// Emit the full CLI reference as `CommonMark` to stdout.
|
/// Emit the full CLI reference as `CommonMark` to stdout.
|
||||||
///
|
///
|
||||||
/// Hidden tooling command (not part of day-to-day operator admin):
|
/// Hidden tooling command (not part of day-to-day operator admin):
|
||||||
|
|
@ -227,6 +240,17 @@ enum Cmd {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Which hive web surface `hivectl open` targets.
|
||||||
|
#[derive(Copy, Clone, Debug, clap::ValueEnum)]
|
||||||
|
enum OpenTarget {
|
||||||
|
/// The operator dashboard (`https://<domain>/`).
|
||||||
|
Home,
|
||||||
|
/// The forge (Forgejo) web UI.
|
||||||
|
Forge,
|
||||||
|
/// The matrix GUI (fluffychat).
|
||||||
|
Matrix,
|
||||||
|
}
|
||||||
|
|
||||||
/// Shared scope flags for `hivectl stop` / `hivectl start`. With no flag
|
/// Shared scope flags for `hivectl stop` / `hivectl start`. With no flag
|
||||||
/// set the verb targets **everything** (all sub-agents + every controllable
|
/// set the verb targets **everything** (all sub-agents + every controllable
|
||||||
/// infra container). Setting any flag restricts to the selected classes,
|
/// infra container). Setting any flag restricts to the selected classes,
|
||||||
|
|
@ -628,6 +652,7 @@ async fn main() -> Result<()> {
|
||||||
print!("{}", clap_markdown::help_markdown::<Cli>());
|
print!("{}", clap_markdown::help_markdown::<Cli>());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
Cmd::Open { target } => open_url(&socket, target).await,
|
||||||
Cmd::Completions { shell } => {
|
Cmd::Completions { shell } => {
|
||||||
generate_completions(shell);
|
generate_completions(shell);
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -635,6 +660,41 @@ async fn main() -> Result<()> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// `open <home|forge|matrix>` — resolve the surface URL from the daemon,
|
||||||
|
/// print it, then best-effort `xdg-open` it. Printing is the reliable
|
||||||
|
/// core (headless / SSH hosts where no browser opener exists); the open
|
||||||
|
/// is convenience on top, so a missing/failed `xdg-open` is not an error.
|
||||||
|
async fn open_url(socket: &Path, target: OpenTarget) -> Result<()> {
|
||||||
|
let urls = query_hive_urls(socket).await.context(
|
||||||
|
"could not reach the hive-c0re daemon for URLs — is hive-c0re running? \
|
||||||
|
(the socket is at /run/hyperhive/host.sock)",
|
||||||
|
)?;
|
||||||
|
let (url, hint) = match target {
|
||||||
|
OpenTarget::Home => (
|
||||||
|
urls.home,
|
||||||
|
"the dashboard URL needs `services.hyperhive.domain` to be set",
|
||||||
|
),
|
||||||
|
OpenTarget::Forge => (
|
||||||
|
urls.forge,
|
||||||
|
"the public forge URL needs `services.hyperhive.forge.behindGateway = true`",
|
||||||
|
),
|
||||||
|
OpenTarget::Matrix => (
|
||||||
|
urls.matrix,
|
||||||
|
"the matrix GUI URL needs `services.hyperhive.matrix.gui.enable = true`",
|
||||||
|
),
|
||||||
|
};
|
||||||
|
let url = url.with_context(|| format!("no URL available for this surface — {hint}"))?;
|
||||||
|
println!("{url}");
|
||||||
|
// Best-effort: many hosts are headless, so a missing opener or a
|
||||||
|
// non-zero exit is fine — the URL is already printed.
|
||||||
|
match std::process::Command::new("xdg-open").arg(&url).status() {
|
||||||
|
Ok(status) if status.success() => {}
|
||||||
|
Ok(status) => eprintln!("note: xdg-open exited with {status} (URL printed above)"),
|
||||||
|
Err(e) => eprintln!("note: could not run xdg-open ({e}) (URL printed above)"),
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Emit a shell completion script for `hivectl` to stdout. Walks the clap
|
/// Emit a shell completion script for `hivectl` to stdout. Walks the clap
|
||||||
/// command tree (the single source of truth — same tree `markdown-docs`
|
/// command tree (the single source of truth — same tree `markdown-docs`
|
||||||
/// renders) so completions never drift from the actual verbs/flags.
|
/// renders) so completions never drift from the actual verbs/flags.
|
||||||
|
|
@ -658,14 +718,20 @@ const WG_INTERFACE: &str = "wg-hive";
|
||||||
const HIVE_TLS_CA_PATH: &str = "/var/lib/hive-tls/ca.pem";
|
const HIVE_TLS_CA_PATH: &str = "/var/lib/hive-tls/ca.pem";
|
||||||
|
|
||||||
/// Best-effort query for this hive's domain from the running daemon
|
/// Best-effort query for this hive's domain from the running daemon
|
||||||
/// (`HostRequest::HiveDomain`, which reads `HYPERHIVE_HIVE_DOMAIN` from
|
/// (`HostRequest::Urls`, which reads `HYPERHIVE_HIVE_DOMAIN` from c0re's
|
||||||
/// c0re's service env). `None` when the daemon is unreachable or the
|
/// service env). `None` when the daemon is unreachable or the domain is
|
||||||
/// domain is unset — callers decide whether that's fatal.
|
/// unset — callers decide whether that's fatal.
|
||||||
async fn query_hive_domain(socket: &Path) -> Option<String> {
|
async fn query_hive_domain(socket: &Path) -> Option<String> {
|
||||||
hive_c0re::client::request(socket, hive_sh4re::HostRequest::HiveDomain)
|
query_hive_urls(socket).await.and_then(|u| u.domain)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Best-effort query for this hive's domain + browser-facing web URLs
|
||||||
|
/// (`HostRequest::Urls`). `None` when the daemon is unreachable.
|
||||||
|
async fn query_hive_urls(socket: &Path) -> Option<hive_sh4re::HiveUrls> {
|
||||||
|
hive_c0re::client::request(socket, hive_sh4re::HostRequest::Urls)
|
||||||
.await
|
.await
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|r| r.domain)
|
.and_then(|r| r.urls)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Require this hive's domain from the daemon for snippet generation.
|
/// Require this hive's domain from the daemon for snippet generation.
|
||||||
|
|
|
||||||
|
|
@ -155,16 +155,12 @@ async fn dispatch(req: &HostRequest, coord: Arc<Coordinator>) -> HostResponse {
|
||||||
.collect();
|
.collect();
|
||||||
HostResponse::agent_statuses(rows)
|
HostResponse::agent_statuses(rows)
|
||||||
}
|
}
|
||||||
// The hive domain is injected into c0re's service env by
|
// The hive domain + per-surface public URLs are injected into
|
||||||
// hive-c0re.nix (`HYPERHIVE_HIVE_DOMAIN`); surface it so the
|
// c0re's service env by hive-c0re.nix; surface them so the
|
||||||
// operator CLI can fill in this hive's own identity.
|
// operator CLI can fill in this hive's own identity (the
|
||||||
HostRequest::HiveDomain => HostResponse::hive_domain(
|
// federation peer-config block) and open the web surfaces
|
||||||
// Treat an empty env value as unset — otherwise the CLI
|
// (`hivectl open`).
|
||||||
// would emit `swarm.peers."" = …`, invalid nix.
|
HostRequest::Urls => HostResponse::urls(hive_urls()),
|
||||||
std::env::var("HYPERHIVE_HIVE_DOMAIN")
|
|
||||||
.ok()
|
|
||||||
.filter(|d| !d.is_empty()),
|
|
||||||
),
|
|
||||||
HostRequest::Pending => HostResponse::pending(coord.approvals.pending()?),
|
HostRequest::Pending => HostResponse::pending(coord.approvals.pending()?),
|
||||||
HostRequest::Approve { id } => {
|
HostRequest::Approve { id } => {
|
||||||
actions::approve(coord.clone(), *id).await?;
|
actions::approve(coord.clone(), *id).await?;
|
||||||
|
|
@ -261,7 +257,7 @@ async fn handle_restart_all() -> Result<HostResponse> {
|
||||||
error: Some(errors.join("; ")),
|
error: Some(errors.join("; ")),
|
||||||
agents: Some(ok_agents),
|
agents: Some(ok_agents),
|
||||||
approvals: None,
|
approvals: None,
|
||||||
domain: None,
|
urls: None,
|
||||||
agent_statuses: None,
|
agent_statuses: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -379,6 +375,25 @@ fn is_broad_scope(scope: &LifecycleScope) -> bool {
|
||||||
scope.agents || scope.is_everything()
|
scope.agents || scope.is_everything()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Assemble this hive's domain + browser-facing web URLs from c0re's
|
||||||
|
/// service env (injected by hive-c0re.nix). Each field is `None` when its
|
||||||
|
/// surface isn't browser-reachable (domain unset, forge not behind the
|
||||||
|
/// gateway, matrix GUI off), so the CLI can hint precisely instead of
|
||||||
|
/// opening a dead link. Scheme matches the existing `HIVE_FORGE_PUBLIC_URL`
|
||||||
|
/// convention (gateway terminates TLS, so https).
|
||||||
|
fn hive_urls() -> hive_sh4re::HiveUrls {
|
||||||
|
// Treat an empty env value as unset everywhere — an empty domain would
|
||||||
|
// otherwise render `swarm.peers."" = …` (invalid nix) and `https:///`.
|
||||||
|
let env = |k: &str| std::env::var(k).ok().filter(|v| !v.is_empty());
|
||||||
|
let domain = env("HYPERHIVE_HIVE_DOMAIN");
|
||||||
|
hive_sh4re::HiveUrls {
|
||||||
|
home: domain.as_ref().map(|d| format!("https://{d}/")),
|
||||||
|
forge: env("HIVE_FORGE_PUBLIC_URL"),
|
||||||
|
matrix: env("HIVE_MATRIX_PUBLIC_URL"),
|
||||||
|
domain,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async fn scoped_agents(scope: &LifecycleScope) -> Result<Vec<String>> {
|
async fn scoped_agents(scope: &LifecycleScope) -> Result<Vec<String>> {
|
||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
let mut set: BTreeSet<String> = BTreeSet::new();
|
let mut set: BTreeSet<String> = BTreeSet::new();
|
||||||
|
|
@ -430,7 +445,7 @@ fn finish_lifecycle(ok_items: Vec<String>, errors: &[String]) -> HostResponse {
|
||||||
error: Some(errors.join("; ")),
|
error: Some(errors.join("; ")),
|
||||||
agents: Some(ok_items),
|
agents: Some(ok_items),
|
||||||
approvals: None,
|
approvals: None,
|
||||||
domain: None,
|
urls: None,
|
||||||
agent_statuses: None,
|
agent_statuses: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,10 +50,13 @@ pub enum HostRequest {
|
||||||
/// Reuses the dashboard's per-agent `ContainerView` aggregation.
|
/// Reuses the dashboard's per-agent `ContainerView` aggregation.
|
||||||
AgentStatus,
|
AgentStatus,
|
||||||
/// Report this hive's canonical DNS domain
|
/// Report this hive's canonical DNS domain
|
||||||
/// (`services.hyperhive.domain`), or `None` when unset. Lets the
|
/// (`services.hyperhive.domain`) plus the browser-facing home /
|
||||||
/// operator CLI fill in the hive's own identity (e.g. the federation
|
/// forge / matrix URLs, daemon-sourced so custom forge/matrix
|
||||||
/// peer-config block) without the operator retyping it.
|
/// domains resolve correctly. Each URL is `None` when its subsystem
|
||||||
HiveDomain,
|
/// is unreachable from a browser (e.g. forge not behind the gateway,
|
||||||
|
/// matrix GUI disabled). Backs `hivectl open` + the federation
|
||||||
|
/// peer-config block (which reads the bare `domain`).
|
||||||
|
Urls,
|
||||||
/// List pending approval requests.
|
/// List pending approval requests.
|
||||||
Pending,
|
Pending,
|
||||||
/// Approve a pending request by id; the action runs immediately.
|
/// Approve a pending request by id; the action runs immediately.
|
||||||
|
|
@ -132,6 +135,25 @@ impl LifecycleScope {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This hive's canonical domain plus the browser-facing URLs for its
|
||||||
|
/// web surfaces — the `Urls` request result. Every field is `None` when
|
||||||
|
/// the corresponding surface can't be reached from a browser (domain
|
||||||
|
/// unset, forge not behind the gateway, matrix GUI disabled), so the CLI
|
||||||
|
/// can give a precise hint instead of opening a dead link.
|
||||||
|
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
||||||
|
pub struct HiveUrls {
|
||||||
|
/// Canonical hive domain (`services.hyperhive.domain`).
|
||||||
|
pub domain: Option<String>,
|
||||||
|
/// Operator dashboard root (`https://<domain>/`).
|
||||||
|
pub home: Option<String>,
|
||||||
|
/// Forge browser URL (`HIVE_FORGE_PUBLIC_URL`) — only the
|
||||||
|
/// behind-gateway public URL; `None` on direct-port forge deploys.
|
||||||
|
pub forge: Option<String>,
|
||||||
|
/// Matrix GUI (fluffychat) browser URL — `None` when the matrix GUI
|
||||||
|
/// is disabled.
|
||||||
|
pub matrix: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct HostResponse {
|
pub struct HostResponse {
|
||||||
pub ok: bool,
|
pub ok: bool,
|
||||||
|
|
@ -141,10 +163,10 @@ pub struct HostResponse {
|
||||||
pub agents: Option<Vec<String>>,
|
pub agents: Option<Vec<String>>,
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
pub approvals: Option<Vec<Approval>>,
|
pub approvals: Option<Vec<Approval>>,
|
||||||
/// This hive's canonical DNS domain — `HiveDomain` result. `None`
|
/// `Urls` result — this hive's domain plus the browser-facing
|
||||||
/// when the domain is unset (no `services.hyperhive.domain`).
|
/// home / forge / matrix URLs. `None` for every other request kind.
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
pub domain: Option<String>,
|
pub urls: Option<HiveUrls>,
|
||||||
/// `AgentStatus` result — one row per managed agent with its
|
/// `AgentStatus` result — one row per managed agent with its
|
||||||
/// running/health flags + technical state. `None` for every other
|
/// running/health flags + technical state. `None` for every other
|
||||||
/// request kind.
|
/// request kind.
|
||||||
|
|
@ -245,7 +267,7 @@ impl HostResponse {
|
||||||
error: None,
|
error: None,
|
||||||
agents: None,
|
agents: None,
|
||||||
approvals: None,
|
approvals: None,
|
||||||
domain: None,
|
urls: None,
|
||||||
agent_statuses: None,
|
agent_statuses: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -257,7 +279,7 @@ impl HostResponse {
|
||||||
error: Some(message.into()),
|
error: Some(message.into()),
|
||||||
agents: None,
|
agents: None,
|
||||||
approvals: None,
|
approvals: None,
|
||||||
domain: None,
|
urls: None,
|
||||||
agent_statuses: None,
|
agent_statuses: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -269,7 +291,7 @@ impl HostResponse {
|
||||||
error: None,
|
error: None,
|
||||||
agents: Some(agents),
|
agents: Some(agents),
|
||||||
approvals: None,
|
approvals: None,
|
||||||
domain: None,
|
urls: None,
|
||||||
agent_statuses: None,
|
agent_statuses: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -281,20 +303,20 @@ impl HostResponse {
|
||||||
error: None,
|
error: None,
|
||||||
agents: None,
|
agents: None,
|
||||||
approvals: Some(approvals),
|
approvals: Some(approvals),
|
||||||
domain: None,
|
urls: None,
|
||||||
agent_statuses: None,
|
agent_statuses: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `HiveDomain` result — this hive's canonical domain (or `None`).
|
/// `Urls` result — this hive's domain + browser-facing web URLs.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn hive_domain(domain: Option<String>) -> Self {
|
pub fn urls(urls: HiveUrls) -> Self {
|
||||||
Self {
|
Self {
|
||||||
ok: true,
|
ok: true,
|
||||||
error: None,
|
error: None,
|
||||||
agents: None,
|
agents: None,
|
||||||
approvals: None,
|
approvals: None,
|
||||||
domain,
|
urls: Some(urls),
|
||||||
agent_statuses: None,
|
agent_statuses: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -307,7 +329,7 @@ impl HostResponse {
|
||||||
error: None,
|
error: None,
|
||||||
agents: None,
|
agents: None,
|
||||||
approvals: None,
|
approvals: None,
|
||||||
domain: None,
|
urls: None,
|
||||||
agent_statuses: Some(rows),
|
agent_statuses: Some(rows),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -953,6 +953,18 @@ in
|
||||||
# falls back to `<hostname>:3000`.
|
# falls back to `<hostname>:3000`.
|
||||||
HIVE_FORGE_PUBLIC_URL = "https://${config.services.hyperhive.forge.domain}";
|
HIVE_FORGE_PUBLIC_URL = "https://${config.services.hyperhive.forge.domain}";
|
||||||
}
|
}
|
||||||
|
//
|
||||||
|
lib.optionalAttrs
|
||||||
|
(
|
||||||
|
config.services.hyperhive.matrix.gui.enable && config.services.hyperhive.matrix.gatewayHost != null
|
||||||
|
)
|
||||||
|
{
|
||||||
|
# Browser-facing matrix GUI (fluffychat) URL — the gateway
|
||||||
|
# vhost (`matrix.<domain>`). Surfaced via the daemon's `Urls`
|
||||||
|
# request for `hivectl open matrix`. Absent when the GUI is off
|
||||||
|
# or no gatewayHost is set (no browser-reachable matrix vhost).
|
||||||
|
HIVE_MATRIX_PUBLIC_URL = "https://${config.services.hyperhive.matrix.gatewayHost}/";
|
||||||
|
}
|
||||||
// lib.optionalAttrs (config.services.hyperhive.swarm.peers != { }) {
|
// lib.optionalAttrs (config.services.hyperhive.swarm.peers != { }) {
|
||||||
# Peer hives serialised as a JSON array of {domain, cert_fingerprint,
|
# Peer hives serialised as a JSON array of {domain, cert_fingerprint,
|
||||||
# wireguard_address?} objects. Consumed by hive-ag3nt::identity::peers()
|
# wireguard_address?} objects. Consumed by hive-ag3nt::identity::peers()
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue