pub fn parse_kv_line(line: &str) -> Option<(String, String)> {
let trimmed = line.trim();
if trimmed.is_empty() || trimmed == "---" || trimmed.starts_with('#') {
return None;
}
let (raw_key, raw_value) = trimmed.split_once(':')?;
let key = raw_key.trim().to_ascii_lowercase();
if key.is_empty() {
return None;
}
let value = strip_one_quote_pair(raw_value.trim()).to_string();
Some((key, value))
}
fn strip_one_quote_pair(value: &str) -> &str {
let bytes = value.as_bytes();
if bytes.len() >= 2 {
let first = bytes[0];
let last = bytes[bytes.len() - 1];
if (first == b'"' && last == b'"') || (first == b'\'' && last == b'\'') {
return &value[1..value.len() - 1];
}
}
value
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parse_kv_normal() {
let (k, v) = parse_kv_line("name: engineer").unwrap();
assert_eq!(k, "name");
assert_eq!(v, "engineer");
}
#[test]
fn parse_kv_url_value() {
let (k, v) = parse_kv_line("repo: https://github.com/x/y").unwrap();
assert_eq!(k, "repo");
assert_eq!(v, "https://github.com/x/y");
}
#[test]
fn parse_kv_timestamp_value() {
let (k, v) = parse_kv_line("created: 2026-06-05T14:31:34").unwrap();
assert_eq!(k, "created");
assert_eq!(v, "2026-06-05T14:31:34");
}
#[test]
fn parse_kv_model_id_value() {
let (k, v) = parse_kv_line("model: bedrock/us.anthropic.claude-sonnet-4-6").unwrap();
assert_eq!(k, "model");
assert_eq!(v, "bedrock/us.anthropic.claude-sonnet-4-6");
}
#[test]
fn parse_kv_model_id_with_colon_in_value() {
let (k, v) = parse_kv_line("model: openrouter:gpt-4").unwrap();
assert_eq!(k, "model");
assert_eq!(v, "openrouter:gpt-4");
}
#[test]
fn parse_kv_strips_trailing_whitespace() {
let (k, v) = parse_kv_line(" role : engineer ").unwrap();
assert_eq!(k, "role");
assert_eq!(v, "engineer");
}
#[test]
fn parse_kv_strips_double_quotes() {
let (k, v) = parse_kv_line(r#"description: "Implements features.""#).unwrap();
assert_eq!(k, "description");
assert_eq!(v, "Implements features.");
}
#[test]
fn parse_kv_strips_single_quotes() {
let (k, v) = parse_kv_line("description: 'Implements features.'").unwrap();
assert_eq!(k, "description");
assert_eq!(v, "Implements features.");
}
#[test]
fn parse_kv_keeps_inner_escaped_quotes() {
let (k, v) = parse_kv_line(r#"initialprompt: "He said \"hi\"""#).unwrap();
assert_eq!(k, "initialprompt");
assert_eq!(v, r#"He said \"hi\""#);
}
#[test]
fn parse_kv_key_is_lower_cased() {
let (k, _) = parse_kv_line("Name: foo").unwrap();
assert_eq!(k, "name");
}
#[test]
fn parse_kv_empty_line_returns_none() {
assert!(parse_kv_line("").is_none());
assert!(parse_kv_line(" ").is_none());
}
#[test]
fn parse_kv_fence_returns_none() {
assert!(parse_kv_line("---").is_none());
assert!(parse_kv_line(" --- ").is_none());
}
#[test]
fn parse_kv_comment_returns_none() {
assert!(parse_kv_line("# this is a comment").is_none());
assert!(parse_kv_line(" # indented comment").is_none());
}
#[test]
fn parse_kv_malformed_no_colon_returns_none() {
assert!(parse_kv_line("not_a_kv_line").is_none());
}
}