The /api/v1/admin endpoint only returns the /64 subnet. Users were
copy-pasting the subnet straight into Compose Message and getting
HTTP 422 from the daemon (\"invalid IP address syntax\"). The full
host part (lower 64 bits) is logged once at boot:
INFO mycelium: Node overlay IP: 43d:956e:7877:d933:eecc:b305:21ff:77f9
Capture it from stdout, surface as a new daemonStatus.overlayIp
field, and render it on Status above the subnet card with the hint
\"use this when sending messages\".
The line carries ANSI colour escapes from tracing's compact format,
so push_log strips SGR sequences before scanning. Hand-rolled to
avoid pulling a regex crate.
Also rebuilds the .deb release artifact.
dpkg-deb -c on the bundled .deb shows mycelium at /usr/bin/mycelium
(no triple suffix), next to the app launcher. Our previous resolver
only looked for the suffixed dev name in resource_dir, so the
installed app could not find its sidecar.
Probe order is now: directory of current_exe, then resource_dir,
then CARGO_MANIFEST_DIR/binaries, then $PATH, with both the plain
"mycelium" name and the dev-style "mycelium-<triple>" alias
checked at each location.
Even with --api-addr set, mycelium also opens an internal JSON-RPC
endpoint on 127.0.0.1:8990 by default (visible in --debug as
\"Starting JSON-RPC server listen_addr=127.0.0.1:8990\"). When a
previous run left an orphan mycelium running as root — which we
can't SIGKILL from a user-level Child::kill_on_drop — the new
instance fails to bind 8990 and exits ~10s after startup, with no
sidecar://exited event because the kill never landed.
Pin --metrics-api-address to a fresh ephemeral port alongside the
other three. Known limitation: stopping the daemon still doesn't
reliably kill the root child; the user has to `sudo pkill mycelium`
between runs. Will be addressed by an elevated-shutdown hook.
mycelium defaults --tcp-listen-port and --quic-listen-port to 9651
when not provided. If anything else holds 9651 (a previous test
instance, a Docker container from the level-1 procedure, another
mycelium running on the host), the daemon comes up far enough to
serve the loopback API for a few seconds before tearing itself
down on the listen failure.
Pick three distinct ephemeral ports (api, tcp, quic) per spawn.
Trade-off: inbound peers need the actual port number, which we
already log; the user can pin via a future SidecarConfig field.
Backend
- sidecar.rs supervises the bundled `mycelium` binary launched via
pkexec; locates it in resource_dir or CARGO_MANIFEST_DIR/binaries
matching $TAURI_ENV_TARGET_TRIPLE
- ephemeral port via portpicker, key + config persisted in
app_data_dir, kill_on_drop with explicit start_kill on stop
- health-check loop calls /api/v1/admin until 2xx (timeout 20s);
emits sidecar://ready and sidecar://exited
- 500-line ring buffer of stdout/stderr surfaced via sidecar_logs
command for the upcoming Settings page
- elevation::is_auth_failure(126|127) maps pkexec cancel to a
dedicated AppError variant
- AppError uses thiserror, Serialize impl renders messages as
plain strings for the JS side
Frontend
- typed `api` wrapper around invoke() in src/lib/api.ts
- node store (Pinia) bootstraps on mount, listens on
sidecar://ready and sidecar://exited
- StartupOverlay covers the whole window for idle/starting/error
phases; sidebar status dot + start/stop button
- Status view renders subnet, pubkey, api endpoint and key path
with one-click clipboard copy