Co-authored-by: Clément Drouin <clement.drouin@mistral.ai> Co-authored-by: Clément Sirieix <clement.sirieix@mistral.ai> Co-authored-by: Cyprien <courtot.c@gmail.com> Co-authored-by: Guillaume LE GOFF <guillaume.lgf@gmail.com> Co-authored-by: Jean Burellier <sheplu@users.noreply.github.com> Co-authored-by: Kim-Adeline Miguel <51720070+kimadeline@users.noreply.github.com> Co-authored-by: Mathias Gesbert <mathias.gesbert@mistral.ai> Co-authored-by: Nelson PROIA <144663685+Nelson-PROIA@users.noreply.github.com> Co-authored-by: Paul VEZIA <166131032+le-codeur-rapide@users.noreply.github.com> Co-authored-by: Pierre Rossinès <pierre.rossines@mistral.ai> Co-authored-by: Quentin <quentin.torroba@mistral.ai> Co-authored-by: Vincent G <10739306+VinceOPS@users.noreply.github.com> Co-authored-by: josephine-delas <57808586+josephine-delas@users.noreply.github.com> Co-authored-by: Mistral Vibe <vibe@mistral.ai>
531 lines
21 KiB
Python
531 lines
21 KiB
Python
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
|
|
|
|
|
|
@pytest.fixture
|
|
def skill_manager(vibe_config: VibeConfig) -> SkillManager:
|
|
return SkillManager(lambda: vibe_config)
|
|
|
|
|
|
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 == BUILTIN_SKILLS
|
|
|
|
def test_discovers_skill_from_skill_paths(self, skills_dir: Path) -> None:
|
|
create_skill(skills_dir, "test-skill", "A test skill")
|
|
|
|
config = build_test_vibe_config(skill_paths=[skills_dir])
|
|
manager = SkillManager(lambda: config)
|
|
|
|
assert "test-skill" in manager.available_skills
|
|
assert manager.available_skills["test-skill"].description == "A test skill"
|
|
|
|
def test_discovers_multiple_skills(self, skills_dir: Path) -> None:
|
|
create_skill(skills_dir, "skill-one", "First skill")
|
|
create_skill(skills_dir, "skill-two", "Second skill")
|
|
create_skill(skills_dir, "skill-three", "Third skill")
|
|
|
|
config = build_test_vibe_config(skill_paths=[skills_dir])
|
|
manager = SkillManager(lambda: config)
|
|
|
|
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
|
|
|
|
def test_ignores_directories_without_skill_md(self, skills_dir: Path) -> None:
|
|
# Create a directory that's not a skill
|
|
not_a_skill = skills_dir / "not-a-skill"
|
|
not_a_skill.mkdir()
|
|
(not_a_skill / "README.md").write_text("Not a skill")
|
|
|
|
# Create a valid skill
|
|
create_skill(skills_dir, "valid-skill", "A valid skill")
|
|
|
|
config = build_test_vibe_config(skill_paths=[skills_dir])
|
|
manager = SkillManager(lambda: config)
|
|
|
|
skills = manager.available_skills
|
|
assert len(skills) == 1 + len(BUILTIN_SKILLS)
|
|
assert "valid-skill" in skills
|
|
assert "not-a-skill" not in skills
|
|
|
|
def test_ignores_files_in_skills_directory(self, skills_dir: Path) -> None:
|
|
# Create a file in the skills directory (not a directory)
|
|
(skills_dir / "not-a-directory.md").write_text("Just a file")
|
|
|
|
# Create a valid skill
|
|
create_skill(skills_dir, "valid-skill", "A valid skill")
|
|
|
|
config = build_test_vibe_config(skill_paths=[skills_dir])
|
|
manager = SkillManager(lambda: config)
|
|
|
|
skills = manager.available_skills
|
|
assert len(skills) == 1 + len(BUILTIN_SKILLS)
|
|
assert "valid-skill" in skills
|
|
|
|
|
|
class TestSkillManagerParsing:
|
|
def test_parses_all_skill_fields(self, skills_dir: Path) -> None:
|
|
create_skill(
|
|
skills_dir,
|
|
"full-skill",
|
|
"A skill with all fields",
|
|
license="MIT",
|
|
compatibility="Requires git",
|
|
metadata={"author": "Test Author", "version": "1.0"},
|
|
allowed_tools="bash read",
|
|
)
|
|
|
|
config = build_test_vibe_config(skill_paths=[skills_dir])
|
|
manager = SkillManager(lambda: config)
|
|
|
|
skill = manager.get_skill("full-skill")
|
|
assert skill is not None
|
|
assert skill.name == "full-skill"
|
|
assert skill.description == "A skill with all fields"
|
|
assert skill.license == "MIT"
|
|
assert skill.compatibility == "Requires git"
|
|
assert skill.metadata == {"author": "Test Author", "version": "1.0"}
|
|
assert skill.allowed_tools == ["bash", "read"]
|
|
|
|
def test_sets_correct_skill_path(self, skills_dir: Path) -> None:
|
|
create_skill(skills_dir, "test-skill", "A test skill")
|
|
|
|
config = build_test_vibe_config(skill_paths=[skills_dir])
|
|
manager = SkillManager(lambda: config)
|
|
|
|
skill = manager.get_skill("test-skill")
|
|
assert skill is not None
|
|
assert skill.skill_path == skills_dir / "test-skill" / "SKILL.md"
|
|
assert skill.skill_dir == skills_dir / "test-skill"
|
|
|
|
def test_skips_skill_with_invalid_frontmatter(self, skills_dir: Path) -> None:
|
|
# Create an invalid skill
|
|
invalid_skill_dir = skills_dir / "invalid-skill"
|
|
invalid_skill_dir.mkdir()
|
|
(invalid_skill_dir / "SKILL.md").write_text("No frontmatter here")
|
|
|
|
# Create a valid skill
|
|
create_skill(skills_dir, "valid-skill", "A valid skill")
|
|
|
|
config = build_test_vibe_config(skill_paths=[skills_dir])
|
|
manager = SkillManager(lambda: config)
|
|
|
|
skills = manager.available_skills
|
|
assert len(skills) == 1 + len(BUILTIN_SKILLS)
|
|
assert "valid-skill" in skills
|
|
assert "invalid-skill" not in skills
|
|
|
|
def test_skips_skill_with_missing_required_fields(self, skills_dir: Path) -> None:
|
|
# Create skill missing description
|
|
missing_desc_dir = skills_dir / "missing-desc"
|
|
missing_desc_dir.mkdir()
|
|
(missing_desc_dir / "SKILL.md").write_text("---\nname: missing-desc\n---\n")
|
|
|
|
# Create a valid skill
|
|
create_skill(skills_dir, "valid-skill", "A valid skill")
|
|
|
|
config = build_test_vibe_config(skill_paths=[skills_dir])
|
|
manager = SkillManager(lambda: config)
|
|
|
|
skills = manager.available_skills
|
|
assert len(skills) == 1 + len(BUILTIN_SKILLS)
|
|
assert "valid-skill" in skills
|
|
|
|
|
|
class TestSkillManagerSearchPaths:
|
|
def test_discovers_from_vibe_skills_when_cwd_trusted(
|
|
self, tmp_working_directory: Path
|
|
) -> None:
|
|
trusted_folders_manager.add_trusted(tmp_working_directory)
|
|
vibe_skills = tmp_working_directory / ".vibe" / "skills"
|
|
vibe_skills.mkdir(parents=True)
|
|
create_skill(vibe_skills, "vibe-skill", "Skill from .vibe/skills")
|
|
|
|
config = build_test_vibe_config(skill_paths=[])
|
|
manager = SkillManager(lambda: config)
|
|
|
|
assert "vibe-skill" in manager.available_skills
|
|
assert (
|
|
manager.available_skills["vibe-skill"].description
|
|
== "Skill from .vibe/skills"
|
|
)
|
|
|
|
def test_discovers_from_agents_skills_when_cwd_trusted(
|
|
self, tmp_working_directory: Path
|
|
) -> None:
|
|
trusted_folders_manager.add_trusted(tmp_working_directory)
|
|
agents_skills = tmp_working_directory / ".agents" / "skills"
|
|
agents_skills.mkdir(parents=True)
|
|
create_skill(agents_skills, "agents-skill", "Skill from .agents/skills")
|
|
|
|
config = build_test_vibe_config(skill_paths=[])
|
|
manager = SkillManager(lambda: config)
|
|
|
|
assert "agents-skill" in manager.available_skills
|
|
assert (
|
|
manager.available_skills["agents-skill"].description
|
|
== "Skill from .agents/skills"
|
|
)
|
|
|
|
def test_discovers_from_both_vibe_and_agents_skills_when_cwd_trusted(
|
|
self, tmp_working_directory: Path
|
|
) -> None:
|
|
trusted_folders_manager.add_trusted(tmp_working_directory)
|
|
vibe_skills = tmp_working_directory / ".vibe" / "skills"
|
|
agents_skills = tmp_working_directory / ".agents" / "skills"
|
|
vibe_skills.mkdir(parents=True)
|
|
agents_skills.mkdir(parents=True)
|
|
create_skill(vibe_skills, "vibe-only", "From .vibe")
|
|
create_skill(agents_skills, "agents-only", "From .agents")
|
|
|
|
config = build_test_vibe_config(skill_paths=[])
|
|
manager = SkillManager(lambda: config)
|
|
|
|
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
|
|
) -> None:
|
|
trusted_folders_manager.add_trusted(tmp_working_directory)
|
|
vibe_skills = tmp_working_directory / ".vibe" / "skills"
|
|
agents_skills = tmp_working_directory / ".agents" / "skills"
|
|
vibe_skills.mkdir(parents=True)
|
|
agents_skills.mkdir(parents=True)
|
|
create_skill(vibe_skills, "shared-skill", "First from .vibe")
|
|
create_skill(agents_skills, "shared-skill", "Second from .agents")
|
|
|
|
config = build_test_vibe_config(skill_paths=[])
|
|
manager = SkillManager(lambda: config)
|
|
|
|
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
|
|
skills_dir_1 = tmp_path / "skills1"
|
|
skills_dir_1.mkdir()
|
|
create_skill(skills_dir_1, "skill-from-dir1", "Skill from directory 1")
|
|
|
|
skills_dir_2 = tmp_path / "skills2"
|
|
skills_dir_2.mkdir()
|
|
create_skill(skills_dir_2, "skill-from-dir2", "Skill from directory 2")
|
|
|
|
config = build_test_vibe_config(skill_paths=[skills_dir_1, skills_dir_2])
|
|
manager = SkillManager(lambda: config)
|
|
|
|
skills = manager.available_skills
|
|
assert len(skills) == 2 + len(BUILTIN_SKILLS)
|
|
assert "skill-from-dir1" in skills
|
|
assert "skill-from-dir2" in skills
|
|
|
|
def test_first_discovered_wins_for_duplicates(self, tmp_path: Path) -> None:
|
|
# Create two directories with the same skill name
|
|
skills_dir_1 = tmp_path / "skills1"
|
|
skills_dir_1.mkdir()
|
|
create_skill(skills_dir_1, "duplicate-skill", "First version")
|
|
|
|
skills_dir_2 = tmp_path / "skills2"
|
|
skills_dir_2.mkdir()
|
|
create_skill(skills_dir_2, "duplicate-skill", "Second version")
|
|
|
|
config = build_test_vibe_config(skill_paths=[skills_dir_1, skills_dir_2])
|
|
manager = SkillManager(lambda: config)
|
|
|
|
skills = manager.available_skills
|
|
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:
|
|
skills_dir = tmp_path / "skills"
|
|
skills_dir.mkdir()
|
|
create_skill(skills_dir, "valid-skill", "A valid skill")
|
|
|
|
config = build_test_vibe_config(
|
|
skill_paths=[skills_dir, tmp_path / "nonexistent"]
|
|
)
|
|
manager = SkillManager(lambda: config)
|
|
|
|
skills = manager.available_skills
|
|
assert len(skills) == 1 + len(BUILTIN_SKILLS)
|
|
assert "valid-skill" in skills
|
|
|
|
|
|
class TestSkillManagerGetSkill:
|
|
def test_returns_skill_by_name(self, skills_dir: Path) -> None:
|
|
create_skill(skills_dir, "test-skill", "A test skill")
|
|
|
|
config = build_test_vibe_config(skill_paths=[skills_dir])
|
|
manager = SkillManager(lambda: config)
|
|
|
|
skill = manager.get_skill("test-skill")
|
|
assert skill is not None
|
|
assert skill.name == "test-skill"
|
|
|
|
def test_returns_none_for_unknown_skill(self, skill_manager: SkillManager) -> None:
|
|
assert skill_manager.get_skill("nonexistent-skill") is None
|
|
|
|
|
|
class TestSkillManagerFiltering:
|
|
def test_enabled_skills_filters_to_only_enabled(self, skills_dir: Path) -> None:
|
|
create_skill(skills_dir, "skill-a", "Skill A")
|
|
create_skill(skills_dir, "skill-b", "Skill B")
|
|
create_skill(skills_dir, "skill-c", "Skill C")
|
|
|
|
config = build_test_vibe_config(
|
|
skill_paths=[skills_dir], enabled_skills=["skill-a", "skill-c"]
|
|
)
|
|
manager = SkillManager(lambda: config)
|
|
|
|
skills = manager.available_skills
|
|
assert len(skills) == 2
|
|
assert "skill-a" in skills
|
|
assert "skill-b" not in skills
|
|
assert "skill-c" in skills
|
|
|
|
def test_disabled_skills_excludes_disabled(self, skills_dir: Path) -> None:
|
|
create_skill(skills_dir, "skill-a", "Skill A")
|
|
create_skill(skills_dir, "skill-b", "Skill B")
|
|
create_skill(skills_dir, "skill-c", "Skill C")
|
|
|
|
config = build_test_vibe_config(
|
|
skill_paths=[skills_dir], disabled_skills=["skill-b"]
|
|
)
|
|
manager = SkillManager(lambda: config)
|
|
|
|
skills = manager.available_skills
|
|
assert len(skills) == 2 + len(BUILTIN_SKILLS)
|
|
assert "skill-a" in skills
|
|
assert "skill-b" not in skills
|
|
assert "skill-c" in skills
|
|
|
|
def test_enabled_skills_takes_precedence_over_disabled(
|
|
self, skills_dir: Path
|
|
) -> None:
|
|
create_skill(skills_dir, "skill-a", "Skill A")
|
|
create_skill(skills_dir, "skill-b", "Skill B")
|
|
|
|
config = build_test_vibe_config(
|
|
skill_paths=[skills_dir],
|
|
enabled_skills=["skill-a"],
|
|
disabled_skills=["skill-a"], # Should be ignored
|
|
)
|
|
manager = SkillManager(lambda: config)
|
|
|
|
skills = manager.available_skills
|
|
assert len(skills) == 1
|
|
assert "skill-a" in skills
|
|
|
|
def test_glob_pattern_matching(self, skills_dir: Path) -> None:
|
|
create_skill(skills_dir, "search-code", "Search code")
|
|
create_skill(skills_dir, "search-docs", "Search docs")
|
|
create_skill(skills_dir, "other-skill", "Other skill")
|
|
|
|
config = build_test_vibe_config(
|
|
skill_paths=[skills_dir], enabled_skills=["search-*"]
|
|
)
|
|
manager = SkillManager(lambda: config)
|
|
|
|
skills = manager.available_skills
|
|
assert len(skills) == 2
|
|
assert "search-code" in skills
|
|
assert "search-docs" in skills
|
|
assert "other-skill" not in skills
|
|
|
|
def test_regex_pattern_matching(self, skills_dir: Path) -> None:
|
|
create_skill(skills_dir, "skill-v1", "Skill v1")
|
|
create_skill(skills_dir, "skill-v2", "Skill v2")
|
|
create_skill(skills_dir, "other-skill", "Other skill")
|
|
|
|
config = build_test_vibe_config(
|
|
skill_paths=[skills_dir], enabled_skills=["re:skill-v\\d+"]
|
|
)
|
|
manager = SkillManager(lambda: config)
|
|
|
|
skills = manager.available_skills
|
|
assert len(skills) == 2
|
|
assert "skill-v1" in skills
|
|
assert "skill-v2" in skills
|
|
assert "other-skill" not in skills
|
|
|
|
def test_get_skill_respects_filtering(self, skills_dir: Path) -> None:
|
|
create_skill(skills_dir, "enabled-skill", "Enabled")
|
|
create_skill(skills_dir, "disabled-skill", "Disabled")
|
|
|
|
config = build_test_vibe_config(
|
|
skill_paths=[skills_dir], disabled_skills=["disabled-skill"]
|
|
)
|
|
manager = SkillManager(lambda: config)
|
|
|
|
assert manager.get_skill("enabled-skill") is not None
|
|
assert manager.get_skill("disabled-skill") is None
|
|
|
|
|
|
class TestSkillUserInvocable:
|
|
def test_user_invocable_defaults_to_true(self, skills_dir: Path) -> None:
|
|
create_skill(skills_dir, "default-skill", "A default skill")
|
|
|
|
config = build_test_vibe_config(skill_paths=[skills_dir])
|
|
manager = SkillManager(lambda: config)
|
|
|
|
skill = manager.get_skill("default-skill")
|
|
assert skill is not None
|
|
assert skill.user_invocable is True
|
|
|
|
def test_user_invocable_can_be_set_to_false(self, skills_dir: Path) -> None:
|
|
create_skill(skills_dir, "hidden-skill", "A hidden skill", user_invocable=False)
|
|
|
|
config = build_test_vibe_config(skill_paths=[skills_dir])
|
|
manager = SkillManager(lambda: config)
|
|
|
|
skill = manager.get_skill("hidden-skill")
|
|
assert skill is not None
|
|
assert skill.user_invocable is False
|
|
|
|
def test_user_invocable_can_be_explicitly_set_to_true(
|
|
self, skills_dir: Path
|
|
) -> None:
|
|
create_skill(
|
|
skills_dir, "explicit-skill", "An explicit skill", user_invocable=True
|
|
)
|
|
|
|
config = build_test_vibe_config(skill_paths=[skills_dir])
|
|
manager = SkillManager(lambda: config)
|
|
|
|
skill = manager.get_skill("explicit-skill")
|
|
assert skill is not None
|
|
assert skill.user_invocable is True
|
|
|
|
def test_mixed_user_invocable_skills(self, skills_dir: Path) -> None:
|
|
create_skill(skills_dir, "visible-skill", "Visible", user_invocable=True)
|
|
create_skill(skills_dir, "hidden-skill", "Hidden", user_invocable=False)
|
|
create_skill(skills_dir, "default-skill", "Default")
|
|
|
|
config = build_test_vibe_config(skill_paths=[skills_dir])
|
|
manager = SkillManager(lambda: config)
|
|
|
|
skills = manager.available_skills
|
|
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
|
|
|
|
|
|
class TestParseSkillCommand:
|
|
def test_plain_text_returns_none(self, skill_manager: SkillManager) -> None:
|
|
assert skill_manager.parse_skill_command("hello world") is None
|
|
|
|
def test_unknown_skill_returns_none(self, skill_manager: SkillManager) -> None:
|
|
assert skill_manager.parse_skill_command("/nonexistent") is None
|
|
|
|
def test_slash_only_returns_none(self, skill_manager: SkillManager) -> None:
|
|
assert skill_manager.parse_skill_command("/") is None
|
|
|
|
def test_parses_skill_without_args(
|
|
self, skills_dir: Path, skill_config: VibeConfig
|
|
) -> None:
|
|
create_skill(skills_dir, "my-skill", body="Do the thing.")
|
|
manager = SkillManager(lambda: skill_config)
|
|
|
|
parsed = manager.parse_skill_command("/my-skill")
|
|
assert parsed is not None
|
|
assert parsed.name == "my-skill"
|
|
assert "Do the thing." in parsed.content
|
|
assert parsed.extra_instructions is None
|
|
|
|
def test_parses_skill_with_args(
|
|
self, skills_dir: Path, skill_config: VibeConfig
|
|
) -> None:
|
|
create_skill(skills_dir, "my-skill", body="Do the thing.")
|
|
manager = SkillManager(lambda: skill_config)
|
|
|
|
parsed = manager.parse_skill_command("/my-skill fix the bug")
|
|
assert parsed is not None
|
|
assert parsed.name == "my-skill"
|
|
assert parsed.extra_instructions == "fix the bug"
|
|
|
|
def test_case_insensitive(self, skills_dir: Path, skill_config: VibeConfig) -> None:
|
|
create_skill(skills_dir, "my-skill", body="Do the thing.")
|
|
manager = SkillManager(lambda: skill_config)
|
|
|
|
parsed = manager.parse_skill_command("/MY-SKILL")
|
|
assert parsed is not None
|
|
assert parsed.name == "my-skill"
|
|
|
|
|
|
class TestSkillManagerConfigIssues:
|
|
def test_invalid_frontmatter_records_config_issue(self, skills_dir: Path) -> None:
|
|
broken_dir = skills_dir / "broken-skill"
|
|
broken_dir.mkdir()
|
|
(broken_dir / "SKILL.md").write_text("No frontmatter here")
|
|
|
|
config = build_test_vibe_config(skill_paths=[skills_dir])
|
|
manager = SkillManager(lambda: config)
|
|
|
|
assert len(manager.config_issues) == 1
|
|
issue = manager.config_issues[0]
|
|
assert issue.file == broken_dir / "SKILL.md"
|
|
assert "Failed to load" in issue.message
|
|
|
|
def test_multiple_invalid_skills_accumulate_issues(self, skills_dir: Path) -> None:
|
|
broken_dir_a = skills_dir / "broken-skill-a"
|
|
broken_dir_a.mkdir()
|
|
(broken_dir_a / "SKILL.md").write_text("not valid")
|
|
broken_dir = skills_dir / "broken-skill"
|
|
broken_dir.mkdir()
|
|
(broken_dir / "SKILL.md").write_text("not valid")
|
|
create_skill(skills_dir, "good-skill", "Works fine")
|
|
|
|
config = build_test_vibe_config(skill_paths=[skills_dir])
|
|
manager = SkillManager(lambda: config)
|
|
|
|
assert {
|
|
(i.file, i.message.startswith("Failed to load"))
|
|
for i in manager.config_issues
|
|
} == {(broken_dir_a / "SKILL.md", True), (broken_dir / "SKILL.md", True)}
|
|
assert "good-skill" in manager.available_skills
|
|
|
|
|
|
class TestBuildSkillPrompt:
|
|
def test_without_args(self, skills_dir: Path, skill_config: VibeConfig) -> None:
|
|
create_skill(skills_dir, "my-skill", body="Do the thing.")
|
|
manager = SkillManager(lambda: skill_config)
|
|
|
|
parsed = manager.parse_skill_command("/my-skill")
|
|
assert parsed is not None
|
|
prompt = SkillManager.build_skill_prompt("/my-skill", parsed)
|
|
assert prompt == parsed.content
|
|
|
|
def test_with_args(self, skills_dir: Path, skill_config: VibeConfig) -> None:
|
|
create_skill(skills_dir, "my-skill", body="Do the thing.")
|
|
manager = SkillManager(lambda: skill_config)
|
|
|
|
text = "/my-skill fix the bug"
|
|
parsed = manager.parse_skill_command(text)
|
|
assert parsed is not None
|
|
prompt = SkillManager.build_skill_prompt(text, parsed)
|
|
assert prompt.startswith("/my-skill fix the bug")
|
|
assert "Do the thing." in prompt
|