app

Local-first trade for farms and co-ops
git clone https://radroots.dev/git/app.git
Log | Files | Refs | README | LICENSE

commit eabed322efbe6f51fd208490d64b43aff401e493
parent 6fc713dff551151fc696d129312a990deac24860
Author: triesap <tyson@radroots.org>
Date:   Fri, 17 Apr 2026 17:00:06 +0000

core: add runtime snapshot boundary

- add shared runtime, build, and host metadata structs in radroots_app_core
- capture host locale and run identity in a shared startup snapshot for the launcher
- add launch startup event scaffolding and core tests for snapshot metadata
- retarget desktop locale selection and app id wiring to the shared runtime snapshot

Diffstat:
Mcrates/launchers/desktop/src/app.rs | 23++++++++++++++++++-----
Mcrates/shared/core/src/lib.rs | 11+++++++++--
Acrates/shared/core/src/runtime.rs | 232+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acrates/shared/core/src/startup.rs | 71+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mcrates/shared/i18n/src/lib.rs | 15---------------
5 files changed, 330 insertions(+), 22 deletions(-)

diff --git a/crates/launchers/desktop/src/app.rs b/crates/launchers/desktop/src/app.rs @@ -1,6 +1,6 @@ use gpui::{AppContext, Application, WindowOptions, px, size}; -use radroots_app_core::APP_ID; -use radroots_app_i18n::select_locale_for_process; +use radroots_app_core::{APP_PROJECTION_SOURCE, AppBuildIdentity, AppRuntimeSnapshot}; +use radroots_app_i18n::select_locale_from_host; use radroots_app_ui::{APP_UI_THEME, PlaceholderView}; fn titlebar_options() -> gpui::TitlebarOptions { @@ -12,10 +12,11 @@ fn titlebar_options() -> gpui::TitlebarOptions { } pub fn launch() { + let snapshot = AppRuntimeSnapshot::capture(build_identity()); let app = Application::new(); - app.run(|cx| { - select_locale_for_process(); + app.run(move |cx| { + select_locale_from_host(&snapshot.host.host_locale); cx.on_window_closed(|cx| { if cx.windows().is_empty() { @@ -24,10 +25,11 @@ pub fn launch() { }) .detach(); + let snapshot = snapshot.clone(); cx.spawn(async move |cx| { cx.open_window( WindowOptions { - app_id: Some(APP_ID.to_owned()), + app_id: Some(snapshot.host.app_identifier.clone()), window_min_size: Some(size( px(APP_UI_THEME.windows.home_min_width_px), px(APP_UI_THEME.windows.home_min_height_px), @@ -45,3 +47,14 @@ pub fn launch() { .detach(); }); } + +fn build_identity() -> AppBuildIdentity { + AppBuildIdentity { + package_name: env!("CARGO_PKG_NAME").to_owned(), + package_version: env!("CARGO_PKG_VERSION").to_owned(), + build_profile: option_env!("PROFILE").unwrap_or("debug").to_owned(), + target_triple: option_env!("TARGET").unwrap_or("unknown-target").to_owned(), + projection_source: APP_PROJECTION_SOURCE.to_owned(), + git_commit: option_env!("RADROOTS_GIT_COMMIT").map(str::to_owned), + } +} diff --git a/crates/shared/core/src/lib.rs b/crates/shared/core/src/lib.rs @@ -1,4 +1,11 @@ #![forbid(unsafe_code)] -pub const APP_ID: &str = "org.radroots.app"; -pub const APP_NAME: &str = "radroots"; +mod runtime; +mod startup; + +pub use runtime::{ + APP_ID, APP_NAME, APP_PLATFORM_RUNTIME, APP_PROJECTION_SOURCE, APP_RUNTIME_ORIGIN, + AppBuildIdentity, AppCoreRuntimeMetadata, AppHostRuntimeMetadata, AppRuntimeCapture, + AppRuntimeMode, AppRuntimeSnapshot, runtime_mode_label, +}; +pub use startup::{AppStartupEvent, AppStartupEventMetadata, launch_startup_event}; diff --git a/crates/shared/core/src/runtime.rs b/crates/shared/core/src/runtime.rs @@ -0,0 +1,232 @@ +use std::time::{SystemTime, UNIX_EPOCH}; + +pub const APP_ID: &str = "org.radroots.app"; +pub const APP_NAME: &str = "radroots"; +pub const APP_PLATFORM_RUNTIME: &str = "app-desktop-gpui"; +pub const APP_PROJECTION_SOURCE: &str = "gpui-native"; +pub const APP_RUNTIME_ORIGIN: &str = "gpui://localhost"; +pub const APP_HOST_PLATFORM: &str = "desktop"; + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum AppRuntimeMode { + Development, + Production, +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct AppBuildIdentity { + pub package_name: String, + pub package_version: String, + pub build_profile: String, + pub target_triple: String, + pub projection_source: String, + pub git_commit: Option<String>, +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct AppCoreRuntimeMetadata { + pub package_name: String, + pub package_version: String, + pub package_authors: String, + pub rust_edition: String, + pub rust_toolchain: String, +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct AppHostRuntimeMetadata { + pub app_identifier: String, + pub app_name: String, + pub app_version: String, + pub app_build: String, + pub platform_name: String, + pub operating_system: String, + pub host_locale: String, + pub runtime_origin: String, +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct AppRuntimeCapture { + pub host_locale: String, + pub operating_system: String, + pub run_id: String, +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct AppRuntimeSnapshot { + pub title: String, + pub runtime_mode: AppRuntimeMode, + pub run_id: String, + pub core: AppCoreRuntimeMetadata, + pub build: AppBuildIdentity, + pub host: AppHostRuntimeMetadata, +} + +impl AppRuntimeCapture { + pub fn current(mode: &AppRuntimeMode) -> Self { + Self { + host_locale: detect_host_locale(), + operating_system: std::env::consts::OS.to_owned(), + run_id: build_run_id(mode), + } + } +} + +impl AppRuntimeSnapshot { + pub fn capture(build: AppBuildIdentity) -> Self { + let mode = parse_runtime_mode(&build.build_profile); + Self::from_capture(build, mode, AppRuntimeCapture::current(&mode)) + } + + pub fn from_capture( + build: AppBuildIdentity, + runtime_mode: AppRuntimeMode, + capture: AppRuntimeCapture, + ) -> Self { + let app_version = build.package_version.clone(); + let app_build = build + .git_commit + .clone() + .unwrap_or_else(|| build.build_profile.clone()); + + Self { + title: APP_NAME.to_owned(), + runtime_mode, + run_id: capture.run_id, + core: AppCoreRuntimeMetadata { + package_name: env!("CARGO_PKG_NAME").to_owned(), + package_version: env!("CARGO_PKG_VERSION").to_owned(), + package_authors: env!("CARGO_PKG_AUTHORS").to_owned(), + rust_edition: "2024".to_owned(), + rust_toolchain: env!("CARGO_PKG_RUST_VERSION").to_owned(), + }, + build, + host: AppHostRuntimeMetadata { + app_identifier: APP_ID.to_owned(), + app_name: APP_NAME.to_owned(), + app_version, + app_build, + platform_name: APP_HOST_PLATFORM.to_owned(), + operating_system: capture.operating_system, + host_locale: capture.host_locale, + runtime_origin: APP_RUNTIME_ORIGIN.to_owned(), + }, + } + } +} + +pub fn runtime_mode_label(mode: &AppRuntimeMode) -> &'static str { + match mode { + AppRuntimeMode::Development => "development", + AppRuntimeMode::Production => "production", + } +} + +fn parse_runtime_mode(build_profile: &str) -> AppRuntimeMode { + match build_profile.trim() { + "release" => AppRuntimeMode::Production, + _ => AppRuntimeMode::Development, + } +} + +fn detect_host_locale() -> String { + [ + std::env::var("LC_ALL").ok(), + std::env::var("LC_MESSAGES").ok(), + std::env::var("LANGUAGE").ok(), + std::env::var("LANG").ok(), + ] + .into_iter() + .flatten() + .find_map(|value| { + let trimmed = value.trim(); + if trimmed.is_empty() { + None + } else { + Some(trimmed.to_owned()) + } + }) + .unwrap_or_else(|| "en".to_owned()) +} + +fn build_run_id(mode: &AppRuntimeMode) -> String { + let started_at_ms = SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap_or_default() + .as_millis(); + format!( + "run-{}-{started_at_ms}-pid{}", + runtime_mode_label(mode), + std::process::id() + ) +} + +#[cfg(test)] +mod tests { + use super::{ + APP_HOST_PLATFORM, APP_ID, APP_NAME, APP_PROJECTION_SOURCE, APP_RUNTIME_ORIGIN, + AppBuildIdentity, AppRuntimeCapture, AppRuntimeMode, AppRuntimeSnapshot, + runtime_mode_label, + }; + + fn test_build_identity() -> AppBuildIdentity { + AppBuildIdentity { + package_name: "radroots_app".to_owned(), + package_version: "0.1.0".to_owned(), + build_profile: "debug".to_owned(), + target_triple: "aarch64-apple-darwin".to_owned(), + projection_source: APP_PROJECTION_SOURCE.to_owned(), + git_commit: Some("deadbeefcafefeed".to_owned()), + } + } + + #[test] + fn runtime_snapshot_surfaces_core_and_host_metadata() { + let snapshot = AppRuntimeSnapshot::from_capture( + test_build_identity(), + AppRuntimeMode::Development, + AppRuntimeCapture { + host_locale: "en_US.UTF-8".to_owned(), + operating_system: "macos".to_owned(), + run_id: "run-development-123-pid456".to_owned(), + }, + ); + + assert_eq!(snapshot.title, APP_NAME); + assert_eq!(snapshot.run_id, "run-development-123-pid456"); + assert_eq!(snapshot.core.package_name, "radroots_app_core"); + assert_eq!(snapshot.core.package_version, env!("CARGO_PKG_VERSION")); + assert_eq!(snapshot.core.package_authors, env!("CARGO_PKG_AUTHORS")); + assert_eq!(snapshot.core.rust_edition, "2024"); + assert_eq!(snapshot.core.rust_toolchain, env!("CARGO_PKG_RUST_VERSION")); + assert_eq!(snapshot.build.package_name, "radroots_app"); + assert_eq!(snapshot.build.target_triple, "aarch64-apple-darwin"); + assert_eq!(snapshot.host.app_identifier, APP_ID); + assert_eq!(snapshot.host.app_name, APP_NAME); + assert_eq!(snapshot.host.app_version, env!("CARGO_PKG_VERSION")); + assert_eq!(snapshot.host.app_build, "deadbeefcafefeed"); + assert_eq!(snapshot.host.platform_name, APP_HOST_PLATFORM); + assert_eq!(snapshot.host.operating_system, "macos"); + assert_eq!(snapshot.host.host_locale, "en_US.UTF-8"); + assert_eq!(snapshot.host.runtime_origin, APP_RUNTIME_ORIGIN); + } + + #[test] + fn runtime_snapshot_falls_back_to_build_profile_when_git_commit_is_missing() { + let mut build = test_build_identity(); + build.git_commit = None; + build.build_profile = "release".to_owned(); + + let snapshot = AppRuntimeSnapshot::from_capture( + build, + AppRuntimeMode::Production, + AppRuntimeCapture { + host_locale: "en".to_owned(), + operating_system: "linux".to_owned(), + run_id: "run-production-123-pid456".to_owned(), + }, + ); + + assert_eq!(snapshot.host.app_build, "release"); + assert_eq!(runtime_mode_label(&snapshot.runtime_mode), "production"); + } +} diff --git a/crates/shared/core/src/startup.rs b/crates/shared/core/src/startup.rs @@ -0,0 +1,71 @@ +use crate::runtime::{AppRuntimeSnapshot, runtime_mode_label}; + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct AppStartupEvent { + pub category: &'static str, + pub name: &'static str, + pub message: &'static str, + pub metadata: AppStartupEventMetadata, +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct AppStartupEventMetadata { + pub home_screen: String, + pub core_package: String, + pub host_surface: String, + pub runtime_mode: String, +} + +pub fn launch_startup_event(snapshot: &AppRuntimeSnapshot) -> AppStartupEvent { + AppStartupEvent { + category: "bootstrap", + name: "runtime.launch", + message: "app launch", + metadata: AppStartupEventMetadata { + home_screen: snapshot.title.clone(), + core_package: snapshot.core.package_name.clone(), + host_surface: snapshot.host.platform_name.clone(), + runtime_mode: runtime_mode_label(&snapshot.runtime_mode).to_owned(), + }, + } +} + +#[cfg(test)] +mod tests { + use crate::{ + APP_PROJECTION_SOURCE, AppBuildIdentity, AppRuntimeCapture, AppRuntimeMode, + AppRuntimeSnapshot, + }; + + use super::launch_startup_event; + + #[test] + fn launch_startup_event_uses_runtime_snapshot_fields() { + let snapshot = AppRuntimeSnapshot::from_capture( + AppBuildIdentity { + package_name: "radroots_app".to_owned(), + package_version: "0.1.0".to_owned(), + build_profile: "debug".to_owned(), + target_triple: "aarch64-apple-darwin".to_owned(), + projection_source: APP_PROJECTION_SOURCE.to_owned(), + git_commit: None, + }, + AppRuntimeMode::Development, + AppRuntimeCapture { + host_locale: "en".to_owned(), + operating_system: "macos".to_owned(), + run_id: "run-development-123-pid456".to_owned(), + }, + ); + + let event = launch_startup_event(&snapshot); + + assert_eq!(event.category, "bootstrap"); + assert_eq!(event.name, "runtime.launch"); + assert_eq!(event.message, "app launch"); + assert_eq!(event.metadata.home_screen, "radroots"); + assert_eq!(event.metadata.core_package, "radroots_app_core"); + assert_eq!(event.metadata.host_surface, "desktop"); + assert_eq!(event.metadata.runtime_mode, "development"); + } +} diff --git a/crates/shared/i18n/src/lib.rs b/crates/shared/i18n/src/lib.rs @@ -46,21 +46,6 @@ pub fn select_locale_from_host(host_locale: &str) -> String { generated::set_locale(&locale).unwrap_or_else(|_| DEFAULT_LOCALE_ID.to_owned()) } -pub fn select_locale_for_process() -> String { - let host_locale = [ - std::env::var("LC_ALL").ok(), - std::env::var("LC_MESSAGES").ok(), - std::env::var("LANGUAGE").ok(), - std::env::var("LANG").ok(), - ] - .into_iter() - .flatten() - .find(|value| !value.trim().is_empty()) - .unwrap_or_else(|| DEFAULT_LOCALE_ID.to_owned()); - - select_locale_from_host(&host_locale) -} - fn normalize_host_locale(host_locale: &str) -> String { let trimmed = host_locale.trim(); if trimmed.is_empty() {