stakpak-ak 0.3.88

Agent knowledge store library
Documentation
use std::fmt::{Display, Formatter};
use std::path::PathBuf;

#[derive(Debug)]
pub enum Error {
    Io(std::io::Error),
    AlreadyExists(PathBuf),
    NotFound(PathBuf),
    NotADirectory(PathBuf),
    UnsafePath(PathBuf),
    Parse(String),
}

impl Display for Error {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::Io(error) => write!(
                f,
                "io error: {error}. check filesystem permissions, parent directories, and AK_STORE"
            ),
            Self::AlreadyExists(path) => write!(
                f,
                "path already exists: {}. choose a new path or overwrite intentionally",
                path.display()
            ),
            Self::NotFound(path) => write!(
                f,
                "path not found: {}. check that the path is relative to the store root",
                path.display()
            ),
            Self::NotADirectory(path) => {
                write!(f, "path is not a directory: {}", path.display())
            }
            Self::UnsafePath(path) => write!(
                f,
                "unsafe path blocked: {}. ak paths must stay inside the store and cannot pass through symlinks",
                path.display()
            ),
            Self::Parse(message) => write!(f, "invalid input: {message}"),
        }
    }
}

impl std::error::Error for Error {}

impl From<std::io::Error> for Error {
    fn from(value: std::io::Error) -> Self {
        Self::Io(value)
    }
}

#[cfg(test)]
mod tests {
    use super::Error;
    use std::path::PathBuf;

    #[test]
    fn not_found_error_explains_path_interpretation() {
        let error = Error::NotFound(PathBuf::from("/tmp/store/knowledge/missing.md"));
        let rendered = error.to_string();

        assert!(rendered.contains("path not found"));
        assert!(rendered.contains("check that the path is relative to the store root"));
    }

    #[test]
    fn already_exists_error_suggests_intentional_overwrite_or_new_path() {
        let error = Error::AlreadyExists(PathBuf::from("/tmp/store/knowledge/existing.md"));
        let rendered = error.to_string();

        assert!(rendered.contains("path already exists"));
        assert!(rendered.contains("choose a new path or overwrite intentionally"));
    }
}