oxios_kernel/skill/
format.rs1#![allow(missing_docs)]
2use std::path::Path;
5
6use serde::{Deserialize, Serialize};
7use serde_yaml::Value;
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
11#[serde(rename_all = "snake_case")]
12pub enum SkillFormat {
13 Oxios,
14 OpenClaw,
15 ClaudeCode,
16 AgentSkills,
17}
18
19impl std::fmt::Display for SkillFormat {
20 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
21 match self {
22 SkillFormat::Oxios => write!(f, "oxios"),
23 SkillFormat::OpenClaw => write!(f, "openclaw"),
24 SkillFormat::ClaudeCode => write!(f, "claude_code"),
25 SkillFormat::AgentSkills => write!(f, "agent_skills"),
26 }
27 }
28}
29
30pub fn detect_format(value: &Value) -> SkillFormat {
31 if let Some(meta) = value.get("metadata")
32 && (meta.get("openclaw").is_some()
33 || meta.get("clawdbot").is_some()
34 || meta.get("clawdis").is_some())
35 {
36 return SkillFormat::OpenClaw;
37 }
38 for key in &[
39 "allowed-tools",
40 "arguments",
41 "when_to_use",
42 "argument-hint",
43 "effort",
44 "hooks",
45 "paths",
46 ] {
47 if value.get(*key).is_some() {
48 return SkillFormat::ClaudeCode;
49 }
50 }
51 for key in &[
52 "requires",
53 "install",
54 "primaryEnv",
55 "primary-env",
56 "skillKey",
57 "skill-key",
58 ] {
59 if value.get(*key).is_some() {
60 return SkillFormat::Oxios;
61 }
62 }
63 SkillFormat::AgentSkills
64}
65
66pub fn resolve_format(value: &Value, skill_dir: &Path) -> SkillFormat {
67 if skill_dir.join(".clawhub").join("origin.json").exists() {
68 return SkillFormat::OpenClaw;
69 }
70 detect_format(value)
71}
72
73#[cfg(test)]
74mod tests {
75 use super::*;
76 #[test]
77 fn test_detect_oxios() {
78 let v: Value = serde_yaml::from_str("name: test\nrequires:\n bins:\n - git\n").unwrap();
79 assert_eq!(detect_format(&v), SkillFormat::Oxios);
80 }
81 #[test]
82 fn test_detect_openclaw() {
83 let v: Value = serde_yaml::from_str(
84 "name: test\nmetadata:\n openclaw:\n requires:\n env:\n - KEY\n",
85 )
86 .unwrap();
87 assert_eq!(detect_format(&v), SkillFormat::OpenClaw);
88 }
89 #[test]
90 fn test_detect_claude() {
91 let v: Value = serde_yaml::from_str("name: test\nallowed-tools: Read Grep\n").unwrap();
92 assert_eq!(detect_format(&v), SkillFormat::ClaudeCode);
93 }
94 #[test]
95 fn test_detect_standard() {
96 let v: Value = serde_yaml::from_str("name: test\ndescription: A skill\n").unwrap();
97 assert_eq!(detect_format(&v), SkillFormat::AgentSkills);
98 }
99}