Files
skills/tests/test_install.py
T
Kevin Veen-BirkenbachandClaude Opus 5.5 c803f4ee28 fix(install): empty the skills directories instead of replacing them
install.sh removed ~/.claude/skills and ~/.agents/skills and created them anew. The Agent Orchestrator bind-mounts ~/.claude/skills, and a new inode left that mount showing the deleted directory, so the hub's radio send failed with radio.py not found after every make install. The installer now keeps each directory and deletes its contents before copying.

🎯 Fix: 93 %
💥 Break: 3 %
💸 Cost: 100 %
⏱️ Time: 100 %
🛡️ Security: 100 %
🏆 Score: 90
🚦 Gate: ✅ 90/5, cost and time <= 100, security 100 %

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-11 08:20:16 +00:00

43 lines
1.9 KiB
Python

"""Pin scripts/install.sh: the installed skill directories keep their inode, so a bind mount of them stays current."""
from __future__ import annotations
import os
import shutil
import subprocess
import tempfile
import unittest
from pathlib import Path
INSTALL = Path(__file__).resolve().parents[1] / "scripts" / "install.sh"
NPX = "#!/bin/sh\nmkdir -p .agents/skills/locked\necho locked > .agents/skills/locked/SKILL.md\n"
class TestInstall(unittest.TestCase):
def test_reinstall_empties_the_skill_directories_in_place(self):
with tempfile.TemporaryDirectory() as tmp:
root = Path(tmp)
repo, target, stubs = root / "repo", root / "target", root / "bin"
(repo / "scripts").mkdir(parents=True)
shutil.copy(INSTALL, repo / "scripts" / "install.sh")
(repo / "scripts" / "enable-plugins.js").write_text("", encoding="utf-8")
(repo / "skills" / "own").mkdir(parents=True)
(repo / "skills" / "own" / "SKILL.md").write_text("own", encoding="utf-8")
stubs.mkdir()
(stubs / "npx").write_text(NPX, encoding="utf-8")
(stubs / "npx").chmod(0o755)
installed = [target / ".agents" / "skills", target / ".claude" / "skills"]
for folder in installed:
(folder / "stale").mkdir(parents=True)
before = [folder.stat().st_ino for folder in installed]
env = {**os.environ, "PATH": f"{stubs}:/usr/bin:/bin", "TARGET": str(target)}
done = subprocess.run(["bash", str(repo / "scripts" / "install.sh")], env=env, capture_output=True, text=True, check=False)
self.assertEqual(done.returncode, 0, done.stderr)
self.assertEqual([folder.stat().st_ino for folder in installed], before)
for folder in installed:
self.assertEqual(sorted(path.name for path in folder.iterdir()), ["locked", "own"])
if __name__ == "__main__":
unittest.main()