diff --git a/src/ui/app.rs b/src/ui/app.rs index 92e10cb..62b0ece 100644 --- a/src/ui/app.rs +++ b/src/ui/app.rs @@ -1431,6 +1431,29 @@ impl App { self.rgp_portrait = crate::ui::rgp::load_portrait_glb(&assets); } + // Read the agent's last explicit atmosphere from + // system/preferences/visual.md and restore the chrome. The agent + // writes this when she uses the atmosphere tool; the TUI reads it + // at conversation start so her choice survives restarts. + let pref_path = repo.root().join("system").join("preferences").join("visual.md"); + if let Ok(content) = std::fs::read_to_string(&pref_path) { + if let Some(body) = content.strip_prefix("---\n") { + if let Some(end) = body.find("\n---\n") { + for line in body[..end].lines() { + if let Some((key, val)) = line.split_once(':') { + let key = key.trim(); + let val = val.trim().trim_matches('"'); + if key == "atmosphere" { + if let Some(atm) = crate::ui::atmosphere::Atmosphere::from_name(val) { + self.presence.transition_atmosphere(atm); + } + } + } + } + } + } + } + // Read energy balance from the agent's memfs. The file is written // by the backend after every turn (write_energy_balance in local.rs). // Parse the YAML frontmatter for generative/consumptive counts and diff --git a/src/ui/atmosphere.rs b/src/ui/atmosphere.rs index 8108f80..f8dfb6a 100644 --- a/src/ui/atmosphere.rs +++ b/src/ui/atmosphere.rs @@ -145,6 +145,29 @@ impl Atmosphere { } } + /// Parse an atmosphere from a preset name (case-insensitive, underscore-tolerant). + /// Returns `None` for unknown names and empty strings. + pub fn from_name(name: &str) -> Option { + let key = name.to_lowercase().replace(' ', "_"); + match key.as_str() { + "" | "default" => Some(Atmosphere::Default), + "mint_tea" => Some(Atmosphere::MintTea), + "therapeutic_blue" => Some(Atmosphere::TherapeuticBlue), + "lavender_calm" => Some(Atmosphere::LavenderCalm), + "warm_amber" => Some(Atmosphere::WarmAmber), + "peach_sunset" => Some(Atmosphere::PeachSunset), + "autumn_browns" => Some(Atmosphere::AutumnBrowns), + "neon_glow" => Some(Atmosphere::NeonGlow), + "aurora_borealis" => Some(Atmosphere::AuroraBorealis), + "cherry_blossom" => Some(Atmosphere::CherryBlossom), + "ocean_depths" => Some(Atmosphere::OceanDepths), + "midnight_galaxy" => Some(Atmosphere::MidnightGalaxy), + "twilight_mist" => Some(Atmosphere::TwilightMist), + "forest_greens" => Some(Atmosphere::ForestGreens), + _ => None, + } + } + /// Map a posture to a default atmosphere (when none is explicitly set). pub fn from_posture(posture: crate::ui::presence::Posture) -> Self { use crate::ui::presence::Posture;