Co-authored-by: Kim-Adeline Miguel <51720070+kimadeline@users.noreply.github.com>
Co-authored-by: Mathias Gesbert <mathias.gesbert@mistral.ai>
Co-authored-by: Michel Thomazo <51709227+michelTho@users.noreply.github.com>
Co-authored-by: Pierre Rossinès <pierre.rossines@mistral.ai>
Co-authored-by: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
Clément Sirieix 2026-04-21 15:19:59 +02:00 committed by GitHub
parent 95336528f6
commit 04305bd77c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
68 changed files with 3473 additions and 1764 deletions

View file

@ -1,12 +1,14 @@
from __future__ import annotations
from pathlib import Path
from typing import cast
import pytest
from tests.conftest import build_test_vibe_config
from tests.skills.conftest import create_skill
from vibe.core.config import VibeConfig
from vibe.core.skills.builtins import BUILTIN_SKILLS
from vibe.core.skills.manager import SkillManager
from vibe.core.trusted_folders import trusted_folders_manager
@ -24,10 +26,15 @@ def skill_manager(config: VibeConfig) -> SkillManager:
class TestSkillManagerDiscovery:
def test_available_skills_is_frozen(self, skill_manager: SkillManager) -> None:
frozen_skills = cast(dict[str, object], skill_manager.available_skills)
with pytest.raises(TypeError):
frozen_skills["new-skill"] = object()
def test_discovers_no_skills_when_directory_empty(
self, skill_manager: SkillManager
) -> None:
assert skill_manager.available_skills == {}
assert skill_manager.available_skills == BUILTIN_SKILLS
def test_discovers_skill_from_skill_paths(self, skills_dir: Path) -> None:
create_skill(skills_dir, "test-skill", "A test skill")
@ -54,7 +61,7 @@ class TestSkillManagerDiscovery:
)
manager = SkillManager(lambda: config)
assert len(manager.available_skills) == 3
assert len(manager.available_skills) == 3 + len(BUILTIN_SKILLS)
assert "skill-one" in manager.available_skills
assert "skill-two" in manager.available_skills
assert "skill-three" in manager.available_skills
@ -76,7 +83,7 @@ class TestSkillManagerDiscovery:
manager = SkillManager(lambda: config)
skills = manager.available_skills
assert len(skills) == 1
assert len(skills) == 1 + len(BUILTIN_SKILLS)
assert "valid-skill" in skills
assert "not-a-skill" not in skills
@ -95,7 +102,7 @@ class TestSkillManagerDiscovery:
manager = SkillManager(lambda: config)
skills = manager.available_skills
assert len(skills) == 1
assert len(skills) == 1 + len(BUILTIN_SKILLS)
assert "valid-skill" in skills
@ -159,7 +166,7 @@ class TestSkillManagerParsing:
manager = SkillManager(lambda: config)
skills = manager.available_skills
assert len(skills) == 1
assert len(skills) == 1 + len(BUILTIN_SKILLS)
assert "valid-skill" in skills
assert "invalid-skill" not in skills
@ -180,7 +187,7 @@ class TestSkillManagerParsing:
manager = SkillManager(lambda: config)
skills = manager.available_skills
assert len(skills) == 1
assert len(skills) == 1 + len(BUILTIN_SKILLS)
assert "valid-skill" in skills
@ -239,9 +246,10 @@ class TestSkillManagerSearchPaths:
)
manager = SkillManager(lambda: config)
assert len(manager.available_skills) == 2
assert manager.available_skills["vibe-only"].description == "From .vibe"
assert manager.available_skills["agents-only"].description == "From .agents"
skills = manager.available_skills
assert len(skills) == 2 + len(BUILTIN_SKILLS)
assert skills["vibe-only"].description == "From .vibe"
assert skills["agents-only"].description == "From .agents"
def test_first_discovered_wins_when_same_skill_in_vibe_and_agents(
self, tmp_working_directory: Path
@ -259,10 +267,9 @@ class TestSkillManagerSearchPaths:
)
manager = SkillManager(lambda: config)
assert len(manager.available_skills) == 1
assert (
manager.available_skills["shared-skill"].description == "First from .vibe"
)
skills = manager.available_skills
assert len(skills) == 1 + len(BUILTIN_SKILLS)
assert skills["shared-skill"].description == "First from .vibe"
def test_discovers_from_multiple_skill_paths(self, tmp_path: Path) -> None:
# Create two separate skill directories
@ -282,7 +289,7 @@ class TestSkillManagerSearchPaths:
manager = SkillManager(lambda: config)
skills = manager.available_skills
assert len(skills) == 2
assert len(skills) == 2 + len(BUILTIN_SKILLS)
assert "skill-from-dir1" in skills
assert "skill-from-dir2" in skills
@ -304,7 +311,7 @@ class TestSkillManagerSearchPaths:
manager = SkillManager(lambda: config)
skills = manager.available_skills
assert len(skills) == 1
assert len(skills) == 1 + len(BUILTIN_SKILLS)
assert skills["duplicate-skill"].description == "First version"
def test_ignores_nonexistent_skill_paths(self, tmp_path: Path) -> None:
@ -319,8 +326,9 @@ class TestSkillManagerSearchPaths:
)
manager = SkillManager(lambda: config)
assert len(manager.available_skills) == 1
assert "valid-skill" in manager.available_skills
skills = manager.available_skills
assert len(skills) == 1 + len(BUILTIN_SKILLS)
assert "valid-skill" in skills
class TestSkillManagerGetSkill:
@ -376,7 +384,7 @@ class TestSkillManagerFiltering:
manager = SkillManager(lambda: config)
skills = manager.available_skills
assert len(skills) == 2
assert len(skills) == 2 + len(BUILTIN_SKILLS)
assert "skill-a" in skills
assert "skill-b" not in skills
assert "skill-c" in skills
@ -514,7 +522,7 @@ class TestSkillUserInvocable:
manager = SkillManager(lambda: config)
skills = manager.available_skills
assert len(skills) == 3
assert len(skills) == 3 + len(BUILTIN_SKILLS)
assert skills["visible-skill"].user_invocable is True
assert skills["hidden-skill"].user_invocable is False
assert skills["default-skill"].user_invocable is True
@ -561,16 +569,6 @@ class TestParseSkillCommand:
assert parsed is not None
assert parsed.name == "my-skill"
def test_raises_on_unreadable_skill(
self, skills_dir: Path, skill_config: VibeConfig
) -> None:
create_skill(skills_dir, "bad-skill", body="content")
manager = SkillManager(lambda: skill_config)
(skills_dir / "bad-skill" / "SKILL.md").unlink()
with pytest.raises(OSError):
manager.parse_skill_command("/bad-skill")
class TestBuildSkillPrompt:
def test_without_args(self, skills_dir: Path, skill_config: VibeConfig) -> None: