Files
Brummel 69034747c6 feat(install): add --force to repoint symlinks; document worktree caveat
install.sh skipped a symlink pointing at another checkout, so there was
no scripted way to take the live set over. Add a --force flag that
repoints such divergent symlinks at the invoking clone (default run still
skips, stays idempotent). Document in INSTALL.md that the plugin must be
developed in the primary clone, not a worktree, and that --force repoints.

closes #17
2026-06-30 14:16:44 +02:00

82 lines
2.5 KiB
Bash
Executable File

#!/usr/bin/env bash
# Install the skills plugin globally into ~/.claude/.
#
# Each top-level directory that contains a SKILL.md is treated as
# a skill. For each such <name>, creates symlinks:
# ~/.claude/skills/<name> -> <repo>/<name>
# ~/.claude/agents/<name> -> <repo>/<name>/agents (if that dir exists)
# and, for each executable Workflow script the skill ships:
# ~/.claude/workflows/<file>.js -> <repo>/<name>/workflows/<file>.js
# (the flat .claude/workflows/ dir is where the Workflow tool resolves
# named workflows from — e.g. implement/workflows/implement-loop.js).
#
# Idempotent — existing symlinks pointing to this repo are left
# alone; existing entries that point elsewhere are reported and
# skipped. Pass --force to repoint such divergent symlinks at this
# clone (used to take the live set over from another checkout).
set -euo pipefail
FORCE=0
for arg in "$@"; do
case "$arg" in
--force) FORCE=1 ;;
*) echo "unknown argument: $arg (only --force is accepted)" >&2; exit 2 ;;
esac
done
REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CLAUDE_SKILLS="$HOME/.claude/skills"
CLAUDE_AGENTS="$HOME/.claude/agents"
CLAUDE_WORKFLOWS="$HOME/.claude/workflows"
mkdir -p "$CLAUDE_SKILLS" "$CLAUDE_AGENTS" "$CLAUDE_WORKFLOWS"
link_one() {
local src="$1"
local dst="$2"
if [ -L "$dst" ]; then
local existing
existing="$(readlink "$dst")"
if [ "$existing" = "$src" ]; then
echo "ok $dst -> $src"
return 0
fi
if [ "$FORCE" -eq 1 ]; then
ln -sfn "$src" "$dst"
echo "relink $dst -> $src (was $existing)"
return 0
fi
echo "skip $dst already symlinked to $existing (use --force to repoint)"
return 0
fi
if [ -e "$dst" ]; then
echo "skip $dst exists and is not a symlink"
return 0
fi
ln -s "$src" "$dst"
echo "link $dst -> $src"
}
for d in "$REPO_DIR"/*/; do
[ -d "$d" ] || continue
[ -f "$d/SKILL.md" ] || continue
name="$(basename "$d")"
link_one "${d%/}" "$CLAUDE_SKILLS/$name"
if [ -d "$d/agents" ]; then
link_one "${d%/}/agents" "$CLAUDE_AGENTS/$name"
fi
if [ -d "$d/workflows" ]; then
for wf in "$d"workflows/*.js; do
[ -f "$wf" ] || continue
link_one "$wf" "$CLAUDE_WORKFLOWS/$(basename "$wf")"
done
fi
done
echo
echo "Install complete."
echo "Next: add a '## Skills plugin: project facts' section to each"
echo "project's CLAUDE.md (template: $REPO_DIR/templates/CLAUDE.md.fragment)."