import json from pathlib import Path from unittest.mock import Mock import pytest from artemis.integrations import codex_skill as integration @pytest.fixture def bundle(tmp_path, monkeypatch): root = tmp_path / "source" source = root / "skills" / "artemis-use" source.mkdir(parents=True) (source / "SKILL.md").write_text( "---\nname: artemis-use\ndescription: official\n---\n", "utf-8" ) (source / "references").mkdir() (source / "references" / "modes.md").write_text("official modes", "utf-8") codex_home = tmp_path / "用户配置" / ".codex" monkeypatch.setenv("CODEX_HOME", str(codex_home)) return root, source, codex_home def test_install_overwrites_entire_reserved_directory_and_is_noop_when_unchanged(bundle): root, source, home = bundle target = home / "skills" / "artemis-use" target.mkdir(parents=True) (target / "SKILL.md").write_text("unmanaged custom content", "utf-8") (target / "custom.txt").write_text("must be removed", "utf-8") unrelated = home / "skills" / "personal" / "SKILL.md" unrelated.parent.mkdir() unrelated.write_text("personal", "utf-8") assert integration.sync_official_skill(root)["status"] == "updated" assert not (target / "custom.txt").exists() assert (target / "SKILL.md").read_bytes() == (source / "SKILL.md").read_bytes() assert unrelated.read_text("utf-8") == "personal" before = (target / "SKILL.md").stat().st_mtime_ns assert integration.sync_official_skill(root)["status"] == "unchanged" assert (target / "SKILL.md").stat().st_mtime_ns == before (target / "SKILL.md").write_text("edited", "utf-8") assert integration.sync_official_skill(root)["status"] == "updated" assert (target / "SKILL.md").read_bytes() == (source / "SKILL.md").read_bytes() def test_update_removes_retired_files_and_migrates_only_marked_rules(bundle): root, source, home = bundle integration.sync_official_skill(root) original = "user prefix\n\nold\n\nuser suffix\n" for name in ("AGENTS.md", "AGENTS.override.md"): (home / name).write_text(original, "utf-8") (source / "references" / "modes.md").unlink() integration.sync_official_skill(root) assert not (home / "skills/artemis-use/references/modes.md").exists() for name in ("AGENTS.md", "AGENTS.override.md"): assert (home / name).read_text("utf-8") == "user prefix\nuser suffix\n" assert (home / (name + ".artemis-update.bak")).read_text("utf-8") == original def test_failed_replacement_restores_previous_bundle(bundle, monkeypatch): root, source, home = bundle integration.sync_official_skill(root) target = home / "skills/artemis-use" original = (target / "SKILL.md").read_bytes() (source / "SKILL.md").write_text("new version", "utf-8") rename = Path.rename def fail_staging(path, destination): if path.name.startswith(".artemis-use-stage-"): raise PermissionError("held open") return rename(path, destination) monkeypatch.setattr(Path, "rename", fail_staging) assert integration.sync_skill_safely(root)["status"] == "error" assert (target / "SKILL.md").read_bytes() == original assert not list(target.parent.glob(".artemis-use-stage-*")) def test_newer_official_bundle_is_not_downgraded(bundle): root, _, home = bundle integration.sync_official_skill(root) stamp = home / "skills/artemis-use" / integration.STAMP data = json.loads(stamp.read_text("utf-8")) data["artemis_version"] = "99.0.0" stamp.write_text(json.dumps(data), "utf-8") assert integration.sync_official_skill(root)["status"] == "newer_installed" def test_default_directory_and_duplicate_cleanup(bundle, tmp_path, monkeypatch): root, source, _ = bundle monkeypatch.delenv("CODEX_HOME") monkeypatch.setattr(Path, "home", lambda: tmp_path) legacy = tmp_path / ".codex/skills/artemis-use" legacy.mkdir(parents=True) (legacy / "SKILL.md").write_text("old", "utf-8") assert integration.sync_official_skill(root)["path"] == str(legacy) modern = tmp_path / ".agents/skills/artemis-use" modern.mkdir(parents=True) (modern / "SKILL.md").write_text("duplicate", "utf-8") assert integration.sync_official_skill(root)["path"] == str(modern) assert not legacy.exists() def test_actual_bundle_links_are_self_contained(): import re source = Path(__file__).resolve().parents[2] / "skills/artemis-use" for document in source.rglob("*.md"): for relative in re.findall(r"\]\(([^)]+)\)", document.read_text("utf-8")): if "://" in relative or relative.startswith("#"): continue target = (document.parent / relative.split("#", 1)[0]).resolve() assert target.is_relative_to(source.resolve()), (document, relative) assert target.exists(), (document, relative) def test_malformed_stamp_does_not_block_authoritative_update(bundle): root, source, home = bundle integration.sync_official_skill(root) target = home / "skills/artemis-use" (target / integration.STAMP).write_text("[]", "utf-8") (target / "SKILL.md").write_text("unofficial", "utf-8") assert integration.sync_official_skill(root)["status"] == "updated" assert (target / "SKILL.md").read_bytes() == (source / "SKILL.md").read_bytes()