use crate::model::{NodeKind, ResourceKind};
use crate::path::RelPath;
pub const STATE_DIR: &str = ".agentlink";
pub const CONFIG_FILE: &str = ".agentlink/config.toml";
pub const LOCK_FILE: &str = ".agentlink/lock.toml";
pub const LOCAL_PROVIDERS_DIR: &str = ".agentlink/providers";
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Layout {
instructions: RelPath,
skills: RelPath,
}
impl Default for Layout {
fn default() -> Self {
Self {
instructions: RelPath::new("AGENTS.md").expect("valid default"),
skills: RelPath::new(".agents/skills").expect("valid default"),
}
}
}
impl Layout {
pub fn canonical(&self, kind: ResourceKind) -> &RelPath {
match kind {
ResourceKind::Instructions => &self.instructions,
ResourceKind::Skills => &self.skills,
}
}
pub fn node(&self, kind: ResourceKind) -> NodeKind {
kind.node()
}
pub fn seeds(&self) -> impl Iterator<Item = (ResourceKind, &RelPath)> {
ResourceKind::ALL
.iter()
.map(|&kind| (kind, self.canonical(kind)))
}
}
pub const AGENTS_MD_TEMPLATE: &str = "\
# AGENTS.md
Shared instructions for every AI coding agent working in this repository.
Managed with [agentlink](https://github.com/fialhosoft/agentlink) — edit this
file from any agent and the change is visible to all of them.
## Project
<!-- What this project is, in two or three sentences. -->
## Commands
<!-- Build, test and lint commands an agent should use. -->
## Conventions
<!-- Code style, patterns to follow, and anything that is off limits. -->
";
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn canonical_paths_match_the_ecosystem_standards() {
let layout = Layout::default();
assert_eq!(
layout.canonical(ResourceKind::Instructions).as_str(),
"AGENTS.md"
);
assert_eq!(
layout.canonical(ResourceKind::Skills).as_str(),
".agents/skills"
);
}
#[test]
fn every_resource_kind_has_a_seed() {
let layout = Layout::default();
assert_eq!(layout.seeds().count(), ResourceKind::ALL.len());
}
}