systemprompt_loader/
services_root.rs1use std::collections::BTreeMap;
17use std::path::PathBuf;
18use std::sync::OnceLock;
19
20use serde::{Deserialize, Serialize};
21
22static ACTIVE_ROOT: OnceLock<ActiveServicesRoot> = OnceLock::new();
23
24#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
25#[serde(tag = "kind", rename_all = "snake_case")]
26pub enum ServicesProvenance {
27 Bundled,
28
29 Fetched {
30 composed_hash: String,
31 versions: BTreeMap<String, String>,
32 },
33
34 LastGood {
35 composed_hash: String,
36 error: String,
37 },
38
39 BundledFallback {
40 error: String,
41 },
42}
43
44#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
45pub struct ActiveServicesRoot {
46 pub path: PathBuf,
47 pub base: PathBuf,
48 pub provenance: ServicesProvenance,
49}
50
51#[derive(Debug, Clone, Copy)]
52pub struct ServicesRootBootstrap;
53
54impl ServicesRootBootstrap {
55 pub fn install(root: ActiveServicesRoot) -> &'static ActiveServicesRoot {
56 ACTIVE_ROOT.get_or_init(|| root)
57 }
58
59 #[must_use]
60 pub fn get() -> Option<&'static ActiveServicesRoot> {
61 ACTIVE_ROOT.get()
62 }
63
64 #[must_use]
65 pub fn is_initialized() -> bool {
66 ACTIVE_ROOT.get().is_some()
67 }
68
69 #[must_use]
70 pub fn active_root_or(fallback: &str) -> PathBuf {
71 ACTIVE_ROOT
72 .get()
73 .map_or_else(|| PathBuf::from(fallback), |root| root.path.clone())
74 }
75
76 #[must_use]
77 pub fn active_path_or(fallback: &str, relative: &str) -> PathBuf {
78 Self::active_root_or(fallback).join(relative)
79 }
80}