Skip to main content

systemprompt_loader/
services_root.rs

1//! Process-wide cell holding the services root the instance actually runs.
2//!
3//! With no bundle sources configured the root is the tree baked into the
4//! image at `paths.services`. With sources it is a composed cache root, and
5//! [`ServicesProvenance`] records how that root was chosen — including the
6//! error that forced a fallback, so an instance running yesterday's bundle
7//! can say so rather than looking healthy.
8//!
9//! The cell is installed once, before [`crate::ConfigLoader`] reads anything;
10//! [`ServicesRootBootstrap::active_root_or`] is the accessor for callers that
11//! must work whether or not boot has reached that point yet.
12//!
13//! Copyright (c) systemprompt.io — Business Source License 1.1.
14//! See <https://systemprompt.io> for licensing details.
15
16use 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}