Files
skills/tests/test_autotune.py
T
Kevin Veen-BirkenbachandClaude Opus 5.5 624baccfc4 refactor(skills)!: rename every skill to kvb-<category>-<name>
All 38 first-party skills move to kvb-<category>-<name> with the categories think, create, code, ci, git, check, org and skills; kvb-cleanup and kvb-help are the only uncategorized names. tests/test_naming.py pins the schema, the Agent Skills name rules and the README organigram. enable-plugins.js repoints hook commands of renamed skills in settings.local.json so a stale script path cannot block tools.

BREAKING CHANGE: the old skill names and slash commands (/commit-next, /dream, /autotune, ...) are gone; use their kvb- successors listed in the README organigram.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-11-01 00:47:23 +01:00

124 lines
4.0 KiB
Python

"""Validate the kvb-skills-tune reminder hook and its settings registration."""
from __future__ import annotations
import json
import shutil
import subprocess
import tempfile
import unittest
from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parents[1]
SKILL = REPO_ROOT / "skills" / "kvb-skills-tune" / "SKILL.md"
HOOK = REPO_ROOT / "skills" / "kvb-skills-tune" / "hooks" / "reminder.sh"
PATCHER = REPO_ROOT / "scripts" / "enable-plugins.js"
def _run_hook(stamp: Path, interval: str = "3600") -> subprocess.CompletedProcess:
return subprocess.run(
["bash", str(HOOK)],
capture_output=True,
text=True,
check=True,
env={
"PATH": "/usr/bin:/bin",
"HOME": str(stamp.parent),
"AUTOTUNE_STAMP": str(stamp),
"AUTOTUNE_INTERVAL_SECONDS": interval,
},
)
class TestAutotuneSkill(unittest.TestCase):
def test_skill_is_trigger_only(self):
text = SKILL.read_text(encoding="utf-8")
self.assertIn("name: kvb-skills-tune", text)
self.assertIn("multiSelect: false", text)
class TestSkillPersistence(unittest.TestCase):
"""Both skill writers must persist to the skills repository AND the live dirs."""
def test_autotune_names_every_target(self):
text = SKILL.read_text(encoding="utf-8")
for target in (
"SKILLS_REPO",
"skills/<name>/SKILL.md",
"~/.claude/skills/",
"~/.agents/skills/",
):
self.assertIn(target, text)
def test_autoskill_routes_to_the_same_persistence(self):
text = (REPO_ROOT / "skills" / "kvb-skills-auto" / "SKILL.md").read_text(
encoding="utf-8"
)
for target in ("Persistence", "~/.claude/skills/", "~/.agents/skills/"):
self.assertIn(target, text)
class TestAutotuneHook(unittest.TestCase):
def setUp(self):
self.tmp = tempfile.TemporaryDirectory()
self.addCleanup(self.tmp.cleanup)
self.stamp = Path(self.tmp.name) / ".claude" / ".autotune-stamp"
def test_first_run_hints_and_stamps(self):
result = _run_hook(self.stamp)
self.assertIn("/kvb-skills-tune", result.stdout)
self.assertTrue(self.stamp.is_file())
def test_second_run_is_silent_within_interval(self):
_run_hook(self.stamp)
self.assertEqual(_run_hook(self.stamp).stdout, "")
def test_hint_returns_after_the_interval(self):
_run_hook(self.stamp)
self.assertIn("/kvb-skills-tune", _run_hook(self.stamp, interval="0").stdout)
def test_corrupt_stamp_does_not_crash(self):
self.stamp.parent.mkdir(parents=True, exist_ok=True)
self.stamp.write_text("not-a-timestamp\n", encoding="utf-8")
self.assertIn("/kvb-skills-tune", _run_hook(self.stamp).stdout)
@unittest.skipUnless(shutil.which("node"), "node not installed")
class TestSettingsRegistration(unittest.TestCase):
def setUp(self):
self.tmp = tempfile.TemporaryDirectory()
self.addCleanup(self.tmp.cleanup)
self.settings = Path(self.tmp.name) / "settings.json"
def _patch(self) -> dict:
subprocess.run(
["node", str(PATCHER), str(self.settings)], check=True, capture_output=True
)
return json.loads(self.settings.read_text(encoding="utf-8"))
def test_hook_registered_once(self):
self._patch()
data = self._patch()
entries = json.dumps(data["hooks"]["UserPromptSubmit"])
self.assertEqual(entries.count("kvb-skills-tune/hooks/reminder.sh"), 1)
def test_existing_hooks_preserved(self):
self.settings.write_text(
json.dumps(
{
"hooks": {
"UserPromptSubmit": [
{"hooks": [{"type": "command", "command": "true"}]}
]
}
}
),
encoding="utf-8",
)
data = self._patch()
self.assertEqual(len(data["hooks"]["UserPromptSubmit"]), 4)
if __name__ == "__main__":
unittest.main()