Skip to main content

Mountain/ProcessManagement/
ExtractDevTag.rs

1//! Cocoon stdout-line inspector. Detects the `[DEV:<TAG>]` prefix written by
2//! `Cocoon/Source/Services/DevLog.ts::CocoonDevLog` and returns the lower-
3//! cased tag for dispatch into Mountain's per-tag `dev_log!` sinks. Returns
4//! `None` for bare stdout so the caller falls back to the catch-all `cocoon`
5//! tag.
6
7pub fn Fn(Line:&str) -> Option<String> {
8	let Stripped = Line.strip_prefix("[DEV:")?;
9
10	let (TagUpper, _Rest) = Stripped.split_once(']')?;
11
12	if TagUpper.is_empty() {
13		return None;
14	}
15
16	// Reject anything that isn't a simple tag ident - prevents stray
17	// `[DEV: something with space]` headers from being treated as tags.
18	if !TagUpper.chars().all(|C| C.is_ascii_uppercase() || C == '-' || C == '_') {
19		return None;
20	}
21
22	Some(TagUpper.to_ascii_lowercase())
23}
24
25#[cfg(test)]
26mod Tests {
27
28	use super::Fn;
29
30	#[test]
31	fn StripsKnownTag() {
32		assert_eq!(
33			Fn("[DEV:BOOTSTRAP-STAGE] [Bootstrap] stage=Environment event=start"),
34			Some("bootstrap-stage".to_string())
35		);
36	}
37
38	#[test]
39	fn RejectsPlainText() {
40		assert_eq!(Fn("plain stdout line"), None);
41	}
42
43	#[test]
44	fn RejectsMalformed() {
45		assert_eq!(Fn("[DEV: BOOT] x"), None);
46
47		assert_eq!(Fn("[DEV:]"), None);
48
49		assert_eq!(Fn("[DEV:BOOT"), None);
50	}
51}