Commit graph

963 commits

Author SHA1 Message Date
iris
4c30b52e48 tabs.js: scrub #398/#432 cookies from container-card render path (#712 batch 4)
Seven cookies removed across the container-card rendering code (4
#398, 3 #432). All point at existing docs/web-ui.md::Container row
prose (rebuild_queue building badge, stopped-container state
clearing). Each comment shrinks to either a short docs ref or just
drops the cookie where the substantive content already explains
itself.

Net ±0 lines in tabs.js (rewrites are similar length); the win is
each comment now reads as 'what this code does' rather than 'why
PR #N decided this'. tabs.js is now at 48 #NNN refs (down from
55 at start of this batch, 73 at start of the milestone).

refs #712, builds on #722 + #724 + #728
2026-05-31 12:35:08 +02:00
damocles
c3ec037105 lifecycle: prebuild attr path needs explicit nixosConfigurations.<name> (fix #721 regression) 2026-05-31 12:31:02 +02:00
atlas
68bac7986b nix/hive-gateway: SPA fallback via Accept-header map, not extension allowlist (#686)
mara on PR #729: "this still feels hacky - is there a proper way to do this?"
damocles: agreed, "Accept-header map is meaningfully better than the
allowlist [...] one map definition that encodes browser semantics directly,
vs ~20 extensions to keep synced with whatever fluffychat (and any future
hyperhive-served SPA) decides to ship".

The previous shape (#684 catch-all regex, then this PR v1's
extension allowlist) leaned on heuristics to distinguish "missing
asset → 404" from "unknown SPA route → fall back to index.html".
Both shapes were fragile against a SPA shipping a new extension,
and the allowlist became dead code the moment a route ended in
`.html-ish-suffix`.

The proper distinction lives at the HTTP layer: top-frame browser
navigations send `Accept: text/html,...` (chrome/firefox/safari are
consistent on this). Asset fetches from script tags / img / fetch() /
XHR send asset-typed Accepts (`image/*`, `application/javascript`,
`*/*`) without `text/html`.

Mechanics: an `nginx http`-context `map` keyed on `$http_accept`
emits either `/matrix/index.html` (navigation) or a sentinel
nonexistent path (`/__matrix_spa_no_html_fallback`); the location's
`try_files $uri $uri/ $matrix_spa_target =404;` does the right thing
for both cases. No extension list, no regex narrowing, no `if` block,
no named-location fallback.

The `map` lives in `services.nginx.appendHttpConfig` (only added
when the matrix GUI is on, otherwise no `map` directive at all).
The location's `extraConfig` is now a single `try_files` line.

Verified via `nix eval` on both the rendered `appendHttpConfig` and
the location's `extraConfig`. Full closure build pending operator
deploy.

Closes #686.
2026-05-31 12:27:52 +02:00
lexis
264c984398 docs: list all 5 system-prompt placeholders + set_status validation limits
turn-loop.md:
- expand stale '{label} and {operator_pronouns}' note to all 5
  current placeholders (#730 added hive_identity + swarm_identity)
- add 200-char + single-line validation note to set_status (#723)
2026-05-31 12:23:59 +02:00
iris
10097bb9b6 tabs.js: collapse stale dangling sentence in per-card actions comment (argus #728)
When I rewrote the original 'Per-card action buttons … moved into
the sticky #selection-bar (see renderSelectionBar) which appears
when the operator has at least one agent selected via the icon
click' comment to use the docs ref, I shrunk part of it but left
the second sentence as a dangling fragment glued onto the new
short ref. Collapse cleanly: docs ref + the still-useful
`needs update ↻` chip note.
2026-05-31 12:16:27 +02:00
iris
69debe6b7d tabs.js + web-ui.md: drop 'no special-case manager' framing (mara on #728)
mara's review nit: explaining the absence of a manager special-case
implicitly endorses the idea that special cases would be normal.
Default is no special case; the doc shouldn't dwell on it.

- ST0P comment block removed entirely (the bulk-button line above
  is self-explanatory; the substantive 'c0re survives manager-down'
  rationale lives in the host docs, not here).
- M0V3 helper comment reframed: trim the 'no special-case' framing
  but keep the substantive note that the backend refuses moves it
  can't satisfy and the failure surfaces in the bulk roll-up.
- docs/web-ui.md::Selection bar bullet list: drop the 'manager
  included; no special-case' qualifiers; just describe the action.
  M0V3→ROOT keeps the rationale that backend refusals surface in
  the roll-up but stops calling out manager specifically.
2026-05-31 12:16:27 +02:00
iris
a9422518e5 docs: scrub selection-bar #443/#596 cookies in tabs.js, add interaction-model preface (#712 batch 3)
selection + selection-bar in tabs.js carried six #443 cookies + two
#596 cookies — most marking the bulk-bar architectural decision
('actions live in bar, not on per-card buttons; manager not
special-cased') or the SW4RM-tab gate. All scrubbed; the canonical
docs/web-ui.md::Selection bar section already covered the bulk
actions in detail but was missing a preface for the **interaction
model** itself (how selection enters/exits, why per-card buttons
moved). Added that as the opening paragraph of the section so the
in-code refs have something to point at.

Net in this batch:
- tabs.js: -8 #NNN refs (#443 ×6, #596 ×2)
- docs/web-ui.md: +9 lines (interaction-model preface)
- functional code unchanged; build clean

refs #712
2026-05-31 12:16:27 +02:00
atlas
7647969d49 nix/hive-matrix: run dart compile js from build CWD so package_config resolves (#685 fixup)
mara's first deploy hit:

    Error: Couldn't resolve the package 'matrix' in 'package:matrix/matrix.dart'.
    /nix/store/k9j8ns45fz7rpjp6rzk33ydjng67pgm0-source/web/native_executor.dart:1:8:
    Error: Not found: 'package:matrix/matrix.dart'

Root cause: `dart compile js` walks up from the source file's dir to
find `.dart_tool/package_config.json`. My previous postInstall passed
`$src/web/native_executor.dart` — pointing dart at the unpacked nix
source, which has no `.dart_tool/` (pub-get wrote it to the build CWD,
not the read-only store path).

Fix: use a relative path `web/native_executor.dart`. nixpkgs's
buildFlutterApplication leaves CWD at the source root in postInstall
(its installPhase is just `cp -r build/web "$out"` with no `cd`
first — see `pkgs/development/compilers/flutter/build-support/
build-flutter-application.nix`), so the relative path walks up from
`web/` to the build CWD where pub-get's package_config lives.

Verified by `nix eval`; full closure build pending operator deploy.
Followup to #697 (the original fix; merged but mara's deploy then
surfaced this regression).
2026-05-31 12:16:01 +02:00
damocles
3323bca677 prompt: thread hive + swarm display names into system prompt opener (#709) 2026-05-31 12:15:34 +02:00
iris
37d99ed118 agent UI: relative paths for all assets/api/ws so the page works under any nginx prefix (#14)
Per mara on #14: 'make agent page not assume root path, links / api
calls need to be relative'. atlas's nginx side (#15) will mount the
per-agent UI at a prefix like /agent/<name>/ instead of its own
port; for the page to keep working under that prefix, every
in-page reference needs to resolve document-relative rather than
root-anchored.

Converted in this pass:
- HTML <link>/<script>/<img>/<a> hrefs in index.html, stats.html,
  screen.html: '/icon' → 'icon', '/static/agent.css' →
  'static/agent.css', back links '/' → './'.
- app.js fetch() targets ('/api/state' → 'api/state', /api/cancel,
  /api/loose-ends, etc.), form actions ('/login/start', '/send'),
  EventSource urls ('/events/stream', '/events/history').
- stats.js fetch() targets.
- screen.html WebSocket URL: was hardcoded as
  ws(s)://host/screen/ws; now derived from document.baseURI via
  new URL('screen/ws', document.baseURI) so the gateway prefix
  flows through.

Slash-command labels (/cancel, /compact, …) and the dashboard-port
link (different port, intentionally absolute) intentionally
untouched.

Added a new 'Per-agent relative paths' section to docs/web-ui.md
covering the rationale + the trailing-slash gotcha (sub-pages like
/stats must NOT have a trailing slash, or 'static/app.js' resolves
under /stats/ instead of replacing the segment).

Functional code unchanged; build clean. Damocles + atlas can
proceed with the backend / nginx side without depending on this
landing first, but once both ship the agent page works under the
gateway-prefixed URL without further changes.

refs #14
2026-05-31 12:10:56 +02:00
iris
003b36c4a0 docs/web-ui.md: trim 3 blank lines → 1 before Selection bar (argus #722) 2026-05-31 11:56:15 +02:00
iris
711d42031c docs: scrub module-split cookies from tabs.js + migrate paintAtomic rationale (#712 batch 2)
Two threads cleaned up in tabs.js:

1. Top-of-file '#406 step 1/2/3' historical narrative deleted —
   it documented past module splits (moves to common.js / flow.js,
   file rename app.js → tabs.js) which are git-history concerns,
   not current-behaviour docs. Replaced with a two-sentence
   contract description that references docs/web-ui.md and the
   present-tense module split.

2. Five 'moved to ./common.js (#406)' stubs deleted — same
   reasoning. The imports at the top of the file already document
   what's in common.js; standalone 'this function lives elsewhere'
   pointers are noise once you stop tracking the move event.

paintAtomic's substantive rationale migrated to a new
'Atomic section repaint' subsection in docs/web-ui.md (under the
existing focus-preservation note); in-code comment shrinks to a
two-line reference. Same pattern as the topology-tree batch.

Net: 36 fewer lines in tabs.js, 14 new in docs/web-ui.md.
Functional code unchanged; build clean.

refs #712
2026-05-31 11:56:15 +02:00
damocles
0a98327685 lifecycle: only prebuild when there's downtime to shave (mara on #721) 2026-05-31 11:55:35 +02:00
damocles
f5372b6016 lifecycle: prebuild system toplevel before stop+update so container downtime shrinks (#706) 2026-05-31 11:55:35 +02:00
damocles
6c2cd078f1 set_status: reject multi-line and over-200-char text (#720) 2026-05-31 11:54:08 +02:00
iris
26d8565365 docs: migrate tabs.js topology-tree prose to docs/web-ui.md (#712 pattern check)
First slice of #712 (dashboard SPA frontend → docs/). Shrinks the
buildAgentTree + treePrefixDom comment blocks in tabs.js to one-line
docs/ references; adds a new 'Topology tree' subsection to
docs/web-ui.md under '### Container row' carrying the substantive
prose.

Net effect on this region:
- 6 #NNN tracking cookies dropped (#363, #361, #388)
- 30 lines of substantive design comments collapsed to 6 lines of
  references in tabs.js
- 35 new lines in docs/web-ui.md (the migrated prose, restructured
  into a single coherent subsection rather than two adjacent comment
  blocks)
- functional code unchanged; build clean

Deliberately small pattern-check (one cohesive subsystem) before
expanding to the rest of #712 (~140 more refs across tabs.js +
dashboard.css + index.html + common.js + flow.js). Reviewers can
sanity-check the shape (where prose lands, how short the in-code
ref becomes, whether section nesting reads well) before I scale.

refs #712
2026-05-31 11:49:02 +02:00
lexis
31288ae760 docs: fix stale wake caveat, add <parent> sentinel + systemd path gotcha
turn-loop.md:
- remove stale "Agent-only today" note from hive wake (fixed by #698)
- add <parent> sentinel to send tool description (added by #703)

gotchas.md:
- add systemd.services.*.path /bin auto-append gotcha (hit by #672/#705)
2026-05-31 11:48:46 +02:00
damocles
c41bf1b562 harness: surface hive + swarm display names to agents (#701) 2026-05-31 11:42:55 +02:00
damocles
04f69c1fe1 topology: early-exit resolve_recipient before topology.json read (argus on #703) 2026-05-31 11:39:27 +02:00
damocles
7142e95c8f broker: resolve <parent> sentinel to topology parent at send time (#692) 2026-05-31 11:39:27 +02:00
atlas
1a9d940a4a nix/hive-matrix: reuse fluffychat-web's pub-cache native_imaging source (no parallel pin, #685 mara feedback)
mara on PR #697: "this still puts us in the position of having to update
that dependency in sync with upstream. cant we use the one from the
nixpkgs build directly somehow?"

Drops the parallel `fetchurl` + sha256 pin in `fluffychat-web-imaging`.
Source now comes from
`pkgs.fluffychat-web.passthru.pubspecLock.dependencySources.native_imaging`
— the exact derivation that fluffychat-web's flutter build already pulls
into its pub-cache for the dart-side bindings. Version likewise pulled
from `passthru.pubspecLock.dependencyVersions.native_imaging`.

Result: when nixpkgs bumps `pkgs.fluffychat-web` (and with it the
pubspec.lock-resolved native_imaging version), our build automatically
picks up the matching source. No parallel hash to bump, no risk of drift
between the dart-side bindings and the wasm-side C compile.

Verified the build still works against the pub-cache-sourced derivation
(same Makefile, same emscripten flow):

  $ nix-build test-passthru.nix
  ...
  buildPhase completed in 52 seconds
  $ ls /nix/store/.../fluffychat-web-imaging-0.4.0/
  Imaging.js   (9956 bytes)
  Imaging.wasm (67363 bytes)

Byte-for-byte identical to the previous v2 output, just sourced from
the same store path fluffychat-web itself uses.

Follow-up to argus's v2 🟢 review of #697. No regression on the prior
review feedback — `make -C js` + explicit installPhase paths still in place.
2026-05-31 11:36:46 +02:00
atlas
0231ac84d3 nix/hive-matrix: drop implicit cd in fluffychat-web-imaging buildPhase (argus #697 v2 🟡)
Switches from `cd js && make ...` to `make -C js ...` so buildPhase
leaves pwd at the source root. installPhase's `js/Imaging.{js,wasm}`
paths are now correct against an explicit pwd rather than relying on
buildPhase's mid-phase cd side-effect carrying over.

No functional change — just robustness against future phase reorders /
`dontBuild` overrides, per argus's 🟡 on the v2 review of #697.
2026-05-31 11:36:46 +02:00
atlas
a9f0955865 nix/hive-matrix: build Imaging.{js,wasm} from source via emscripten (#685, mara feedback)
mara on PR #697: "dont use the prebuilt binary, fix the compile of the
one in nixpkgs (however its easiest: overlay, own derivation based on
it, hell if you want to you can fix buildFlutterApplication, idk)."

Replaces the upstream-tarball vendor with an own derivation that
compiles `Imaging.{js,wasm}` from the `native_imaging` dart package's
C source via `pkgs.emscripten`. Same source provenance as fluffychat
itself uses (both pin native_imaging 0.4.0 from pub.dev), now actually
exercised at build time.

Mechanics: new `fluffychat-web-imaging` derivation in the `let` block:

  - src: `fetchurl` from pub.dev's `native_imaging-0.4.0.tar.gz`
    (hash sha256-ztessYuApDFXjJBo65w+51+N85SR6K2vRxY1usKC1lE=)
  - nativeBuildInputs: emscripten + cmake + gnumake + jq
  - buildPhase: `cd js && make Imaging.js Imaging.wasm`
    (`HOME` + `EM_CACHE` set in TMPDIR so emscripten's sysroot
    builds work in the sandbox — standard nixpkgs pattern for
    emcc-using derivations, see pkgs/top-level/emscripten-packages.nix)
  - installPhase: `install -m 644` the two output files

Closure cost: build-time only — `pkgs.emscripten` is ~3.6 GiB
(LLVM + toolchain). Runtime closure is just the two produced files,
nothing emscripten-shaped survives into the deployed dist.

`postInstall` in `fluffychat-web-fixed` now references
`${fluffychat-web-imaging}` for the install copies, replacing the
previous reference to the deleted `fluffychat-web-imaging-prebuilt`
runCommandLocal.

Verified the emscripten build runs cleanly against the Makefile:

  $ nix-build test-imaging-built.nix
  ...
  emcc -s MODULARIZE=1 -s ALLOW_MEMORY_GROWTH=1 -O3 --closure 1 ...
  cache:INFO: generating system library: sysroot/lib/.../libstubs.a ...
  cache:INFO: generating system library: sysroot/lib/.../libc.a ...
  cache:INFO: generating system library: sysroot/lib/.../libc++-noexcept.a ...
  cache:INFO: generating system library: sysroot/lib/.../libc++abi-noexcept.a ...
  make: Nothing to be done for 'Imaging.wasm'.
  buildPhase completed in 52 seconds
  /nix/store/x5ds7rkrgfgyy3gb1lk44ak8mkdvdx0p-fluffychat-web-imaging-0.4.0
  $ ls /nix/store/.../fluffychat-web-imaging-0.4.0/
  Imaging.js  Imaging.wasm
  $ stat -c '%s' .../Imaging.js .../Imaging.wasm
  9956
  67363

Matches the upstream prebuilt byte-counts (9936 + 67770 — small
delta from different emscripten / closure-compiler versions).
2026-05-31 11:36:46 +02:00
atlas
a11d508bee nix/hive-matrix: patch fluffychat-web dist to add native_executor.js + Imaging.{js,wasm} (#685)
mara on #685: "do the post build step. check if there are any more file
that should have been built." Investigated the full diff between
`pkgs.fluffychat-web` (nixpkgs's nix-built dist) and the upstream
prebuilt release tarball. **Three** files missing from the nix build:

1. `native_executor.js` — flutter web worker entry. Source is
   `web/native_executor.dart` in fluffychat. `flutter341.buildFlutterApplication`
   skips `web/*.dart` worker entries; needs a separate `dart compile js`
   pass. Solved by adding `pkgs.flutter341.dart` to nativeBuildInputs +
   `dart compile js` in postInstall.

2. `Imaging.js` (~10 KB) + `Imaging.wasm` (~67 KB) — emscripten-compiled
   C library from the `native_imaging` dart package (vendored by
   Famedly). The package ships only C source + a Makefile that builds
   them via `emcc`; the package does NOT ship prebuilt versions —
   they're expected to be built at install time. nixpkgs's flutter
   builder doesn't run that pipeline. Two paths considered:
   - run emcc at build time: +~600 MB of `pkgs.emscripten` closure
     for two files
   - vendor the prebuilt files from the upstream release tarball:
     same fluffychat release version → byte-identical output
   Chose vendoring (cheaper closure, same result). Pinned to
   `pkgs.fluffychat-web.version`-templated URL with sha256, so a
   version bump auto-fetches the matching prebuilt.

The single other missing file (`native_executor.js.deps`) is a Dart
build-metadata artefact, not used at runtime — ignored.

Mechanics: two new `let`-bindings in `nix/modules/hive-matrix.nix`:

- `fluffychat-web-imaging-prebuilt` — small `runCommandLocal` that
  fetches the upstream `fluffychat-web.tar.gz` and extracts just the
  two Imaging files. Hash pinned, URL templated on the nixpkgs
  fluffychat-web version.
- `fluffychat-web-fixed` — `pkgs.fluffychat-web.overrideAttrs` carrying
  forward the existing `--base-href "/matrix/"` override (#634) plus
  the new postInstall that runs `dart compile js` on
  `web/native_executor.dart` and installs the two Imaging files from
  the prebuilt derivation.

Then `services.hyperhive.matrix.gui.package`'s default flips from the
inline overrideAttrs to `fluffychat-web-fixed`.

Symptom this resolves: fluffychat-web's blank-page-after-load (#643)
caused by `main.dart.js` requesting `native_executor.js` and the SPA
runtime never booting. With `native_executor.js` present + the
gateway-side SPA-fallback fix (#684 making missing assets visible),
flutter's bootstrap completes and the login form is usable.

Verified `nix eval` produces a different derivation hash than the
unpatched `pkgs.fluffychat-web` (aag55wgh... vs ldgcxy50...),
confirming the override takes effect. Full closure build pending
operator deploy — local sandbox networking flaky.

Closes #685.
2026-05-31 11:36:46 +02:00
iris
1656b265ed dashboard #486: drop manager special-case + enable M0V3 picker for multi-select (mara on #695)
Two changes from mara's review:

1. drop the manager special-case. Both M0V3 affordances now apply
   regardless of whether the manager is in the selection; backend
   topology::set_parent refuses the manager move and the failure
   surfaces in the bulk-action error roll-up. Matches the #443 ST0P
   policy of 'don't pre-gate manager actions, let the backend speak'.

2. enable the M0V3 → <pick> picker for multi-select. Was single-agent
   only in v1. Picker now omits every selected agent itself plus the
   union of every selected agent's descendants (cycle-safe across the
   whole batch); on submit POSTs once per selected agent sequentially,
   same shape as the existing bulk-button loop. Confirm message +
   error roll-up adapt to selection size.

docs/web-ui.md updated to match.
2026-05-31 11:32:13 +02:00
iris
2950a7f9ee dashboard: selection-bar M0V3 affordances for re-parenting agents (#486)
Backend POST /api/topology/set-parent already shipped; the dashboard
was missing the operator surface to drive it. Adds two affordances
to the SW4RM tab's selection bar (alongside the existing R3ST4RT /
ST0P / ST4RT / R3BU1LD / DESTR0Y / PURG3 actions):

- '⇡ M0V3 → ROOT' (bulk): promote selected agents to top-level
  (parent=null). Disabled when all selected are already at root or
  the selection includes the manager (backend refuses anyway).

- '⇢ M0V3 → [pick]' (single-agent only): inline <select> dropdown
  + button pair. Dropdown lists every container that isn't the
  target nor a descendant of it (client-side BFS via the existing
  c.parent map). On submit POSTs form-encoded
  'child=<name>&new_parent=<target>' to /api/topology/set-parent;
  the backend re-checks the cycle invariant and re-emits a
  container snapshot so the tree repaints without a reload.

Both POSTs hit a single URL, so addBulkButton grew an optional
'perAgentBodyFor(name)' hook to handle the body-driven endpoint
shape (vs the URL-suffix /start/<name> shape every other action
uses). Lifecycle endpoints unchanged.

Mauve chrome (var(--mauve)) reads as 'structural change' rather
than the destructive red / amber of destroy / rebuild.

closes #486
2026-05-31 11:32:13 +02:00
iris
b714ba15c2 harness: drop trailing /bin from systemd path entries so wrapper sudo resolves (#672 fixup)
systemd.services.<name>.path appends /bin to each entry, so the
literal '/run/wrappers/bin' here was being expanded to
'/run/wrappers/bin/bin' inside the unit's PATH — a path that
doesn't exist. 'which sudo' then fell back to
'/run/current-system/sw/bin/sudo' (the non-setuid nix-store binary)
and refused with 'must be owned by uid 0 and have the setuid bit
set' on every agent, despite hyperhive.user.passwordlessSudo = true.

Verified on this container post-rebuild:
  PATH includes /run/wrappers/bin/bin (non-existent)
  /run/wrappers/bin/sudo exists with mode r-s--x--x (real setuid)
  but `sudo` resolves to /run/current-system/sw/bin/sudo and fails.

Fix: drop the trailing /bin from both entries. systemd appends it.

The /run/current-system/sw entry was already correctly
expanding to /run/current-system/sw/bin (because of the same
auto-append), which is why everything else on PATH worked despite
the broken wrappers entry — only sudo (the one binary that needs
the wrapper dir) was affected.
2026-05-31 11:29:18 +02:00
lexis
ed59cb0660 docs: remove stale Wake-agent-only note after #698 (follow-up to #693) 2026-05-31 10:27:25 +02:00
damocles
b257f861db docs: fix hivectl --password example to include a value (argus on #696) 2026-05-31 10:27:08 +02:00
damocles
a4cd0518a0 harness: enable hive wake on manager role (#693) 2026-05-31 10:20:15 +02:00
damocles
d8cd3ef68c docs: post-#598 catch up — hive-ag3nt/hive-m1nd → unified hive binary in turn-loop.md + CLAUDE.md 2026-05-31 10:14:20 +02:00
damocles
fcb5fae345 docs: catch up post-#658/#604/#660 + add operator hivectl section (#124) 2026-05-31 10:13:33 +02:00
damocles
022afc794b harness: clear stale needs-login sentinel on healthy boot (#682) on unified binary 2026-05-31 03:25:26 +02:00
damocles
dcaf1838e1 harness: unify hive-ag3nt + hive-m1nd into one binary picking role from HIVE_ROLE (#598) 2026-05-31 03:21:06 +02:00
damocles
843ad32e5a Cargo.lock: bump 24 patch-level deps (#680) 2026-05-31 02:44:22 +02:00
iris
1a236a4119 harness: clear stale needs-login sentinel on healthy boot (#682)
The mara: 'many agents stuck at needs login? seem to do turns fine, no
needs login on agent page. dash shows needs login tho'.

Diagnosed: hive-ag3nt::events::Bus::emit_status writes
{state_dir}/hyperhive-needs-login when status flips to needs_login_idle
and only removes it when status flips to online. But the boot flow only
emits 'online' if the harness was previously parked in wait_for_login —
the LoginState::Online branch went straight into serve() without
touching emit_status. So a sentinel written on a prior boot (e.g. a
401-triggered park) survived a healthy re-spawn, and the dashboard's
auth_failed_sentinel(name) read it as still-needing-login forever after.

Fix: add bus.emit_status('online') at the top of the LoginState::Online
boot branch in both hive-ag3nt.rs (sub-agent) and hive-m1nd.rs (manager).
Idempotent — emit_status is a one-line write/remove on a tiny empty
file; calling it for an already-clean state is a no-op.

This addresses one half of #682. The other half (claude_has_session()
may EACCES on the agent's 0700-perm ~/.claude dir post-#658 root drop)
is c0re-side and tracked separately in the issue thread for damocles.

refs #682
2026-05-31 01:39:56 +02:00
atlas
6d886da19f nix/hive-gateway: stop SPA fallback from masking missing /matrix/ assets (#643)
iris's diagnosis on #643 (mara's fluffychat-web login attempt): the gateway's
`/matrix/` location used

    try_files $uri $uri/ /matrix/index.html;

which silently returned `index.html` (Content-Type: text/html, status 200) for
ANY missing path under `/matrix/`, including static assets like
`native_executor.js`. flutter's bootstrap requested that JS file, got HTML back,
failed to load the JS runtime, and the page rendered blank without any visible
error in the browser console.

(Confirmed root cause for the missing file itself: the upstream `fluffychat-web`
dist in nixpkgs ships `native_executor.dart` but no compiled `native_executor.js`,
even though `main.dart.js` references the latter. That's a separate
fluffychat-web packaging issue — tracked separately; this PR fixes only the
gateway-side masking that hides such failures.)

Replaces the inline `try_files` fallback with a named-location fallback that
distinguishes between route-shaped URIs (no extension) and asset-shaped URIs
(any `.<ext>` suffix):

    location /matrix/ {
      alias <pkg>/;
      try_files $uri $uri/ @matrix_spa_fallback;
    }

    location @matrix_spa_fallback {
      if ($uri ~ "\.[A-Za-z0-9]+$") {
        return 404;
      }
      rewrite ^ /matrix/index.html last;
    }

Routes still fall back to `index.html` so SPA client-side routing keeps
working; missing assets now surface a real 404 so flutter (and the operator's
devtools) can see the failure.

Verified the rendered nginx location attr via
`nix eval .#nixosConfigurations.* .... locations."@matrix_spa_fallback".extraConfig`.
2026-05-31 01:35:17 +02:00
iris
f05be94587 frontend: npm dependency updates (#681)
Bumps:
- marked       4.3.0  → 18.0.4  (agent + dashboard)
- chart.js     4.4.4  → 4.5.1   (agent stats page)
- esbuild      0.25.5 → 0.28.0  (workspace devDep)

marked v18 still ships a synchronous `marked.parse(text)` + `marked.setOptions({})`,
so our `mdNode()` call sites in dashboard/common.js and agent/app.js work
unchanged. `window.marked = marked` global bridge survives the bundler.
Verified end-to-end: `** strong **`, `[link](https://…)`, bullets, fenced
code blocks all render identically to v4. Agent app.js shrank ~15kb,
dashboard tabs.js shrank ~16kb (smaller marked + tighter esbuild).

chart.js 4.5.1 is patch-bump within the 4.x line — `new Chart(el, config)`
core API unchanged. esbuild 0.28.0 builds cleanly with our existing
build.mjs configurations.

`npm audit` reports 0 vulnerabilities. nix build passes; recomputed
npmDepsHash via `prefetch-npm-deps frontend/package-lock.json`.

closes #681
2026-05-31 01:29:35 +02:00
lexis
fab0e4804f docs: update harness-base/agent-base/manager.nix entries for hyperhive.role (#671) 2026-05-31 00:51:54 +02:00
damocles
ef968c11dd c0re: dedupe chown_to_agent into lifecycle (argus #678) 2026-05-31 00:40:40 +02:00
damocles
0cf703a939 c0re: chown per-agent state writes to agent uid:gid (#673) 2026-05-31 00:40:40 +02:00
atlas
d23fd8847d nix/templates: actually collapse agent-base + manager to role shims (#671 fixup)
The merge of #676 (commit 0951cd1) landed the role-driven harness service
in `harness-base.nix` but the rebase resolution accidentally kept the
legacy `systemd.services.hive-ag3nt` / `hive-m1nd` blocks in
agent-base.nix and manager.nix. Module merging silently accepts the
duplicate definitions because they evaluate to identical attrs — but
the whole point of #671 was to single-source the systemd unit + manager
forge defaults.

Collapses both templates to bare role-setters as originally intended:

    { ... }: {
      imports = [ ./harness-base.nix ];
      hyperhive.role = "agent";  # or "manager"
    }

Verified post-collapse:
- `nixosConfigurations.agent-base.config.systemd.services.hive-ag3nt
  .serviceConfig.ExecStart` -> `.../bin/hive-ag3nt serve`
- `nixosConfigurations.manager.config.systemd.services.hive-m1nd
  .serviceConfig.ExecStart` -> `.../bin/hive-m1nd serve`
- `agent-base` `.path` is `[ /run/wrappers/bin /run/current-system/sw ... ]`
- `manager` `.environment.HIVE_PORT` is `"8000"`

Follow-up to #671 (#676). No behaviour change — the duplicate
definitions were merging to the same values; this just deletes the
redundant copies so `harness-base.nix` is the true single source.
2026-05-31 00:07:55 +02:00
atlas
2e9c50ecc7 nix/harness-base: prepend /run/wrappers/bin to PATH (argus #676 / #672 fixup)
argus on #676 🔴: this PR deletes agent-base.nix + manager.nix and
moves the harness service to harness-base.nix without carrying
forward damocles's #672 fix (which adds `/run/wrappers/bin` to the
service PATH so the setuid sudo wrapper resolves before the bare
nix-store binary).

Pull the #672 fix forward: prepend `/run/wrappers/bin` to the unified
harness service's path list. Same shape as damocles's diff on
agent-base + manager, but applied once in harness-base.nix.

Without this, post-#658 `sudo` inside the container resolves to the
un-setuid nix-store binary and refuses with "must be owned by uid 0
and have the setuid bit set" even when
`hyperhive.user.passwordlessSudo = true` is configured.

Verified via `nix eval`:
- agent-base.systemd.services.hive-ag3nt.path[0] = "/run/wrappers/bin" ✓
- manager.systemd.services.hive-m1nd.path[0]    = "/run/wrappers/bin" ✓

#672 (damocles) supersedes when this lands — the two changes are
equivalent and the consolidated harness-base.nix is now the canonical
home for the fix.
2026-05-30 23:41:13 +02:00
atlas
0951cd1b3d nix/templates: merge manager + agent harness into harness-base.nix (#671)
mara on #671: "manager should not be as special anymore."

Single `harness-base.nix` now declares the harness systemd unit + the
manager-only forge defaults, driven by a new `hyperhive.role` option
(`"agent"` | `"manager"`, default `"agent"`). The two child templates
collapse to thin role-setters.

Mechanics:
- `hyperhive.role = "agent"` → `systemd.services.hive-ag3nt` running
  `hive-ag3nt serve`, default forge notification surface.
- `hyperhive.role = "manager"` → `systemd.services.hive-m1nd` running
  `hive-m1nd serve`, forge `keepSubscriptions = false` +
  `skipNotifyReasons = [ "subscribed" "participating" ]` (mentions-
  only inbox), plus standalone-eval fallbacks `HIVE_PORT = "8000"` +
  `HIVE_LABEL = "hm1nd"` (meta.rs overrides via the generated
  `applied/hm1nd/flake.nix`).

`agent-base.nix` (62 → 9 lines) and `manager.nix` (79 → 18 lines) are
now thin shims that just set the role and import `harness-base.nix`.

External surface unchanged: `nixosModules.{agent-base, manager}` +
`nixosConfigurations.{agent-base, manager}` still resolve identically.
meta.rs's role selection (`if isManager then hyperhive.nixosConfigurations.manager
else hyperhive.nixosConfigurations.agent-base`) keeps working without
edits.

Verified via `nix eval`:
- agent-base: role="agent", services=["hive-ag3nt"], forge.keepSubscriptions=true
- manager:    role="manager", services=["hive-m1nd"], forge.keepSubscriptions=false,
              forge.skipNotifyReasons=["subscribed","participating"],
              ExecStart=hive-m1nd/bin

Closes #671.
2026-05-30 23:41:13 +02:00
damocles
c73c8389ec harness: prepend /run/wrappers/bin to service path so sudo wrapper resolves (#658 fixup) 2026-05-30 23:40:16 +02:00
lexis
bee338cf4f docs: matrix serverName defaults to bare domain, not subdomain (follow-up to #661) 2026-05-30 23:39:37 +02:00
lexis
bed2eba52a docs: add hyperhive.user.name + passwordlessSudo to agent configuration (follow-up to #664) 2026-05-30 23:39:23 +02:00
damocles
2b46d0f3d7 CLAUDE.md: catch up daemon socket path to /run/hive-matrix/socket (argus #664) 2026-05-30 23:27:26 +02:00
damocles
97797cf790 hivectl: extend --password to forge; clarify matrix M_USER_IN_USE asymmetry (#663 / argus) 2026-05-30 23:27:26 +02:00
müde
8571e3243a c0re: chmod 0666 mcp.sock after bind so in-container agent user can connect (#658 fixup) 2026-05-30 23:15:16 +02:00