feat(skill-learning): merge plugin skill updates

This commit is contained in:
2026-06-16 11:55:55 +08:00
parent c9e6c37b5c
commit a34b1219bc
15 changed files with 860 additions and 5 deletions

View File

@ -234,3 +234,58 @@ def test_sync_enabled_supersedes_stale_pending_update(tmp_path: Path) -> None:
assert len(candidates) == 2
assert {candidate.status for candidate in candidates} == {"open", "superseded"}
assert any(candidate.candidate_id != first_candidate.candidate_id for candidate in candidates)
def test_pause_leaves_skill_active_and_suppresses_update_candidates(tmp_path: Path) -> None:
workspace = tmp_path / "workspace"
plugin_root = _write_skill_plugin(workspace / "plugins")
_manager(workspace).enable("baoyu-comic")
_manager(workspace).pause("baoyu-comic")
_rewrite_plugin_version(plugin_root, version="1.1.0", skill_text="# Baoyu Comic\n\nPaused update.\n")
_manager(workspace).sync_enabled()
assert SkillSpecStore(workspace).get_skill_spec("baoyu-comic").status == "active" # type: ignore[union-attr]
assert SkillLearningStore(workspace / "memory" / "skills").list_learning_candidates() == []
def test_resume_reconciles_and_syncs_updates(tmp_path: Path) -> None:
workspace = tmp_path / "workspace"
plugin_root = _write_skill_plugin(workspace / "plugins")
_manager(workspace).enable("baoyu-comic")
_manager(workspace).pause("baoyu-comic")
_rewrite_plugin_version(plugin_root, version="1.1.0", skill_text="# Baoyu Comic\n\nResume update.\n")
state = _manager(workspace).resume("baoyu-comic")
assert state.status == "update_pending"
assert SkillLearningStore(workspace / "memory" / "skills").list_learning_candidates()
def test_disable_plugin_disables_linked_skills_without_deleting_versions(tmp_path: Path) -> None:
workspace = tmp_path / "workspace"
_write_skill_plugin(workspace / "plugins")
_manager(workspace).enable("baoyu-comic")
with pytest.raises(ValueError, match="disable_linked_skills"):
_manager(workspace).disable("baoyu-comic", disable_linked_skills=False)
state = _manager(workspace).disable("baoyu-comic", disable_linked_skills=True)
spec = SkillSpecStore(workspace).get_skill_spec("baoyu-comic")
assert state.enabled is False
assert spec is not None and spec.status == "disabled"
assert SkillSpecStore(workspace).read_published_skill("baoyu-comic", "v0001") is not None
def test_adopt_detaches_plugin_binding_and_keeps_skill_active(tmp_path: Path) -> None:
workspace = tmp_path / "workspace"
_write_skill_plugin(workspace / "plugins")
_manager(workspace).enable("baoyu-comic")
spec = _manager(workspace).adopt("baoyu-comic", "baoyu-comic")
state = PluginStateStore(workspace).get_plugin("baoyu-comic")
assert spec.source_kind == "managed"
assert spec.status == "active"
assert "adopted_from_plugin:baoyu-comic" in spec.lineage
assert state is not None and "baoyu-comic" not in state.skills