From 9fe42f03271e5c9e37b8643867852ac18f192845 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 25 Aug 2026 14:46:29 +1000 Subject: [PATCH] feat(plugin): add worktree skill --- .claude-plugin/marketplace.json | 5 + .../engineering/.claude-plugin/plugin.json | 10 ++ plugins/engineering/skills/worktree/SKILL.md | 41 ++++++ .../skills/worktree/scripts/worktree.sh | 128 ++++++++++++++++++ 4 files changed, 184 insertions(+) create mode 100644 plugins/engineering/.claude-plugin/plugin.json create mode 100644 plugins/engineering/skills/worktree/SKILL.md create mode 100755 plugins/engineering/skills/worktree/scripts/worktree.sh diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index a8378c2..a3b2824 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -11,6 +11,11 @@ "name": "deepwiki", "description": "AI-generated documentation for GitHub repositories", "source": "./plugins/deepwiki" + }, + { + "name": "engineering", + "description": "Reusable engineering workflow skills", + "source": "./plugins/engineering" } ] } diff --git a/plugins/engineering/.claude-plugin/plugin.json b/plugins/engineering/.claude-plugin/plugin.json new file mode 100644 index 0000000..ed72ffa --- /dev/null +++ b/plugins/engineering/.claude-plugin/plugin.json @@ -0,0 +1,10 @@ +{ + "name": "engineering", + "description": "Reusable engineering workflow skills for repository maintenance and delivery.", + "author": { + "name": "AllAgents" + }, + "version": "1.0.0", + "category": "development", + "homepage": "https://github.com/EntityProcess/allagents/tree/main/plugins/engineering" +} diff --git a/plugins/engineering/skills/worktree/SKILL.md b/plugins/engineering/skills/worktree/SKILL.md new file mode 100644 index 0000000..0c813a4 --- /dev/null +++ b/plugins/engineering/skills/worktree/SKILL.md @@ -0,0 +1,41 @@ +--- +name: worktree +description: Creates and removes isolated Git worktrees under a consistent repository sibling directory. Use when starting feature or fix work in a dedicated worktree, or cleaning up a finished worktree. +--- + +# Git Worktrees + +Resolve this skill's directory, then invoke its bundled `scripts/worktree.sh`. Pass `-C ` when the shell is not already inside the target repository. + +## Add + +```bash +/scripts/worktree.sh -C add [start-point] +``` + +The script: + +1. uses an existing local branch when present; +2. creates a tracking branch when `/` exists; +3. otherwise creates the branch from `start-point`, the remote default branch, or `HEAD`; +4. prints the created worktree path. + +Fetch the remote before adding when the worktree must start from its latest state: + +```bash +git -C fetch origin +/scripts/worktree.sh -C add feat/example origin/main +``` + +Worktrees default to `__worktrees/`. Set `WORKTREE_ROOT` to use another parent and `WORKTREE_REMOTE` to use a remote other than `origin`. + +## Remove + +```bash +/scripts/worktree.sh -C remove +/scripts/worktree.sh -C remove --force +``` + +Normal removal preserves Git's dirty-worktree protection. Use `--force` only when discarding the worktree's uncommitted files is intended. Removal unregisters and deletes the worktree directory; it leaves the branch intact. + +An add is complete when the script prints the new path and `git -C worktree list` contains it. A removal is complete when that path is absent. diff --git a/plugins/engineering/skills/worktree/scripts/worktree.sh b/plugins/engineering/skills/worktree/scripts/worktree.sh new file mode 100755 index 0000000..08679e1 --- /dev/null +++ b/plugins/engineering/skills/worktree/scripts/worktree.sh @@ -0,0 +1,128 @@ +#!/usr/bin/env bash +set -euo pipefail + +usage() { + cat <<'EOF' +Usage: + worktree.sh [-C ] add [start-point] + worktree.sh [-C ] remove [--force] + +Worktrees are created under __worktrees by default. Override the +location with WORKTREE_ROOT and the default remote with WORKTREE_REMOTE. +Branch slashes become dashes in directory names. +EOF +} + +fail() { + printf 'worktree: %s\n' "$*" >&2 + exit 1 +} + +repo_dir="." +if [[ "${1:-}" == "-C" ]]; then + [[ $# -ge 3 ]] || { + usage >&2 + exit 2 + } + repo_dir="$2" + shift 2 +fi + +repo_root="$(git -C "$repo_dir" rev-parse --show-toplevel 2>/dev/null)" || + fail "repository not found: $repo_dir" +remote="${WORKTREE_REMOTE:-origin}" +[[ -n "$remote" ]] || fail "WORKTREE_REMOTE must not be empty" + +configured_root="${WORKTREE_ROOT:-${repo_root}__worktrees}" +if [[ "$configured_root" = /* ]]; then + raw_worktree_root="${configured_root%/}" +else + raw_worktree_root="${repo_root}/${configured_root%/}" +fi + +worktree_path_for_branch() { + local branch="$1" + printf '%s/%s\n' "$worktree_root" "${branch//\//-}" +} + +default_start_point() { + local remote_head + remote_head="$(git -C "$repo_root" symbolic-ref --quiet --short "refs/remotes/$remote/HEAD" 2>/dev/null || true)" + printf '%s\n' "${remote_head:-HEAD}" +} + +command="${1:-}" +case "$command" in + add) + [[ $# -ge 2 && $# -le 3 ]] || { + usage >&2 + exit 2 + } + + branch="$2" + start_point="${3:-$(default_start_point)}" + git -C "$repo_root" check-ref-format --branch "$branch" >/dev/null 2>&1 || + fail "invalid branch name: $branch" + + mkdir -p "$raw_worktree_root" + worktree_root="$(cd "$raw_worktree_root" && pwd -P)" + path="$(worktree_path_for_branch "$branch")" + [[ ! -e "$path" ]] || fail "path already exists: $path" + + if git -C "$repo_root" show-ref --verify --quiet "refs/heads/$branch"; then + git -C "$repo_root" worktree add "$path" "$branch" + elif git -C "$repo_root" show-ref --verify --quiet "refs/remotes/$remote/$branch"; then + git -C "$repo_root" worktree add --track -b "$branch" "$path" "$remote/$branch" + else + git -C "$repo_root" worktree add -b "$branch" "$path" "$start_point" + fi + + printf '%s\n' "$path" + ;; + + remove) + shift + force=() + if [[ "${1:-}" == "--force" ]]; then + force=(--force) + shift + fi + [[ $# -eq 1 ]] || { + usage >&2 + exit 2 + } + + [[ -d "$raw_worktree_root" ]] || + fail "worktree root does not exist: $raw_worktree_root" + worktree_root="$(cd "$raw_worktree_root" && pwd -P)" + + target="$1" + if [[ "$target" = /* ]]; then + candidate="$target" + else + candidate="$repo_root/$target" + fi + if [[ -d "$candidate" ]]; then + path="$(cd "$candidate" && pwd -P)" + else + path="$(worktree_path_for_branch "$target")" + fi + + case "$path" in + "$worktree_root"/*) ;; + *) fail "refusing to remove a worktree outside $worktree_root" ;; + esac + + [[ -d "$path" ]] || fail "worktree does not exist: $path" + git -C "$repo_root" worktree remove "${force[@]}" "$path" + ;; + + -h|--help|help) + usage + ;; + + *) + usage >&2 + exit 2 + ;; +esac