use serde::Serialize;
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize)]
pub struct Cell {
pub status: NativeStatus,
pub note: &'static str,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize)]
#[serde(rename_all = "kebab-case")]
pub enum NativeStatus {
Native,
NotOffered,
Unadapted,
NonNative,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize)]
#[serde(rename_all = "kebab-case")]
pub enum McpMechanism {
ConfigKey,
NativeCommand,
Protocol,
Unsupported,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize)]
pub struct InteractionSurfaces {
pub serve: Cell,
pub sdk: Cell,
pub acp: Cell,
pub rpc: Cell,
pub cli: Cell,
pub pty: Cell,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize)]
pub struct McpRegistration {
pub mechanism: McpMechanism,
pub detail: &'static str,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize)]
pub struct ConfigLocations {
pub settings: &'static str,
pub hooks: &'static str,
pub permissions: &'static str,
pub model_catalog: &'static str,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize)]
pub struct AwpPrimitives {
pub model_selection: Cell,
pub effort: Cell,
pub session_open: Cell,
pub session_resume: Cell,
pub session_cancel: Cell,
pub streaming: Cell,
pub instruction_channel: Cell,
pub permission_modes: Cell,
pub skills: Cell,
pub hooks: Cell,
pub subagents: Cell,
pub plugins: Cell,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize)]
pub struct NativeCapability {
pub last_verified: &'static str,
pub surfaces: InteractionSurfaces,
pub mcp: McpRegistration,
pub config: ConfigLocations,
pub primitives: AwpPrimitives,
}
pub const fn cell(status: NativeStatus, note: &'static str) -> Cell {
Cell { status, note }
}
impl NativeCapability {
pub fn date_is_iso(&self) -> bool {
parse_iso_date(self.last_verified).is_some()
}
}
pub fn parse_iso_date(text: &str) -> Option<(i32, u32, u32)> {
let bytes = text.as_bytes();
if bytes.len() != 10 || bytes[4] != b'-' || bytes[7] != b'-' {
return None;
}
let year: i32 = text[..4].parse().ok()?;
let month: u32 = text[5..7].parse().ok()?;
let day: u32 = text[8..10].parse().ok()?;
if !(1..=12).contains(&month) || !(1..=31).contains(&day) {
return None;
}
Some((year, month, day))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn iso_date_parser_accepts_calendar_days() {
assert_eq!(parse_iso_date("2026-10-21"), Some((2026, 10, 21)));
assert!(parse_iso_date("2026-13-01").is_none());
assert!(parse_iso_date("yesterday").is_none());
}
}