- 工作区内部路径 .agents/ -> .astrion/ - 默认运行态数据根 ~/.agents/agents/ -> ~/.astrion/astrion/ - 环境变量 AGENTS_DATA_ROOT -> ASTRION_DATA_ROOT(无兼容) - 同步更新代码、测试、文档与脚本中的路径引用 - 新增 .gitignore 忽略 .astrion/ 与 .agents/ 运行态目录
102 lines
4.0 KiB
Python
102 lines
4.0 KiB
Python
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()
|