agent-berth 1.0.1

Monitor and resume coding agents
Documentation
use std::time::Duration;

use anyhow::{Context, Result, bail};

pub fn parse_duration(input: &str) -> Result<Duration> {
    let trimmed = input.trim();
    if trimmed.is_empty() {
        bail!("duration must not be empty");
    }
    let split = trimmed
        .char_indices()
        .find(|(_, ch)| !ch.is_ascii_digit() && *ch != '.')
        .map(|(i, _)| i)
        .unwrap_or(trimmed.len());
    let (number, unit) = trimmed.split_at(split);
    if number.is_empty() {
        bail!("duration {input:?} is missing a number");
    }
    let value: f64 = number
        .parse()
        .with_context(|| format!("invalid duration number in {input:?}"))?;
    if !value.is_finite() || value < 0.0 {
        bail!("duration {input:?} must be a finite non-negative number");
    }
    let factor = match unit.trim().to_ascii_lowercase().as_str() {
        "" | "s" | "sec" | "secs" | "second" | "seconds" => 1.0,
        "m" | "min" | "mins" | "minute" | "minutes" => 60.0,
        "h" | "hr" | "hrs" | "hour" | "hours" => 3600.0,
        "d" | "day" | "days" => 86400.0,
        other => bail!("unknown duration unit {other:?} in {input:?}"),
    };
    Ok(Duration::from_secs_f64(value * factor))
}

pub fn parse_idle(input: Option<&str>) -> Result<Option<Duration>> {
    input.map(parse_duration).transpose()
}

#[cfg(test)]
#[path = "duration_tests.rs"]
mod tests;