All checks were successful
check / check (push) Successful in 36s
The watch daemon publishes bread.crumbs.profile.changed and bread.crumbs.health.changed on real transitions (not every poll tick) and honors bread.command.crumbs.set_profile via the existing state::set_profile path. BreadClient is fail-silent: if breadd is down, breadcrumbs behaves exactly as before. Document the contract in EVENTS.md. CLAUDE.md now points at CONTRIBUTING (single-trunk, no three-branch model), bakery, and EVENTS.md.
53 lines
1.7 KiB
Rust
53 lines
1.7 KiB
Rust
use std::fs;
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
use crate::config::{state_dir, state_path, Config};
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct State {
|
|
pub profile: String,
|
|
#[serde(default)]
|
|
pub updated: String,
|
|
}
|
|
|
|
impl State {
|
|
pub fn load(default_profile: &str) -> State {
|
|
if let Ok(text) = fs::read_to_string(state_path()) {
|
|
if let Ok(s) = toml::from_str::<State>(&text) {
|
|
if !s.profile.is_empty() {
|
|
return s;
|
|
}
|
|
}
|
|
}
|
|
State {
|
|
profile: default_profile.to_string(),
|
|
updated: String::new(),
|
|
}
|
|
}
|
|
|
|
pub fn save(&self) -> Result<(), String> {
|
|
fs::create_dir_all(state_dir()).map_err(|e| format!("creating state dir: {e}"))?;
|
|
let text = toml::to_string_pretty(self).map_err(|e| format!("serializing state: {e}"))?;
|
|
fs::write(state_path(), text).map_err(|e| format!("writing state: {e}"))
|
|
}
|
|
}
|
|
|
|
/// Persist `name` as the active profile if it exists in `cfg`. Shared by the
|
|
/// CLI `profile set` path and `bread.command.crumbs.set_profile` so they
|
|
/// cannot drift. Does not run [`crate::flow::run`] — the CLI applies
|
|
/// afterwards unless `--no-apply`, and the watch daemon picks the new
|
|
/// profile up on its next tick.
|
|
pub fn set_profile(cfg: &Config, name: &str) -> Result<(), String> {
|
|
if !cfg.profiles.contains_key(name) {
|
|
let avail: Vec<&String> = cfg.profiles.keys().collect();
|
|
return Err(format!("unknown profile '{name}'. Available: {avail:?}"));
|
|
}
|
|
State {
|
|
profile: name.to_string(),
|
|
updated: crate::util::timestamp(),
|
|
}
|
|
.save()?;
|
|
crate::notify::log(&format!("profile set -> {name}"));
|
|
Ok(())
|
|
}
|