ensure_core_profiles() was unconditionally backfilling home/work/away
into the in-memory config on every load, even when the user had
already defined their own profiles (e.g. Home/Away/School). This
showed up as duplicate/phantom lowercase entries in `breadcrumbs
profile list`, and downstream in breadbar and bos-settings.
Now the self-heal only fires when the profile set is completely
empty (a genuinely fresh or corrupted config), never padding an
existing customized set.
"(exit: , optional)" printed with nothing after the colon whenever no
Tailscale exit node was configured (the default). Now renders "none",
and relabels "exit:" to "exit node:" -- the abbreviated form read as an
exit *code* at a glance, which is what led to this being misdiagnosed
as a process-exit-code formatting bug in the first place.
graphical-session.target ships RefuseManualStart=yes and BOS has no
session manager to activate it properly (the same issue worked around
for breadclipd) - breadcrumbs doesn't need a Wayland session anyway,
so default.target avoids the problem entirely.
breadcrumbs had a watch subcommand meant to run continuously but no
systemd unit anywhere, so bakery installs never actually started it -
Wi-Fi profile config in bos-settings had no daemon consuming it.
GitHub Actions self-hosted runners need per-repo registration on a
personal account; Forgejo Actions' runner already serves every repo
with zero setup. Moves release publishing there (dl.breadway.dev stays
the primary bakery target; GitHub release upload is kept as the
fallback via an explicit token, since Forgejo Actions has no ambient
GITHUB_TOKEN) and adds a mirror workflow to keep GitHub in sync
automatically.
Features:
- Introduce a Backend trait + System impl so flow/status/watch can be unit
tested against a fake; add 11 connect-state-machine tests.
- Captive-portal detection: status::connectivity returns Online/Portal/Offline;
surfaced in status, JSON, connect notes, and a dedicated watch state.
- `status --json` for bars/scripts; `profile add`/`profile remove`; detect now
scores by number of in-range markers.
Robustness:
- Pin LC_ALL=C/LANG=C on child processes for locale-independent parsing.
- Atomic config/state writes (temp + rename); 0600 config never world-readable.
- Transient PSK file written to $XDG_RUNTIME_DIR when available.
Fixes (from prior audit):
- Feed Wi-Fi PSK to nmcli via stdin/passwd-file, never argv.
- mask() no longer panics on multi-byte passwords.
- Connectivity check requires HTTP 204 (no captive-portal false positives).
- nmcli NAME,TYPE parsing handles escaped colons.
- Strip CIDR suffix from displayed IP; PKGBUILD/Cargo version aligned (2.1.0).
- packaging/arch/PKGBUILD: builds and publishes breadcrumbs to [breadway] repo
- .forgejo/workflows/mirror.yml: mirrors every push/tag to GitHub
- .forgejo/workflows/package.yml: builds on tag, publishes to Forgejo registry
Requires FORGEJO_TOKEN and GITHUB_MIRROR_TOKEN secrets in Forgejo.
Core WiFi management works without Tailscale. tailscale, sudo, and
xdg-utils are only needed for Tailscale login and URL-open features,
so they become optional (warn, don't block) instead of required.
- bakery.toml: describes breadcrumbs for bakery install
- release.yml: builds on hestia self-hosted runner, publishes binary to
dl.breadway.dev and GitHub Releases on v* tags
- flow.rs/nm.rs: connect_and_verify now returns Result<(), String> with
a descriptive error message instead of a bare bool