Files
LLeMbas-Desktop/src-tauri/build.rs
T
HomerandClaude Opus 5.5 96a2abe7e0 One window, the app's own page; the server through /api/v2
The two webviews (local title bar, remote web UI) become one WebviewWindow on
ui/index.html. The window refuses every navigation but the app's page and its
sealed frames; the capability still names only main and no remote URL.

- server.rs: discovery refuses a server older than 2.0 (protocol 3 and major
  version 2) and an app API newer than this app knows; the app's own device
  login for the app scope, the token kept in account.json (0600) and never
  given to the page; a proxy limited to /api/v2 paths; the SSE stream.
- files.rs: list and read the agent's working directory, resolved (links and
  .. included) and refused outside the agent's folders.
- sealed.rs: HTML for the viewer on its own scheme under the server's sealed
  policy: no bridge, no network, no navigation.
- watch.rs + tauri-plugin-notification: a notification when a reply or an
  agent chat finishes out of sight.
- A failed start and panics go to desktop.log; a missing tray no longer stops
  the app; the DMA-BUF renderer is off under NVIDIA's driver.
- The unstable multiwebview feature, the gtk dependency and the theme report
  are gone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 04:55:03 +00:00

73 lines
3.0 KiB
Rust

//! Besides Tauri's own build step: the two themes' page colour, which the window itself paints
//! before the page has (so a dark theme does not start white), read out of `ui/tokens.css` (the server's tokens, fetched by `scripts/fetch-tokens.sh`) into
//! `$OUT_DIR/tokens.rs`, so no colour is written in Rust. `lib.rs` includes that file.
use std::env;
use std::fs;
use std::path::Path;
/// The themes the app knows, by the name `tokens.css` selects them with (`data-theme`), and the
/// Rust names the constants get.
const THEMES: [(&str, &str); 2] = [("moria", "MORIA"), ("shire", "SHIRE")];
/// The tokens taken from each theme, by the custom property and the constant's suffix.
const TOKENS: [(&str, &str); 1] = [("--bg", "BG")];
fn main() {
let tokens = Path::new("../ui/tokens.css");
println!("cargo:rerun-if-changed={}", tokens.display());
let css = fs::read_to_string(tokens)
.unwrap_or_else(|e| panic!("{}: {e}; run scripts/fetch-tokens.sh", tokens.display()));
let mut out = String::from(
"// Generated by build.rs from ui/tokens.css: the colours the window paints itself.\n",
);
for (theme, name) in THEMES {
let block = theme_block(&css, theme).unwrap_or_else(|| {
panic!("ui/tokens.css has no `:root[data-theme=\"{theme}\"]` block")
});
for (token, suffix) in TOKENS {
let (r, g, b) = hex_token(block, token).unwrap_or_else(|| {
panic!(
"ui/tokens.css: `{token}` of the {theme} theme is not a six-digit hex colour"
)
});
out.push_str(&format!(
"pub const {name}_{suffix}: (u8, u8, u8) = (0x{r:02X}, 0x{g:02X}, 0x{b:02X});\n"
));
}
}
let dest = Path::new(&env::var("OUT_DIR").expect("OUT_DIR")).join("tokens.rs");
fs::write(&dest, out).expect("write tokens.rs");
tauri_build::build()
}
/// The declarations of the theme's block: from the selector naming it (at the start of a line,
/// so a mention in a comment does not count) to the block's closing brace at the start of a
/// line, which is the file's own layout, one block per theme.
fn theme_block<'a>(css: &'a str, theme: &str) -> Option<&'a str> {
let selector = format!("\n:root[data-theme=\"{theme}\"]");
let at = css.find(&selector)?;
let open = at + css[at..].find('{')?;
let close = open + css[open..].find("\n}")?;
Some(&css[open + 1..close])
}
/// `--token: #RRGGBB;` in the block, as bytes.
fn hex_token(block: &str, token: &str) -> Option<(u8, u8, u8)> {
let value = block
.lines()
.map(str::trim)
.find_map(|l| {
l.strip_prefix(token)
.and_then(|r| r.trim_start().strip_prefix(':'))
})?
.trim()
.trim_end_matches(';')
.trim();
let hex = value.strip_prefix('#')?;
if hex.len() != 6 {
return None;
}
let byte = |i: usize| u8::from_str_radix(&hex[i..i + 2], 16).ok();
Some((byte(0)?, byte(2)?, byte(4)?))
}