from __future__ import annotations import os import tempfile import unittest from pathlib import Path # 本模块测试按 web 模式布局推断 skills 目录,需在导入 config 前设定模式。 os.environ["TERMINAL_SANDBOX_MODE"] = "web" from modules.skills_manager import ( archive_skill_directory, get_skills_catalog, infer_private_skills_dir, sync_workspace_skills, validate_skill_directory, ) class SkillsManagerTest(unittest.TestCase): def test_validate_skill_directory_requires_skill_md_and_frontmatter_fields(self): with tempfile.TemporaryDirectory() as tmp: root = Path(tmp) skill_dir = root / "sample-skill" skill_dir.mkdir() missing_file = validate_skill_directory(skill_dir) self.assertFalse(missing_file.get("success")) self.assertEqual(missing_file.get("error"), "缺少 SKILL.md") (skill_dir / "SKILL.md").write_text("---\nname: Sample\n---\n", encoding="utf-8") missing_description = validate_skill_directory(skill_dir) self.assertFalse(missing_description.get("success")) self.assertEqual(missing_description.get("error"), "缺少 description:") (skill_dir / "SKILL.md").write_text( "---\nname: Sample\ndescription: Demo skill\n---\n", encoding="utf-8", ) valid = validate_skill_directory(skill_dir) self.assertTrue(valid.get("success")) self.assertEqual(valid.get("skill_name"), "sample-skill") def test_archive_skill_directory_moves_without_overwriting(self): with tempfile.TemporaryDirectory() as tmp: root = Path(tmp) skill_dir = root / "sample-skill" target_root = root / "agentskills" skill_dir.mkdir() (skill_dir / "SKILL.md").write_text( "---\nname: Sample\ndescription: Demo skill\n---\n", encoding="utf-8", ) archived = archive_skill_directory(skill_dir, target_root) self.assertTrue(archived.get("success")) self.assertFalse(skill_dir.exists()) self.assertTrue((target_root / "sample-skill" / "SKILL.md").exists()) duplicate_src = root / "sample-skill" duplicate_src.mkdir() (duplicate_src / "SKILL.md").write_text( "---\nname: Sample\ndescription: Demo skill\n---\n", encoding="utf-8", ) duplicate = archive_skill_directory(duplicate_src, target_root) self.assertFalse(duplicate.get("success")) self.assertEqual(duplicate.get("error"), "目标 skill 已存在") def test_private_skills_are_cataloged_and_synced(self): with tempfile.TemporaryDirectory() as tmp: root = Path(tmp) global_root = root / "global" private_root = root / "users" / "jojo" / "agentskills" data_dir = root / "users" / "jojo" / "data" project = root / "project" private_skill = private_root / "private-skill" private_skill.mkdir(parents=True) data_dir.mkdir(parents=True) project.mkdir(parents=True) (private_skill / "SKILL.md").write_text( "---\nname: Private Skill\ndescription: Private demo\n---\n", encoding="utf-8", ) self.assertEqual(infer_private_skills_dir(data_dir), private_root.resolve()) catalog = get_skills_catalog(base_dir=str(global_root), private_dir=private_root) self.assertEqual([item["id"] for item in catalog], ["private-skill"]) synced = sync_workspace_skills( project, enabled_skills=["private-skill"], base_dir=str(global_root), private_dir=private_root, ) self.assertTrue(synced.get("success")) self.assertTrue((project / ".astrion" / "skills" / "private-skill" / "SKILL.md").exists()) if __name__ == "__main__": unittest.main()