#!/usr/bin/env bash # install.sh — bootstrap installer for the skills library. # # Usage (one-liner, hosts without Task): # curl -fsSL https://gitea.d-ma.be/mathias/skills/raw/branch/main/install.sh | bash # # Pinned to a specific tag: # SKILLS_REF=v0.1.0 bash install.sh # # Idempotent: re-running pulls the latest changes for the configured ref # (default: main) and re-wires symlinks. Existing correct links are # left alone; mismatched ones are replaced. set -euo pipefail REPO_URL="${SKILLS_REPO_URL:-https://gitea.d-ma.be/mathias/skills.git}" REF="${SKILLS_REF:-main}" CHECKOUT_DIR="${SKILLS_CHECKOUT_DIR:-$HOME/.local/share/skills}" CLAUDE_GLOBAL_DIR="${CLAUDE_SKILLS_DIR:-$HOME/.claude/skills}" log() { printf '[skills] %s\n' "$*"; } ensure_checkout() { if [ -d "$CHECKOUT_DIR/.git" ]; then log "updating $CHECKOUT_DIR" git -C "$CHECKOUT_DIR" fetch --tags --quiet git -C "$CHECKOUT_DIR" checkout --quiet "$REF" if git -C "$CHECKOUT_DIR" symbolic-ref -q HEAD >/dev/null; then # on a branch — fast-forward git -C "$CHECKOUT_DIR" pull --ff-only --quiet fi else log "cloning $REPO_URL into $CHECKOUT_DIR (ref=$REF)" mkdir -p "$(dirname "$CHECKOUT_DIR")" git clone --quiet "$REPO_URL" "$CHECKOUT_DIR" git -C "$CHECKOUT_DIR" checkout --quiet "$REF" fi } list_skills() { # Every top-level entry that isn't a known meta file. (cd "$CHECKOUT_DIR" && ls -1) | grep -Ev '^(Taskfile\.yml|install\.sh|README\.md|SKILLS_INDEX\.md|\.gitea|\.git)$' || true } link_skill() { # link_skill local target_dir="$1" local skill="$2" local target="$CHECKOUT_DIR/$skill" local link="$target_dir/$skill" if [ -L "$link" ] || [ -e "$link" ]; then local current current=$(readlink "$link" 2>/dev/null || true) if [ "$current" = "$target" ]; then return fi rm -rf "$link" fi ln -s "$target" "$link" log "linked $link → $target" } wire_claude_global() { mkdir -p "$CLAUDE_GLOBAL_DIR" while IFS= read -r skill; do [ -n "$skill" ] || continue link_skill "$CLAUDE_GLOBAL_DIR" "$skill" done < <(list_skills) } wire_claude_repo() { # Only wire per-repo when invoked from inside a git repo and it isn't # the skills repo itself. if ! git rev-parse --show-toplevel >/dev/null 2>&1; then return fi local repo repo=$(git rev-parse --show-toplevel) if [ "$repo" = "$CHECKOUT_DIR" ]; then return fi local target_dir="$repo/.claude/skills" mkdir -p "$target_dir" while IFS= read -r skill; do [ -n "$skill" ] || continue link_skill "$target_dir" "$skill" done < <(list_skills) } main() { ensure_checkout wire_claude_global wire_claude_repo log "done — $(list_skills | wc -l | tr -d ' ') skill(s) wired at ref=$REF" } main "$@"