Write a single ClawShell-managed skill bundle into ` /skills/ /` and return its manifest entry.
(
skill: onboard::OnboardSkillBundle,
openclaw_config_path: &Path,
)
| 132 | /// Write a single ClawShell-managed skill bundle into |
| 133 | /// `<openclaw_root>/skills/<skill_name>/` and return its manifest entry. |
| 134 | fn write_openclaw_skill_bundle( |
| 135 | skill: onboard::OnboardSkillBundle, |
| 136 | openclaw_config_path: &Path, |
| 137 | ) -> Result<WrittenOpenclawSkill, Box<dyn Error>> { |
| 138 | let openclaw_root = onboard::openclaw_config_root(openclaw_config_path); |
| 139 | let skill_dir = openclaw_root.join("skills").join(skill.name); |
| 140 | std::fs::create_dir_all(&skill_dir)?; |
| 141 | |
| 142 | let mut managed_files: Vec<(String, String)> = Vec::new(); |
| 143 | for file in skill.files { |
| 144 | let path = skill_dir.join(file.relative_path); |
| 145 | if let Some(parent) = path.parent() { |
| 146 | std::fs::create_dir_all(parent)?; |
| 147 | } |
| 148 | std::fs::write(path, &file.content)?; |
| 149 | managed_files.push((file.relative_path.to_string(), file.content)); |
| 150 | } |
| 151 | |
| 152 | let metadata = onboard::build_managed_skill_metadata(skill.name, &managed_files); |
| 153 | onboard::write_managed_skill_metadata(&skill_dir, &metadata)?; |
| 154 | let manifest_entry = onboard::build_managed_skill_manifest_entry(&skill_dir, &metadata); |
| 155 | |
| 156 | if !align_owner_with_openclaw_path(&skill_dir, openclaw_config_path)? { |
| 157 | warn!( |
| 158 | path = %skill_dir.display(), |
| 159 | openclaw_path = %openclaw_config_path.display(), |
| 160 | "Could not determine OpenClaw file owner while writing skill files; will retry later" |
| 161 | ); |
| 162 | } |
| 163 | |
| 164 | Ok(WrittenOpenclawSkill { |
| 165 | path: skill_dir, |
| 166 | manifest_entry, |
| 167 | }) |
| 168 | } |
| 169 | |
| 170 | /// Write every ClawShell-managed skill that applies to this onboarding |
| 171 | /// run into OpenClaw's skills directory. The stats skill is always |
no test coverage detected