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