Some checks failed
release / tag (push) Has been cancelled
Phase 1 of mathias/skills extraction (infra#62 Track D — homelab next-step plan addendum). Imports ~/dev/.skills/ verbatim (19 skill dirs + SKILLS_INDEX.md) and adds the installation surface: - Taskfile.yml — install / update / list / release / check targets - install.sh — bootstrap installer for hosts without Task. Idempotent symlink wirer; default checkout at ~/.local/share/skills/ on every host; SKILLS_REF env var pins a tag (default: main). - .gitea/workflows/release.yml — auto-tag every push to main by Bump-Type footer (major/minor/patch, default patch). Skipped when commit contains [skip-release]. - README — usage, versioning, contribution flow, secret-hygiene rule. Phase 1 wires Claude Code only (~/.claude/skills/<name> global + <repo>/.claude/skills/<name> per-repo). Phase 2 adds Crush, opencode, antigravity, and gitea-resident agents (cobalt-dingo, agentsquad) once their skill conventions are researched. Public repo, markdown-only — no secrets, no client names. Verified via pre-push grep before initial push. [skip-release]
131 lines
4.9 KiB
YAML
131 lines
4.9 KiB
YAML
version: '3'
|
|
|
|
# Skills library Taskfile.
|
|
#
|
|
# Primary entry point for project + host installation. Consumer projects
|
|
# do NOT depend on this file directly — they ship their own
|
|
# `skills:install` target that delegates here via `install.sh`. This
|
|
# Taskfile is invoked by maintainers of the skills repo itself, plus by
|
|
# install.sh during the post-clone wire step.
|
|
|
|
vars:
|
|
REPO_URL: 'https://gitea.d-ma.be/mathias/skills.git'
|
|
CHECKOUT_DIR: '{{.HOME}}/.local/share/skills'
|
|
CLAUDE_GLOBAL_DIR: '{{.HOME}}/.claude/skills'
|
|
|
|
tasks:
|
|
|
|
default:
|
|
cmds:
|
|
- task: list
|
|
|
|
list:
|
|
desc: 'Print every skill in this repo'
|
|
cmds:
|
|
- 'ls -1 {{.TASKFILE_DIR}} | grep -Ev "^(Taskfile.yml|install.sh|README.md|SKILLS_INDEX.md|.gitea|.git$)$" || true'
|
|
silent: true
|
|
|
|
install:
|
|
desc: 'Wire skills into every harness detected on this host (Claude Code today, more in phase 2).'
|
|
cmds:
|
|
- task: install:claude:global
|
|
- task: install:claude:repo
|
|
|
|
install:claude:global:
|
|
desc: 'Per-skill symlinks under ~/.claude/skills/<name> — visible in every Claude Code project on this host.'
|
|
cmds:
|
|
- mkdir -p {{.CLAUDE_GLOBAL_DIR}}
|
|
- |
|
|
for skill in $(ls -1 "{{.TASKFILE_DIR}}" | grep -Ev "^(Taskfile.yml|install.sh|README.md|SKILLS_INDEX.md|.gitea|.git$)$"); do
|
|
target="{{.TASKFILE_DIR}}/${skill}"
|
|
link="{{.CLAUDE_GLOBAL_DIR}}/${skill}"
|
|
if [ -L "$link" ] || [ -e "$link" ]; then
|
|
current=$(readlink "$link" 2>/dev/null || true)
|
|
if [ "$current" = "$target" ]; then
|
|
continue
|
|
fi
|
|
rm -rf "$link"
|
|
fi
|
|
ln -s "$target" "$link"
|
|
echo "linked $link → $target"
|
|
done
|
|
|
|
install:claude:repo:
|
|
desc: 'Per-skill symlinks under $(pwd)/.claude/skills/<name> when invoked inside a git repo.'
|
|
cmds:
|
|
- |
|
|
if ! git rev-parse --show-toplevel >/dev/null 2>&1; then
|
|
echo "not in a git repo — skipping per-repo wire"; exit 0
|
|
fi
|
|
repo=$(git rev-parse --show-toplevel)
|
|
if [ "$repo" = "{{.TASKFILE_DIR}}" ]; then
|
|
echo "running from skills repo itself — skipping per-repo wire"; exit 0
|
|
fi
|
|
target_dir="$repo/.claude/skills"
|
|
mkdir -p "$target_dir"
|
|
for skill in $(ls -1 "{{.TASKFILE_DIR}}" | grep -Ev "^(Taskfile.yml|install.sh|README.md|SKILLS_INDEX.md|.gitea|.git$)$"); do
|
|
target="{{.TASKFILE_DIR}}/${skill}"
|
|
link="${target_dir}/${skill}"
|
|
if [ -L "$link" ] || [ -e "$link" ]; then
|
|
current=$(readlink "$link" 2>/dev/null || true)
|
|
if [ "$current" = "$target" ]; then
|
|
continue
|
|
fi
|
|
rm -rf "$link"
|
|
fi
|
|
ln -s "$target" "$link"
|
|
echo "linked $link → $target"
|
|
done
|
|
|
|
update:
|
|
desc: 'git pull the canonical checkout then re-run install.'
|
|
cmds:
|
|
- |
|
|
if [ ! -d "{{.CHECKOUT_DIR}}/.git" ]; then
|
|
echo "no canonical checkout at {{.CHECKOUT_DIR}} — run install.sh first"; exit 1
|
|
fi
|
|
git -C "{{.CHECKOUT_DIR}}" pull --ff-only
|
|
- task: install
|
|
|
|
release:
|
|
desc: 'Tag HEAD per Bump-Type in the latest commit footer. Normally CI handles this — run locally only when CI is unavailable.'
|
|
cmds:
|
|
- |
|
|
latest=$(git -C "{{.TASKFILE_DIR}}" describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0")
|
|
major=$(echo "$latest" | sed -E 's/^v([0-9]+)\.([0-9]+)\.([0-9]+)$/\1/')
|
|
minor=$(echo "$latest" | sed -E 's/^v([0-9]+)\.([0-9]+)\.([0-9]+)$/\2/')
|
|
patch=$(echo "$latest" | sed -E 's/^v([0-9]+)\.([0-9]+)\.([0-9]+)$/\3/')
|
|
bump=$(git -C "{{.TASKFILE_DIR}}" log -1 --pretty=%B | grep -iE "^Bump-Type:" | head -1 | awk '{print tolower($2)}')
|
|
case "$bump" in
|
|
major) major=$((major + 1)); minor=0; patch=0 ;;
|
|
minor) minor=$((minor + 1)); patch=0 ;;
|
|
*) patch=$((patch + 1)) ;;
|
|
esac
|
|
next="v${major}.${minor}.${patch}"
|
|
echo "tagging $next (previous $latest, bump=${bump:-patch})"
|
|
git -C "{{.TASKFILE_DIR}}" tag -a "$next" -m "release $next"
|
|
echo "now: git push origin $next"
|
|
|
|
check:
|
|
desc: 'Sanity check — every skill dir has a SKILL.md, no stray files at root.'
|
|
cmds:
|
|
- |
|
|
missing=0
|
|
for skill in $(ls -1 "{{.TASKFILE_DIR}}" | grep -Ev "^(Taskfile.yml|install.sh|README.md|SKILLS_INDEX.md|.gitea|.git$)$"); do
|
|
dir="{{.TASKFILE_DIR}}/${skill}"
|
|
if [ ! -d "$dir" ]; then
|
|
echo "ERROR: $skill is not a directory" >&2
|
|
missing=$((missing + 1))
|
|
continue
|
|
fi
|
|
if [ ! -f "$dir/SKILL.md" ]; then
|
|
echo "ERROR: $dir missing SKILL.md" >&2
|
|
missing=$((missing + 1))
|
|
fi
|
|
done
|
|
if [ $missing -gt 0 ]; then
|
|
echo "$missing skill(s) failed structure check" >&2
|
|
exit 1
|
|
fi
|
|
echo "all skills have SKILL.md"
|