lifeloop-cli 0.1.1

Provider-neutral lifecycle abstraction and normalizer for AI harnesses
Documentation
//! Sentinel markers for Lifeloop managed sections inside model
//! instruction source files.
//!
//! The marker format is part of Lifeloop's public source-file contract.
//! Changing it is a wire-affecting change that must update
//! `tests/wire_contract.rs` and `tests/spec_alignment.rs` together with
//! the spec body.

/// Stable prefix for the begin marker. Followed by metadata key/value
/// pairs and the closing `-->`.
pub const BEGIN_PREFIX: &str = "<!-- LIFELOOP:BEGIN managed-section";

/// Stable closing marker. No metadata is carried on this line; the
/// begin marker is the source of truth.
pub const END_MARKER: &str = "<!-- LIFELOOP:END managed-section -->";

/// Metadata parsed from the begin marker.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct BeginMeta {
    pub template_version: u32,
    pub adapter_id: String,
}

/// Render the begin marker for a given (adapter, template_version) pair.
pub fn render_begin(adapter_id: &str, template_version: u32) -> String {
    format!("{BEGIN_PREFIX} v={template_version} adapter={adapter_id} -->",)
}

/// Parse a begin-marker line. Returns `None` if the line is not a
/// recognized begin marker. The parser is deliberately tolerant of
/// trailing whitespace and key order.
pub fn parse_begin(line: &str) -> Option<BeginMeta> {
    let trimmed = line.trim();
    let rest = trimmed.strip_prefix(BEGIN_PREFIX)?.trim();
    let body = rest.strip_suffix("-->")?.trim();
    let mut template_version: Option<u32> = None;
    let mut adapter_id: Option<String> = None;
    for token in body.split_whitespace() {
        let (key, value) = token.split_once('=')?;
        match key {
            "v" => {
                template_version = Some(value.parse().ok()?);
            }
            "adapter" => {
                adapter_id = Some(value.to_owned());
            }
            // Ignore unknown future keys to keep forward compatibility
            // tolerant; we never *write* unknown keys.
            _ => {}
        }
    }
    Some(BeginMeta {
        template_version: template_version?,
        adapter_id: adapter_id?,
    })
}

/// True when the line is a recognized end marker.
pub fn is_end(line: &str) -> bool {
    line.trim() == END_MARKER
}