Coverage for src/lilbee/cli/launchers/skill_install.py: 100%
28 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-08-14 11:46 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-08-14 11:46 +0000
1"""Install the bundled lilbee-mcp guidance skill into an agent's skills directory."""
3from __future__ import annotations
5import os
6import shutil
7import tempfile
8from importlib import resources
9from pathlib import Path
11_SKILL_PACKAGE = "lilbee.skills.lilbee_mcp"
14def install_bundled_skill(dest: Path) -> Path | None:
15 """Copy the bundled lilbee-mcp skill into *dest*; skip (return None) if it exists."""
16 if dest.exists():
17 return None
18 source = resources.files(_SKILL_PACKAGE)
19 dest.parent.mkdir(parents=True, exist_ok=True)
20 # Stage in a sibling temp dir and atomically rename so a partial copy never
21 # leaves a half-written skill dir that exists() would then skip forever.
22 staging = Path(tempfile.mkdtemp(dir=dest.parent, prefix=".lilbee-mcp-"))
23 try:
24 for entry in source.iterdir():
25 if entry.is_file() and not entry.name.startswith("__"):
26 (staging / entry.name).write_bytes(entry.read_bytes())
27 try:
28 os.replace(staging, dest)
29 except OSError:
30 # On Windows, os.replace into an existing dest can race with another
31 # installer. If dest now exists, the skill is already installed.
32 shutil.rmtree(staging, ignore_errors=True)
33 if dest.exists():
34 return None
35 raise
36 except BaseException:
37 shutil.rmtree(staging, ignore_errors=True)
38 raise
39 return dest