mirror of
https://github.com/guillaumemeyer/watermarks-remover.git
synced 2026-08-22 13:11:57 +02:00
103 lines
3.0 KiB
Python
103 lines
3.0 KiB
Python
#!/usr/bin/env python3
|
|||
|
|
"""Install the lightweight text skill for Cursor."""
|
||
|
|
|
||
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
import argparse
|
||
|
|
import os
|
||
|
|
import shutil
|
||
|
|
import sys
|
||
|
|
import tempfile
|
||
|
|
import uuid
|
||
|
|
from pathlib import Path
|
||
|
|
|
||
|
|
SKILL_NAME = "clean-user-facing-text"
|
||
|
|
ROOT = Path(__file__).resolve().parent
|
||
|
|
SOURCE = ROOT / "skills" / SKILL_NAME
|
||
|
|
|
||
|
|
|
||
|
|
def _present(path: Path) -> bool:
|
||
|
|
return path.exists() or path.is_symlink()
|
||
|
|
|
||
|
|
|
||
|
|
def _remove_path(path: Path) -> None:
|
||
|
|
if path.is_symlink() or path.is_file():
|
||
|
|
path.unlink()
|
||
|
|
elif path.exists():
|
||
|
|
shutil.rmtree(path)
|
||
|
|
|
||
|
|
|
||
|
|
def _stage(skills_dir: Path) -> tuple[Path, Path]:
|
||
|
|
skills_dir.mkdir(parents=True, exist_ok=True)
|
||
|
|
staging_root = Path(
|
||
|
|
tempfile.mkdtemp(prefix=f".{SKILL_NAME}.staging.", dir=skills_dir)
|
||
|
|
)
|
||
|
|
staged_skill = staging_root / SKILL_NAME
|
||
|
|
try:
|
||
|
|
shutil.copytree(SOURCE, staged_skill)
|
||
|
|
if not (staged_skill / "SKILL.md").is_file():
|
||
|
|
raise RuntimeError("staged skill is missing SKILL.md")
|
||
|
|
except BaseException:
|
||
|
|
shutil.rmtree(staging_root, ignore_errors=True)
|
||
|
|
raise
|
||
|
|
return staging_root, staged_skill
|
||
|
|
|
||
|
|
|
||
|
|
def _install(destination: Path, force: bool) -> tuple[bool, Path | None]:
|
||
|
|
if _present(destination) and not force:
|
||
|
|
print(f"already exists: {destination}", file=sys.stderr)
|
||
|
|
print(
|
||
|
|
"No changes made. Re-run with --force to back up and replace.",
|
||
|
|
file=sys.stderr,
|
||
|
|
)
|
||
|
|
return False, None
|
||
|
|
|
||
|
|
staging_root, staged_skill = _stage(destination.parent)
|
||
|
|
backup: Path | None = None
|
||
|
|
try:
|
||
|
|
if _present(destination):
|
||
|
|
backup = destination.with_name(
|
||
|
|
f"{destination.name}.backup.{uuid.uuid4().hex[:12]}"
|
||
|
|
)
|
||
|
|
os.replace(destination, backup)
|
||
|
|
try:
|
||
|
|
os.replace(staged_skill, destination)
|
||
|
|
except BaseException:
|
||
|
|
if backup is not None and not _present(destination):
|
||
|
|
os.replace(backup, destination)
|
||
|
|
raise
|
||
|
|
finally:
|
||
|
|
shutil.rmtree(staging_root, ignore_errors=True)
|
||
|
|
|
||
|
|
return True, backup
|
||
|
|
|
||
|
|
|
||
|
|
def main() -> int:
|
||
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
||
|
|
parser.add_argument(
|
||
|
|
"--force",
|
||
|
|
action="store_true",
|
||
|
|
help="Back up and replace an existing Cursor installation",
|
||
|
|
)
|
||
|
|
parser.add_argument("--cursor-home", help="Override Cursor home (default: ~/.cursor)")
|
||
|
|
args = parser.parse_args()
|
||
|
|
|
||
|
|
cursor_home = Path(
|
||
|
|
args.cursor_home
|
||
|
|
or os.environ.get("CURSOR_HOME", Path.home() / ".cursor")
|
||
|
|
).expanduser()
|
||
|
|
destination = cursor_home / "skills" / SKILL_NAME
|
||
|
|
|
||
|
|
installed, backup = _install(destination, args.force)
|
||
|
|
if not installed:
|
||
|
|
return 1
|
||
|
|
if backup is not None:
|
||
|
|
print(f"Cursor: backed up existing skill to {backup}")
|
||
|
|
print(f"Cursor: installed {destination}")
|
||
|
|
print("Start a new Cursor session if the skill does not appear automatically.")
|
||
|
|
return 0
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
raise SystemExit(main())
|