diff --git a/nix/docs.nix b/nix/docs.nix index c4427c94..8cadf7db 100644 --- a/nix/docs.nix +++ b/nix/docs.nix @@ -5,22 +5,28 @@ nixosSystem, }: # Options documentation for hyperhive's NixOS module surfaces. -# Closes #616. +# Closes #616. HTML output added per mara on internal-requests #8. # -# Two output trees: -# docs-host — operator-facing options exposed by the meta module -# (`hyperhive.nixosModules.default`). Covers -# `hyperhive.*` (domain, enable, c0re, forge, matrix) -# plus the deprecated `services.hive-c0re.*` alias. -# docs-agent — per-agent options declared by the shared harness -# module (`nix/templates/harness-base.nix`, transitively -# imported by `agent-base.nix` and `manager.nix`). -# Covers `hyperhive.*` (model, allowedRecipients, -# extraMcpServers, frontend, forge, matrix, gui, …). +# Three rendering layers: +# CommonMark — `pkgs.nixosOptionsDoc.optionsCommonMark`. Source of +# truth; kept as `.md` files in the bundle. +# HTML — `pkgs.cmark-gfm` over the CommonMark output, wrapped +# in a minimal inline-CSS template. Primary surface; the +# bundle's `index.html` / `host.html` / `agent.html` are +# what the operator's nginx serves from +# `hyperhive.darkest.space/options/`. # -# Both render as CommonMark via `pkgs.nixosOptionsDoc`. `docs` bundles -# them into one derivation alongside a small `README.md` index so it -# can be published verbatim. +# Three output trees consumed by `flake.nix`: +# docs-host — operator-facing host-module options +# (`services.hive-c0re.*`, `hyperhive.{domain,forge,matrix}.*`) +# docs-agent — per-agent harness options +# (`hyperhive.{model,allowedRecipients,extraMcpServers,…}`) +# docs — bundled static site (index + host + agent, .html + .md) +# +# All asset paths inside the rendered HTML are relative (e.g. +# `./host.html`) so the bundle can be mounted at any URL prefix +# without rewriting; styles are inline so there's no second-fetch +# request for the operator's browser. let # Evaluate the host module under a stub NixOS system. Stubs satisfy # the few hard-required options (filesystems, stateVersion) without @@ -121,9 +127,11 @@ let inherit transformOptions; }; - mkPage = + # Plain-markdown page (with a short header). Source of truth; the + # HTML version is rendered from this. + mkMarkdownPage = name: title: doc: - pkgs.runCommand "hyperhive-${name}-options.md" { } '' + pkgs.runCommand "hyperhive-${name}.md" { } '' { echo "# ${title}" echo @@ -134,38 +142,188 @@ let cat ${doc.optionsCommonMark} } > $out ''; + + # Single self-contained stylesheet. Inlined into every page so the + # bundle doesn't depend on a second HTTP fetch — keeps the + # `/options/` mount trivial for nginx (no MIME guessing for separate + # .css files, no cache-busting needed when this updates). + styleCSS = '' + :root { + color-scheme: light dark; + --fg: #1a1a1a; + --bg: #fafafa; + --muted: #6b6b6b; + --accent: #5e548e; + --code-bg: rgba(94, 84, 142, 0.08); + --rule: rgba(94, 84, 142, 0.2); + } + @media (prefers-color-scheme: dark) { + :root { + --fg: #e6e6e6; + --bg: #0d0d0d; + --muted: #9b9b9b; + --accent: #c4a7e7; + --code-bg: rgba(196, 167, 231, 0.08); + --rule: rgba(196, 167, 231, 0.2); + } + } + * { box-sizing: border-box; } + body { + font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; + max-width: 56rem; + margin: 0 auto; + padding: 2rem 1.25rem 4rem; + color: var(--fg); + background: var(--bg); + line-height: 1.55; + } + nav { + margin-bottom: 2rem; + padding-bottom: 1rem; + border-bottom: 1px solid var(--rule); + font-size: 0.9rem; + color: var(--muted); + } + nav a { color: var(--accent); text-decoration: none; } + nav a:hover { text-decoration: underline; } + nav a + a { margin-left: 0.5rem; } + nav a + a::before { content: "· "; color: var(--muted); margin-right: 0.25rem; } + h1, h2, h3 { color: var(--accent); line-height: 1.25; } + h1 { font-size: 1.75rem; margin-top: 0; } + h2 { + font-size: 1.15rem; + margin-top: 2.5rem; + padding-top: 0.5rem; + border-top: 1px solid var(--rule); + font-family: ui-monospace, "SFMono-Regular", Menlo, monospace; + } + h3 { font-size: 1rem; } + p { margin: 0.75rem 0; } + code { + background: var(--code-bg); + padding: 0.1em 0.35em; + border-radius: 0.25em; + font-family: ui-monospace, "SFMono-Regular", Menlo, monospace; + font-size: 0.9em; + } + pre { + background: var(--code-bg); + padding: 0.85rem 1rem; + border-left: 2px solid var(--accent); + border-radius: 0 0.25rem 0.25rem 0; + overflow-x: auto; + line-height: 1.4; + } + pre code { background: transparent; padding: 0; } + a { color: var(--accent); } + em { color: var(--muted); font-style: normal; font-size: 0.9em; } + footer { + margin-top: 4rem; + padding-top: 1rem; + border-top: 1px solid var(--rule); + font-size: 0.85rem; + color: var(--muted); + } + ''; + + # HTML page: CommonMark → cmark-gfm → minimal template with inline + # CSS + relative-only links. cmark-gfm rather than plain cmark so + # any future tables / autolinks Just Work without revisiting. + mkHtmlPage = + name: title: doc: + pkgs.runCommand "hyperhive-${name}.html" { nativeBuildInputs = [ pkgs.cmark-gfm ]; } '' + { + echo '' + echo '' + echo '' + echo '' + echo '' + echo '${title}' + echo '' + echo '' + echo '' + echo '' + echo '
' + echo '

${title}

' + echo '

Auto-generated from the hyperhive flake. Source: nix/docs.nix.

' + cmark-gfm ${doc.optionsCommonMark} + echo '
' + echo '' + echo '' + echo '' + } > $out + ''; + + # Landing page — same template shape as the option pages but + # hand-authored content (short intro + cross-links). Kept tight; the + # detail lives on the two option pages. + indexHTML = pkgs.runCommand "hyperhive-docs-index.html" { } '' + { + echo '' + echo '' + echo '' + echo '' + echo '' + echo 'hyperhive — nix options reference' + echo '' + echo '' + echo '' + echo '' + echo '
' + echo '

hyperhive — nix options reference

' + echo '

Auto-generated from the hyperhive flake. Two reading paths:

' + echo '

host options

' + echo '

Options exposed by hyperhive.nixosModules.default to operator host configurations: services.hive-c0re.*, hyperhive.domain, hyperhive.forge.*, hyperhive.matrix.*.

' + echo '

agent options

' + echo '

Per-agent options declared in nix/templates/harness-base.nix and visible from every agent.nix: hyperhive.model, hyperhive.allowedRecipients, hyperhive.extraMcpServers, hyperhive.frontend.*, hyperhive.forge.*, hyperhive.matrix.*, hyperhive.gui.*.

' + echo '

Regenerate

' + echo '
nix build .#docs          # bundled static site (index + host + agent)'
+      echo 'nix build .#docs-host     # host page only (HTML)'
+      echo 'nix build .#docs-agent    # agent page only (HTML)
' + echo '

The bundle also ships .md versions of each page (host.md, agent.md) — same content, source-of-truth shape — alongside the HTML.

' + echo '
' + echo '' + echo '' + echo '' + } > $out + ''; + + hostHTML = mkHtmlPage "docs-host" "hyperhive — host options" hostDoc; + agentHTML = mkHtmlPage "docs-agent" "hyperhive — per-agent options" agentDoc; + hostMD = mkMarkdownPage "docs-host" "hyperhive — host options" hostDoc; + agentMD = mkMarkdownPage "docs-agent" "hyperhive — per-agent options" agentDoc; in { - host = mkPage "docs-host" "hyperhive — host options" hostDoc; - agent = mkPage "docs-agent" "hyperhive — per-agent options" agentDoc; + # Individual page outputs (HTML is the primary surface; the .md + # source is one `nix build` step away if needed). + host = hostHTML; + agent = agentHTML; - # Bundle both pages plus a thin index so the whole thing can be - # published as a single static tree. + # Bundled static site for nginx to serve at `/options/`. Asset paths + # are all relative, no root-absolute references, so the prefix can + # change without rebuild. bundle = pkgs.runCommand "hyperhive-options-docs" { } '' mkdir -p $out - cp ${mkPage "docs-host" "hyperhive — host options" hostDoc} $out/host.md - cp ${mkPage "docs-agent" "hyperhive — per-agent options" agentDoc} $out/agent.md - cat > $out/README.md <<'EOF' - # hyperhive — nix options reference - - auto-generated from the hyperhive flake. - - - [host.md](./host.md) — options exposed by `hyperhive.nixosModules.default` - to operator host configurations (`services.hive-c0re.*`, - `hyperhive.domain`, `hyperhive.forge.*`, `hyperhive.matrix.*`). - - [agent.md](./agent.md) — per-agent options declared in - `nix/templates/harness-base.nix` and visible from every `agent.nix` - (`hyperhive.model`, `hyperhive.allowedRecipients`, - `hyperhive.extraMcpServers`, `hyperhive.frontend.*`, - `hyperhive.forge.*`, `hyperhive.matrix.*`, `hyperhive.gui.*`). - - regenerate: - - ```sh - nix build .#docs # bundled tree - nix build .#docs-host # host page only - nix build .#docs-agent # agent page only - ``` - EOF + cp ${indexHTML} $out/index.html + cp ${hostHTML} $out/host.html + cp ${agentHTML} $out/agent.html + cp ${hostMD} $out/host.md + cp ${agentMD} $out/agent.md ''; }