use anyhow::{Context, Result, bail};
use std::fs;
use std::path::Path;
use super::schema::{DynamicState, StateSchema};
pub fn load_schema(path: &Path) -> Result<StateSchema> {
let content = fs::read_to_string(path)
.with_context(|| format!("Failed to read schema file: {:?}", path))?;
serde_json::from_str(&content).with_context(|| format!("Failed to parse schema: {:?}", path))
}
pub fn load_default_schema() -> Result<StateSchema> {
if let Ok(schema_path) = std::env::var("MX_STATE_SCHEMA") {
let path = std::path::PathBuf::from(&schema_path);
if path.exists() {
return load_schema(&path);
} else {
bail!(
"MX_STATE_SCHEMA points to non-existent file: {}",
schema_path
);
}
}
if let Ok(agent) = std::env::var("MX_CURRENT_AGENT")
&& let Some(home) = dirs::home_dir()
{
let agent_schema = home.join(format!(".{}/schemas/state.json", agent));
if agent_schema.exists() {
return load_schema(&agent_schema);
}
}
let locations = [
Some(crate::paths::schemas_dir().join("emotional-state.json")),
Some(std::path::PathBuf::from(
"/etc/mx/schemas/emotional-state.json",
)),
];
for loc in locations.into_iter().flatten() {
if loc.exists() {
return load_schema(&loc);
}
}
bail!(
"Could not find state schema. Tried:\n\
- MX_STATE_SCHEMA environment variable\n\
- MX_CURRENT_AGENT environment variable (looks for ~/.{{agent}}/schemas/state.json)\n\
- {}/emotional-state.json\n\
- /etc/mx/schemas/emotional-state.json",
crate::paths::schemas_dir().display()
)
}
pub fn parse_wake_preference_dynamic(line: &str, schema: &StateSchema) -> Result<DynamicState> {
let trimmed = line.trim();
if trimmed.starts_with(&schema.stele.header) {
return DynamicState::decode_stele(trimmed, schema);
}
let mode = if let Some(stripped) = trimmed.strip_prefix("Wake Preference:") {
stripped.trim()
} else if let Some(stripped) = trimmed.strip_prefix("Wake State:") {
stripped.trim()
} else {
trimmed
};
DynamicState::from_mode(mode, schema)
}