diff --git a/CHANGELOG.md b/CHANGELOG.md index 57571881..2e640966 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,9 +13,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 robot glyph every unbranded agent shares, so a Pi tab was indistinguishable from an Aider or Qwen one in the sidebar, the tab chip and the tray menu. They now carry their own avatar on the existing sky accent, status dot unchanged. - Pi ships no symbol to transcribe, so the mark is tty7's own geometric Greek - pi, cut to the same 24x24 grid and stroke weight as the bundled brand marks — - nothing trademarked is vendored in. Restoring a Pi pane also resumes its + The mark is Pi's own, from pi.dev, rescaled to the same 24x24 grid as the + other bundled brand marks — its `prefers-color-scheme` stylesheet dropped, + since these avatars are tinted by the app. Restoring a Pi pane also resumes its conversation now: the tty7 extension reports Pi's session id, and the resume command is `pi --session ` (Pi's `--resume` is a boolean that only opens the interactive picker), with `--session` / `--session-id` / `--fork` / diff --git a/assets/icons/agents/pi.svg b/assets/icons/agents/pi.svg index bf6c98a5..89ed68a6 100644 --- a/assets/icons/agents/pi.svg +++ b/assets/icons/agents/pi.svg @@ -1,7 +1,11 @@ - + - + + diff --git a/src/ui/assets.rs b/src/ui/assets.rs index 9e2cdad9..43361596 100644 --- a/src/ui/assets.rs +++ b/src/ui/assets.rs @@ -185,10 +185,11 @@ fn agent_icon(path: &str) -> Option<&'static [u8]> { // silhouette, so this is lobehub/lobe-icons' square transcription (MIT), // drawn for exactly this avatar use. Its notice rides in the SVG. "icons/agents/grok.svg" => include_bytes!("../../assets/icons/agents/grok.svg"), - // The one mark that isn't a vendor's at all: Pi ships no symbol to - // transcribe, so this is tty7's own geometric Greek pi, cut to the same - // 24x24 grid and stroke weight as the rest of the row. The letter is not - // a trademark, so nothing is borrowed here. + // Pi's own mark, from pi.dev — the one file that arrives with theme + // logic attached (`logo-auto.svg` carries a `prefers-color-scheme` + // style block). The geometry is kept as published and rescaled to the + // 24x24 grid; the CSS is dropped, since these avatars are tinted by the + // app and no other mark here brings a stylesheet. Details in the SVG. "icons/agents/pi.svg" => include_bytes!("../../assets/icons/agents/pi.svg"), _ => return None, }; diff --git a/src/ui/tray/icon.rs b/src/ui/tray/icon.rs index ae11b045..a32ea73b 100644 --- a/src/ui/tray/icon.rs +++ b/src/ui/tray/icon.rs @@ -339,11 +339,17 @@ mod tests { assert_ne!(normal.data, attention.data); } - /// The avatar renders for a branded agent, an unbranded (bot-fallback) - /// agent, and with/without the status dot. + /// Every avatar renders, with and without the status dot. Run over the + /// whole roster rather than one branded and one fallback agent, because + /// this is the only test that puts the bundled SVGs through resvg: the + /// asset-source test next door proves the bytes resolve, not that they + /// parse into visible geometry. Vendor marks arrive in whatever shape the + /// vendor publishes — stylesheets, nested groups, features usvg quietly + /// drops — and a mark that parses to nothing shows up as a bare accent + /// disc, which nothing else here would catch. #[test] fn agent_avatar_renders_brand_and_fallback() { - for agent in [CLIAgent::Claude, CLIAgent::Qwen] { + for agent in CLIAgent::ALL { let idle = agent_avatar(agent, AgentStatus::Idle).unwrap(); let waiting = agent_avatar(agent, AgentStatus::Waiting).unwrap(); assert_eq!((idle.width(), idle.height()), (32, 32)); @@ -351,6 +357,22 @@ mod tests { assert_eq!(idle.pixel(0, 0).unwrap().alpha(), 0); // …and the center is covered (disc + glyph). assert!(idle.pixel(16, 16).unwrap().alpha() > 0); + // The glyph actually drew something. The disc under it is a flat + // accent fill, so every opaque pixel shares one colour unless the + // white mark landed on top — one colour means resvg handed back an + // empty canvas, which is what a silently-unsupported SVG feature + // looks like from here. + let shades: std::collections::HashSet<_> = idle + .pixels() + .iter() + .filter(|p| p.alpha() == 0xFF) + .map(|p| (p.red(), p.green(), p.blue())) + .collect(); + assert!( + shades.len() > 1, + "{} rendered as a bare disc — its glyph drew nothing", + agent.display_name() + ); // The status dot changes the bottom-right corner. assert_ne!(idle.data(), waiting.data()); }