#![cfg(feature = "skills")]
#![allow(clippy::expect_used)]
use meerkat_contracts::{CapabilityStatus, available_capabilities, resolve_capabilities};
use meerkat_core::skills::{
CapabilityId, SkillEngine, SkillFilter, SkillKey, SkillName, SkillSource,
};
use meerkat_skills::{DefaultSkillEngine, EmbeddedSkillSource};
fn builtin_skill_key(slug: &str) -> SkillKey {
SkillKey::builtin(SkillName::parse(slug).expect("valid skill name"))
}
fn capability(slug: &str) -> CapabilityId {
CapabilityId::parse(slug).expect("valid capability")
}
async fn embedded_skill_names_with_capabilities(caps: &[&str]) -> Vec<String> {
let engine = DefaultSkillEngine::new(
EmbeddedSkillSource::new(),
caps.iter().map(|slug| capability(slug)).collect(),
);
engine
.list_skills(&SkillFilter::default())
.await
.expect("list embedded skills")
.into_iter()
.map(|skill| skill.key.skill_name.to_string())
.collect()
}
#[tokio::test]
async fn base_crate_registers_mob_communication_for_cross_surface_resume() {
let _ = meerkat::SESSION_VERSION;
let source = EmbeddedSkillSource::new();
let key = builtin_skill_key("mob-communication");
let result = source.load(&key).await;
assert!(
result.is_ok(),
"mob-communication should be registered from the base crate"
);
let Ok(skill) = result else {
unreachable!("asserted embedded mob communication skill is available above");
};
assert_eq!(
skill.descriptor.key.skill_name.as_str(),
"mob-communication"
);
assert_eq!(skill.descriptor.name, "mob-communication");
assert_eq!(
skill.descriptor.description,
"How to communicate with peers in a collaborative mob"
);
}
#[tokio::test]
async fn base_crate_registers_cli_reference_for_help_surface() {
let _ = meerkat::SESSION_VERSION;
let source = EmbeddedSkillSource::new();
let key = builtin_skill_key("meerkat-cli-reference");
let skill = source
.load(&key)
.await
.expect("meerkat-cli-reference should be registered from the base crate");
assert_eq!(skill.descriptor.key, key);
assert_eq!(skill.descriptor.name, "meerkat-cli-reference");
assert!(skill.body.contains("There is no `--tools all`"));
assert!(
skill
.body
.contains("rkat blob get <BLOB-ID> --output fox.png")
);
}
#[tokio::test]
async fn companion_skills_load_from_builtin_source_by_stable_slug() {
let _ = std::any::TypeId::of::<meerkat::WorkGraphService>();
let _ = std::any::TypeId::of::<meerkat::ScheduleService>();
let source = EmbeddedSkillSource::new();
let slugs = [
"task-workflow",
"shell-patterns",
"mob-communication",
"hook-authoring",
"workgraph-workflow",
"schedule-workflow",
"skill-discovery-workflow",
"builtin-utilities-workflow",
#[cfg(feature = "mcp")]
"mcp-server-setup",
#[cfg(feature = "comms")]
"multi-agent-comms",
#[cfg(feature = "memory-store-session")]
"memory-retrieval",
#[cfg(feature = "session-store")]
"session-management",
];
for slug in slugs {
let result = source.load(&builtin_skill_key(slug)).await;
assert!(
result.is_ok(),
"{slug} should load from builtin source: {result:?}"
);
let Ok(doc) = result else {
continue;
};
assert_eq!(doc.descriptor.key.skill_name.as_str(), slug);
}
}
#[tokio::test]
async fn companion_skills_are_listed_only_when_capabilities_are_available() {
let _ = std::any::TypeId::of::<meerkat::WorkGraphService>();
let _ = std::any::TypeId::of::<meerkat::ScheduleService>();
let without_caps = embedded_skill_names_with_capabilities(&[]).await;
assert!(!without_caps.iter().any(|name| name == "workgraph-workflow"));
assert!(!without_caps.iter().any(|name| name == "schedule-workflow"));
let workgraph_caps = embedded_skill_names_with_capabilities(&["work_graph"]).await;
assert!(
workgraph_caps
.iter()
.any(|name| name == "workgraph-workflow")
);
assert!(
!workgraph_caps
.iter()
.any(|name| name == "schedule-workflow")
);
let schedule_caps = embedded_skill_names_with_capabilities(&["schedule"]).await;
assert!(schedule_caps.iter().any(|name| name == "schedule-workflow"));
assert!(
!schedule_caps
.iter()
.any(|name| name == "workgraph-workflow")
);
}
#[test]
fn companion_skills_are_not_help_preloads() {
let preload = meerkat::help::platform_preload_skill_names();
assert!(!preload.iter().any(|name| name == "workgraph-workflow"));
assert!(!preload.iter().any(|name| name == "schedule-workflow"));
}
#[test]
fn skills_crate_registers_skills_capability_for_composed_runtime() {
let _ = meerkat::SESSION_VERSION;
let mut config = meerkat_core::Config::default();
assert!(
available_capabilities(&config).contains(&meerkat_contracts::CapabilityId::Skills),
"skills-enabled composed runtime should register the skills capability"
);
config.skills.enabled = false;
let skills_status = resolve_capabilities(&config)
.into_iter()
.find_map(|(registration, status)| {
(registration.id == meerkat_contracts::CapabilityId::Skills).then_some(status)
})
.expect("skills capability registration should exist");
assert!(matches!(
skills_status,
CapabilityStatus::DisabledByPolicy { .. }
));
}