Extracts the app-launcher substance (desktop-entry parsing, fuzzy
matching/ranking, launch history, launching) out of breadbox into a
reusable ecosystem crate, so breadbar's future embedded capsule and
breadbox's overlay window can share one implementation instead of two
(THEME_SYSTEM_PLAN.md Phase 4/6a). The GTK4 results-list widget lives
behind a `gtk` feature, mirroring bread-theme's `gtk`/`adw` gating, so a
headless consumer isn't forced to link GTK.
Adds unit tests for fuzzy_score/matches_term/priority_rank, which were
previously untested pure functions inside breadbox's main.rs.
Implements the shell theme manifest layer from THEME_SYSTEM_PLAN.md
§4-5: ShellTheme/WindowSpec/Slots/Tokens/LayerRule types, TOML
discovery (user -> system -> compiled-in builtin), one level of
`extends` deep-merge, deny_unknown_fields validation naming the
offending key, slot module-name validation, and css() token
substitution with an extra.css overlay. load() never fails, falling
back to the compiled-in builtin and logging once.
Ships exactly one builtin manifest, liquid-motion, describing
breadbar/breadbox as they exist today (not the design-doc demo, which
disagrees with the code on bar side margin, launcher geometry, and the
easing curves). Compositor rules and surface specs are keyed by
layer-shell namespace and cover all five breadbar namespaces plus
breadbox/breadbar-panel/breadbar-dismiss.
watch() is gated behind the existing `gtk` feature (gio::FileMonitor
is a gtk4 dependency); the rest of the module is gtk-free so bread and
breadcrumbs can validate a theme without linking GTK. No consumer
changes — breadbar/breadbox still use their own hardcoded values.
bread-app is the GTK bootstrap new tools should use instead of another
copied main.rs: com.breadway.* app id, singleton lock, optional
gtk_popup re-export, optional bread.command.<app>.** listen loop.
Tests cover app-id helpers and command-verb parse. Existing apps are
not migrated.
bread-polkit is an own PolicyKit1 session authentication agent with a
bread-theme GTK4 password prompt (not a polkit-gnome wrapper).
Autostart via contrib/bread-polkit.desktop or exec-once. Not a bakery
product; not added to the BOS ISO lockfile.
Default remains ~/.local. Setting prefix=/usr/local (via
/etc/bakery/config.toml or BAKERY_PREFIX) installs bins and share
under that prefix and systemd user units under /usr/lib/systemd/user.
Writes that need root use sudo -n, then pkexec. State stays per-user.
bakery --version is compiled from workspace.package.version; bakery list
reports the git tag. Those must match at tag time. 0.7.2 is unreleased
work after v0.7.1 — no tag in this commit.
cargo test --workspace failed to link bread-onnx's own unit tests
(undefined symbol OrtGetApiBase) because nothing in this workspace
supplies an ort backend — that's deliberately left to each downstream
consumer app (breadarr, breadmill, breadpad) in their own repos. None
of bread-onnx's unit tests actually open an ONNX session, so enabling
ort's load-dynamic feature as a dev-dependency (unifies into this
crate's own test builds only, never into downstream consumers) is
enough to satisfy the linker without requiring a real onnxruntime.
New CLI surface, approved for review before merge:
- search <query>: case-insensitive name/description substring match
- completions <shell>: bash/zsh/fish/elvish/powershell via clap_complete
- rollback <pkg>: restore the previously installed version from a local
pre-update binary backup (not a network re-fetch — index.json's minisign
signature only covers the current published version, so pinning an old
version from the server would only be checkable against its unsigned
per-version .sha256 sidecar, a materially weaker trust path)
- verify [pkg]: recompute installed binaries' sha256 and compare against
the hash recorded at install time, not a fresh index lookup (the index
only has the latest release's checksum, which may not match what's
actually installed)
- remove --purge: additionally remove the license dir, desktop entry, and
data dir, each gated through the existing confirm() prompt; config is
still deliberately left alone
- self-update: documented entry point for updating bakery itself
- --dry-run: global flag, short-circuits right before install::
install_package in both the install and update paths
- download progress: chunked read loop in manifest::fetch_bytes prints
periodic \r progress on stderr when Content-Length is present and stderr
is a tty
- update --all output: "already at X" is now DIM with a neutral glyph
instead of GREEN, plus a bold one-line summary count, so unchanged
packages don't visually compete with ones that actually changed
InstalledPackage gained previous_version and binary_sha256 (both
#[serde(default)]) to back rollback/verify. fetch_and_place now returns the
verified sha256 instead of discarding it.
Also fixes a handful of pre-existing clippy lints in files this touches
(manual split_once, &PathBuf-vs-&Path, derivable Default, unnecessary
unwrap) surfaced by a clippy version newer than when that code was last
touched — confirmed via git stash that they predate this branch. bread-
utils has one more of these (suspicious_open_options in singleton.rs) left
alone: the mechanical fix would truncate the PID file before the
lock-held-by-another-process branch reads its contents, which would break
toggle_or_kill's PID lookup, so cargo clippy -p bakery needs --no-deps
until that one's fixed with actual thought.
Track switches now always take effect on `update --all` instead of
silently no-op'ing or permanently refusing on strict semver comparison.
`remove` no longer aborts cleanup on the first failed binary removal,
orphaning the systemd unit. State reads/writes are now lock-protected
and go through fsync'd atomic writes (also fixes a temp-path collision
in binary installs). The index loader falls back to a stale-but-signed
cache instead of hard-failing offline. systemd units now re-fetch on
every update instead of freezing after first install. `doctor` now
flags missing recorded binaries.
Security hardening: path-traversal guard on all index-controlled
filenames, archive extraction now rejects symlink/traversal entries
before tar touches disk, archive temp files use secure unique paths,
post_install hooks are gated behind --no-hooks/confirmation, response
buffering is capped, empty-checksum downloads get a clear error, and
both stable-track CI workflows now hard-fail on a missing signing key
(matching the existing dev/rc guard) instead of silently publishing an
index next to a stale signature. gen-index.sh now publishes the index
and its signature atomically.
Also: bakery install on an already-installed package no longer
silently reinstalls/downgrades, cmd_update exits non-zero for unknown
packages, and the unused toml dependency is removed.
New `adw` feature (gated separately from `gtk`, since AdwApplicationWindow
isn't compatible with gtk4-layer-shell — the five panel/launcher apps stay
on plain `gtk`, only breadman/breadhelp-style plain-window apps want this):
preferences_group/toggle_row/spin_row/action_row/preferences_page, wrapping
libadwaita's PreferencesGroup/SwitchRow/SpinRow/ActionRow/PreferencesPage.
adw::init() also forces dark color-scheme, since bread-theme's whole design
is a fixed dark base regardless of system GTK preference.
These directly target defects a design critique found: hand-rolled
switch+label rows with no intrinsic width (breadman/settings' ~1400px
stretched toggles) and spinners stranded far from their label — both just
don't happen when the row is a real AdwSwitchRow/AdwSpinRow instead of a
box assembled from scratch.
Also, two shared-stylesheet fixes usable by every app immediately, gtk
feature only:
- `scale` (slider) had no rule at all, so every volume/brightness slider
showed GTK's own default blue instead of the palette accent — the same
critique flagged breadbar's control-panel sliders contradicting its own
on-brand OSD fill two clicks away.
- A new `chip()`/`set_chip_active()` helper in gtk.rs uses the existing
(already-tokenized, already-defined) `.chip`/`.pill` stylesheet rule
instead of each app hand-rolling its own filter-chip CSS — which is how
breadclip/breadpad/breadman ended up with three different, mutually
disagreeing pill fills for what's supposed to be one shared component.
A solid background can't reveal whether a surface that's supposed to be
translucent (breadbox/breadclip/breadsearch's full-screen overlay
windows, breadbar's alpha-blended notification/OSD surfaces) is actually
compositing as translucent — a flat color showing through a flat color
still just looks flat. Generates a diagonal rainbow gradient (full hue
sweep, via the `image` crate) sized exactly to the capture canvas and
sets it as Sway's output background instead.
Needed installing swaybg (the external helper Sway's `output ... bg`
config directive shells out to) — without it the bg command silently
no-ops and the canvas stays black, which is why the first attempt at
this looked identical to the old flat-color version.
New bread-screenshots crate captures a layer-shell surface (by namespace+pid,
to disambiguate from an already-running instance) or the whole focused
output via grim, using bread-utils::hypr/proc. bread-utils::Monitor gains a
scale field and logical_size() so output geometry accounts for HiDPI/
transform, matching breadshot's proven math. bread-utils::hypr gains
find_layer() over hyprctl layers -j.
bread-capture is a small orchestrator that drives an app's --screenshot mode
and collects the resulting PNGs; hardcoded to breadbar's two views for now.
Adds a track concept to bakery (separate from the existing bakery/pacman
distribution channel): stable (unchanged tag-triggered releases), beta
(deliberate beta-v* tag promotion), and dev (published on every push to
dev). Each track gets its own signed index + artifact tree under
dl.breadway.dev so stable's paths and existing installs are untouched.
- bakery: new Track type, a global track preference in installed.json
(defaults to stable via serde, no migration needed), `bakery track
show`/`set`, a BAKERY_INDEX_BASE_URL override for testing, and a real
semver comparison in `update` (was a plain string-equality check before).
ANSI-colored/aligned CLI output (TTY + NO_COLOR aware).
- gen-index.sh: TRACK env var selects which subtree to read/write.
- CI: dev-bakery.yml/beta-bakery.yml/dev-bread-theme.yml/beta-bread-theme.yml
publish those two products on the new tracks; dev/beta skip the GitHub
Release upload step (no per-commit release spam).
- docs/release-channels.md documents the three-track policy.
The old bakery-signing-key.minisign-sec on hestia was password-encrypted
and the password was lost, so scripts/gen-index.sh never actually signed
index.json (silent no-op warning). bakery/src/manifest.rs (0.3.0+) hard-
requires that signature, so every bakery command has been failing with
'fetching index.json.minisig — the index must be signed before it can be
trusted' since the signing enforcement shipped.
Generated a new no-password minisign keypair on hestia
(~/.secrets/bakery-signing-key-2.minisign-sec), updated the hardcoded
PUBKEY in manifest.rs and get.sh to match, wired
BAKERY_MINISIGN_SEC_KEY_PATH as a Forgejo Actions secret so future CI
releases sign automatically, and manually signed+published the current
index.json on hestia so bakery works immediately.
bread-utils extracts genuinely duplicated logic found across breadbox,
breadclip, breadmon, breadcrumbs, bos-settings, and breadhelp:
- hypr: Hyprland socket1 request/response client (breadbox's
get_active_workspace + breadclip's position.rs hyprctl_json were
near-identical), socket2 path resolution (breadmon), and a
version-tolerant `fullscreen` field parser (Hyprland has shipped both
bool and int representations across versions).
- singleton: correct flock-based single-instance toggle, replacing the
TOCTOU-prone read-pid/check-proc/kill/write-pid pattern duplicated
verbatim between breadbox and breadclip (breadclip's own comment says
"matches breadbox pattern").
- proc: breadcrumbs' timeout-guarded subprocess runner, promoted verbatim
as the one implementation in the ecosystem that already got this right.
- atomic + xdg: atomic (temp-then-rename) file writes with an optional
.bak-before-overwrite variant, and XDG path helpers that never fall back
to a literal "~/..." string (the exact breadclip-core and
breadpad-shared bug: PathBuf never expands `~`).
- tomlcfg (feature "toml"): the load_doc/save_doc TOML-editing discipline
bos-settings and breadhelp both implemented byte-for-byte identically in
the same fix pass that introduced it.
- gtk_popup (feature "gtk"): layer-shell overlay window setup, visible-row
navigation, and click-outside-close, deduplicated from breadbox and
breadclip (~150 duplicated lines, per both apps' own "same as breadbox"
comments).
bread-onnx extracts the embedding pipeline (tokenize -> tensor build ->
mean-pool -> L2-normalize) duplicated near-verbatim between breadarr and
breadsearch, a shared execution-provider session builder with loud EP-
registration logging, and a model download+integrity helper. Defaults AMD
iGPU acceleration to ort::ep::MIGraphX (not ROCm) per this machine's own
breadsearch-gpu-backends lesson: ROCMExecutionProvider silently no-ops to
CPU on distro ROCm onnxruntime builds compiled with --use_migraphx.
Both crates build and pass their own test suites standalone. Consumer
migrations follow in subsequent commits.
- Add minisign-based signing/verification for the bakery index:
scripts/gen-index.sh signs index.json (MINISIGN_SEC_KEY env var, dormant
no-op with a loud warning until a key is provisioned); bakery/src/manifest.rs
fetches index.json.minisig and verifies it with minisign-verify against a
hardcoded PUBKEY before parsing/caching, and re-verifies the cached copy
on every load (falls back to one re-fetch if the cache predates signing
or fails verification; a fresh fetch that fails verification is a hard
error).
- Close the previously-unchecksummed config-example and systemd-unit
downloads in bakery/src/install.rs (scaffold_config, install_service):
index.json now carries `sha256`/`example_sha256` for these artifacts
(computed in gen-index.sh), verified via the same download::verify_sha256
used for binaries. Downloads without a matching sha256 in the index are
refused rather than installed unverified.
- scripts/get.sh now verifies the bakery release binary itself against a
pinned minisign public key before installing it (falls back to the
existing sha256-only check with a loud warning if no .minisig is
published yet or minisign isn't installed; a present-but-invalid
signature is a hard failure).
- Add dormant "sign release binary" steps to the bakery and bread-theme
release workflows (.github/workflows/release.yml,
.forgejo/workflows/release-bread-theme.yml), gated on secrets that are
not yet configured — binaries ship unsigned exactly as before until the
owner wires up the secret.
- .gitignore: add *.minisign-sec / minisign.key so the signing key can
never be committed by accident.
- bread-theme: fix stale docs describing a "Catppuccin Mocha fallback"
(BREAD_DESIGN_SYSTEM.md, README.md, Cargo.toml/bakery.toml/registry
descriptions) — the actual implementation (palette.rs) uses a fixed BOS
dark base with only accent colors from pywal.
- bread-theme: fix the legacy css_vars() path, which had its own
hand-written @define-color block that predated the `accent` and computed
`on-*` ink colors used by the rest of the stylesheet — any caller whose
CSS referenced those names against css_vars()'s output would hit
undefined colors (the illegible-text bug). css_vars() now delegates to
the same define_colors() the full stylesheet uses, so the two can't
drift apart again.
Critical fixes:
- gen-index.sh: emit services, config, optional_system_deps from bakery.toml;
parse product list from registry TOML instead of hardcoded array; fail loudly
when bakery.toml is missing (was silently producing empty metadata in prod)
- install.rs: download service units and example configs from dl server at
install time (were never fetched); check systemctl exit codes (were swallowed);
save state before file cleanup in remove_package (was inconsistent on error)
- doctor.rs: rewrite dep detection to use `pacman -Q` as primary (no more
dependency on `which` or pkg-config name mismatches); add optional_system_deps
support returning (missing, warnings) — warnings print but never block install
- get.sh: fix GitHub fallback URL (was 404 for both latest and versioned
releases); add SHA-256 checksum verification using published .sha256 file
High priority fixes:
- bakery doctor <unknown-pkg>: exit non-zero (was silently passing)
- bakery update: add --all flag (documented in README but missing from CLI);
add doctor gate before update (was bypassing dep check)
- bread_deps: now resolved recursively with cycle detection (was ignored)
- manifest.rs: add artifact_urls() helper and optional_system_deps field
- state.rs: atomic save via tmp+rename; cmd_info shows optional_system_deps
Tests: 17 new unit tests across doctor, download, install, state modules;
scripts/test-gen-index.sh fixture test for full pipeline