rss-cli 0.2.0

An AI-friendly, cache-backed RSS / Atom / JSON Feed CLI that also runs as an MCP server
Documentation
//! Runtime parameters and policies — the *non-serialized* counterpart to [`crate::model`].

use std::time::Duration;

use chrono::{DateTime, Utc};

use crate::model::ContentFormat;

/// Default User-Agent. Polite, identifies the tool, points at the project.
pub const DEFAULT_USER_AGENT: &str = concat!(
    "rss-cli/",
    env!("CARGO_PKG_VERSION"),
    " (+https://github.com/AnderEnder/rss-cli)"
);

/// How the cache should be consulted for a fetch.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum CachePolicy {
    /// Default. Always revalidate with a conditional GET (`If-None-Match` /
    /// `If-Modified-Since`); a `304` serves the cached body.
    #[default]
    Revalidate,
    /// Serve directly from cache without hitting the network if the cached entry is
    /// younger than this duration; otherwise behave like [`CachePolicy::Revalidate`].
    MaxAge(Duration),
    /// Serve the cached entry **without any network call, regardless of age**, if one
    /// exists; only on a cache miss does it fetch (then behave like [`CachePolicy::Revalidate`]).
    /// Used by item lookup (`rss show` / MCP `get_item`) so a rolled feed window cannot evict
    /// an item the caller already saw. Exception to the always-revalidate default — see
    /// ADR-0014.
    CacheFirst,
    /// Ignore the cache entirely (do not read or write it).
    NoCache,
}

/// Parameters shared by the CLI and the MCP server for a fetch operation.
#[derive(Debug, Clone)]
pub struct FetchParams {
    pub content_format: ContentFormat,
    /// Maximum items per feed (most recent first), or `None` for all.
    pub limit: Option<usize>,
    /// Maximum characters of extracted `content` per item; longer bodies are truncated on a
    /// char boundary and flagged `content_truncated`. `None` keeps full content.
    pub max_content_chars: Option<usize>,
    /// Only include items published at or after this instant.
    pub since: Option<DateTime<Utc>>,
    /// Maximum number of feeds fetched concurrently.
    pub concurrency: usize,
    pub timeout: Duration,
    pub user_agent: String,
    pub cache_policy: CachePolicy,
}

impl Default for FetchParams {
    fn default() -> Self {
        Self {
            content_format: ContentFormat::Markdown,
            limit: None,
            max_content_chars: None,
            since: None,
            concurrency: 8,
            timeout: Duration::from_secs(30),
            user_agent: DEFAULT_USER_AGENT.to_string(),
            cache_policy: CachePolicy::Revalidate,
        }
    }
}