feat: auto-discover custom skills from assets/skills/
- setup.sh skills command now does two things: 1. Installs registry skills from <platform>-skills.txt 2. Auto-discovers and copies custom skill folders from assets/skills/ - Added SKILLS_DIR config (default: ~/.copilot/skills/) - Added download_dir_to helper for copying skill folders remotely - Created assets/skills/ for team-maintained custom skills
This commit is contained in:
parent
b5e7de10e7
commit
20446c5224
@ -41,7 +41,7 @@ That's it.
|
|||||||
|
|
||||||
| Command | What It Does |
|
| Command | What It Does |
|
||||||
|---------|-------------|
|
|---------|-------------|
|
||||||
| `setup.sh skills [platform]` | Install skills from a curated list |
|
| `setup.sh skills [platform]` | Install registry skills + custom skills (auto-discovered) |
|
||||||
| `setup.sh agents` | Install all agent prompt files (auto-discovered) |
|
| `setup.sh agents` | Install all agent prompt files (auto-discovered) |
|
||||||
| `setup.sh instructions` | Install all instruction rule files (auto-discovered) |
|
| `setup.sh instructions` | Install all instruction rule files (auto-discovered) |
|
||||||
| `setup.sh all [platform]` | All of the above in one shot |
|
| `setup.sh all [platform]` | All of the above in one shot |
|
||||||
@ -59,19 +59,21 @@ That's it.
|
|||||||
|
|
||||||
| Asset | Default Location | Override |
|
| Asset | Default Location | Override |
|
||||||
|-------|-----------------|----------|
|
|-------|-----------------|----------|
|
||||||
| Skills | Managed by `npx skills` CLI | — |
|
| Registry skills | Managed by `npx skills` CLI | — |
|
||||||
|
| Custom skills | `~/.copilot/skills/` | `SKILLS_DIR` |
|
||||||
| Agents | `~/.copilot/agents/` | `AGENTS_DIR` |
|
| Agents | `~/.copilot/agents/` | `AGENTS_DIR` |
|
||||||
| Instructions | `./instructions/` | `INSTRUCTIONS_DIR` |
|
| Instructions | `./instructions/` | `INSTRUCTIONS_DIR` |
|
||||||
|
|
||||||
## Adding New Assets
|
## Adding New Assets
|
||||||
|
|
||||||
- **Agents or instructions** — Drop the file into `assets/agents/` or `assets/instructions/` and push. The script discovers files from the directory automatically. No manifest to update.
|
- **Agents or instructions** — Drop the file into `assets/agents/` or `assets/instructions/` and push. Auto-discovered.
|
||||||
- **Skills** — Add the install command to the appropriate `.txt` file (e.g., `ios-skills.txt`). One command per line.
|
- **Custom skills** — Add a folder with a `SKILL.md` to `assets/skills/` and push. Auto-discovered.
|
||||||
|
- **Registry skills** — Add the install entry to the appropriate `.txt` file (e.g., `ios-skills.txt`). One per line.
|
||||||
|
|
||||||
## How It Works
|
## How It Works
|
||||||
|
|
||||||
| Mode | Agents / Instructions | Skills |
|
| Mode | Agents / Instructions / Custom Skills | Registry Skills |
|
||||||
|------|----------------------|--------|
|
|------|---------------------------------------|----------------|
|
||||||
| **Local** (cloned repo) | `find` scans the directory | Reads the `.txt` file |
|
| **Local** (cloned repo) | `find` scans the directory | Reads the `.txt` file |
|
||||||
| **Remote** (no clone) | Queries GitLab/GitHub API to list files | Downloads the `.txt` file |
|
| **Remote** (no clone) | Queries GitLab/GitHub API to list files | Downloads the `.txt` file |
|
||||||
|
|
||||||
@ -83,6 +85,9 @@ assets/
|
|||||||
ios-skills.txt ← curated iOS skills (one per line)
|
ios-skills.txt ← curated iOS skills (one per line)
|
||||||
android-skills.txt ← curated Android skills
|
android-skills.txt ← curated Android skills
|
||||||
shared-skills.txt ← curated cross-platform skills
|
shared-skills.txt ← curated cross-platform skills
|
||||||
|
skills/ ← custom skill folders (auto-discovered)
|
||||||
|
my-skill/
|
||||||
|
SKILL.md
|
||||||
agents/ ← agent prompt files (auto-discovered)
|
agents/ ← agent prompt files (auto-discovered)
|
||||||
instructions/ ← instruction rule files (auto-discovered)
|
instructions/ ← instruction rule files (auto-discovered)
|
||||||
```
|
```
|
||||||
@ -92,6 +97,5 @@ assets/
|
|||||||
| Variable | Purpose | Required? |
|
| Variable | Purpose | Required? |
|
||||||
|----------|---------|-----------|
|
|----------|---------|-----------|
|
||||||
| `ASSETS_BASE_URL` | Base URL for remote downloads | Only without a clone |
|
| `ASSETS_BASE_URL` | Base URL for remote downloads | Only without a clone |
|
||||||
| `AGENTS_DIR` | Custom agents install path | No |
|
| `AGENTS_DIR` | Custom agents install path | No || `SKILLS_DIR` | Custom skills install path | No || `INSTRUCTIONS_DIR` | Custom instructions install path | No |
|
||||||
| `INSTRUCTIONS_DIR` | Custom instructions install path | No |
|
|
||||||
| `REPO_TOKEN` | Auth token for private repos | Only if API rejects |
|
| `REPO_TOKEN` | Auth token for private repos | Only if API rejects |
|
||||||
@ -13,11 +13,12 @@ set -euo pipefail
|
|||||||
# bash <(curl -fsSL "$ASSETS_BASE_URL/setup.sh") all ios
|
# bash <(curl -fsSL "$ASSETS_BASE_URL/setup.sh") all ios
|
||||||
# ─────────────────────────────────────────────────────────────────────
|
# ─────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
VERSION="2.0.0"
|
VERSION="2.1.0"
|
||||||
|
|
||||||
# ── Configuration (override with env vars) ───────────────────────────
|
# ── Configuration (override with env vars) ───────────────────────────
|
||||||
ASSETS_BASE_URL="${ASSETS_BASE_URL:-}"
|
ASSETS_BASE_URL="${ASSETS_BASE_URL:-}"
|
||||||
AGENTS_DIR="${AGENTS_DIR:-$HOME/.copilot/agents}"
|
AGENTS_DIR="${AGENTS_DIR:-$HOME/.copilot/agents}"
|
||||||
|
SKILLS_DIR="${SKILLS_DIR:-$HOME/.copilot/skills}"
|
||||||
INSTRUCTIONS_DIR="${INSTRUCTIONS_DIR:-./instructions}"
|
INSTRUCTIONS_DIR="${INSTRUCTIONS_DIR:-./instructions}"
|
||||||
REPO_TOKEN="${REPO_TOKEN:-}"
|
REPO_TOKEN="${REPO_TOKEN:-}"
|
||||||
|
|
||||||
@ -135,34 +136,99 @@ download_to() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Download an entire remote directory (one level deep).
|
||||||
|
download_dir_to() {
|
||||||
|
local src_subdir="$1" dest_dir="$2"
|
||||||
|
mkdir -p "$dest_dir"
|
||||||
|
if [[ "$MODE" == "local" ]]; then
|
||||||
|
cp -R "$ASSETS_DIR/$src_subdir/"* "$dest_dir/" 2>/dev/null || true
|
||||||
|
else
|
||||||
|
local files
|
||||||
|
files=$(list_remote_files "$src_subdir" "")
|
||||||
|
while IFS= read -r file; do
|
||||||
|
[[ -z "$file" ]] && continue
|
||||||
|
curl -fsSL ${REPO_TOKEN:+-H "Authorization: Bearer $REPO_TOKEN"} "$ASSETS_BASE_URL/$src_subdir/$file" -o "$dest_dir/$file"
|
||||||
|
done <<< "$files"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
# ── Commands ─────────────────────────────────────────────────────────
|
# ── Commands ─────────────────────────────────────────────────────────
|
||||||
|
|
||||||
# -- skills [platform] ────────────────────────────────────────────────
|
# -- skills [platform] ────────────────────────────────────────────────
|
||||||
# Reads a plain-text skills file. Each non-empty, non-comment line is
|
# 1. Install registry skills from <platform>-skills.txt
|
||||||
# passed to `npx skills add`.
|
# 2. Auto-discover and copy custom skills from assets/skills/
|
||||||
cmd_skills() {
|
cmd_skills() {
|
||||||
local platform="${1:-shared}"
|
local platform="${1:-shared}"
|
||||||
local manifest="${platform}-skills.txt"
|
local manifest="${platform}-skills.txt"
|
||||||
|
|
||||||
heading "Skills ($platform)"
|
# ── Registry skills ──
|
||||||
|
heading "Registry Skills ($platform)"
|
||||||
|
|
||||||
local content
|
local content
|
||||||
content="$(fetch "$manifest")" || fail "Could not fetch $manifest"
|
content="$(fetch "$manifest" 2>/dev/null)" || content=""
|
||||||
|
|
||||||
local count=0
|
local reg_count=0
|
||||||
|
if [[ -n "$content" ]]; then
|
||||||
while IFS= read -r line; do
|
while IFS= read -r line; do
|
||||||
[[ -z "$line" || "$line" == \#* ]] && continue
|
[[ -z "$line" || "$line" == \#* ]] && continue
|
||||||
info "npx skills add $line"
|
info "npx skills add $line"
|
||||||
read -r -a args <<< "$line"
|
read -r -a args <<< "$line"
|
||||||
npx skills add "${args[@]}"
|
npx skills add "${args[@]}"
|
||||||
count=$((count + 1))
|
reg_count=$((reg_count + 1))
|
||||||
done <<< "$content"
|
done <<< "$content"
|
||||||
|
|
||||||
if [[ $count -eq 0 ]]; then
|
|
||||||
warn "No entries in $manifest — nothing to install."
|
|
||||||
else
|
|
||||||
ok "$count skill(s) installed. Restart your editor if they don't appear."
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [[ $reg_count -eq 0 ]]; then
|
||||||
|
warn "No entries in $manifest."
|
||||||
|
else
|
||||||
|
ok "$reg_count registry skill(s) installed."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── Custom / local skills ──
|
||||||
|
heading "Custom Skills → $SKILLS_DIR"
|
||||||
|
mkdir -p "$SKILLS_DIR"
|
||||||
|
|
||||||
|
local skill_dirs count=0
|
||||||
|
|
||||||
|
if [[ "$MODE" == "local" ]]; then
|
||||||
|
if [[ -d "$ASSETS_DIR/skills" ]]; then
|
||||||
|
skill_dirs=$(find "$ASSETS_DIR/skills" -mindepth 1 -maxdepth 1 -type d -exec basename {} \; | sort)
|
||||||
|
else
|
||||||
|
skill_dirs=""
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# Remote: list subdirectories in skills/ via API.
|
||||||
|
# The API returns entries — filter for directories (type "tree" in GitLab, "dir" in GitHub).
|
||||||
|
local api_url
|
||||||
|
api_url=$(derive_api_url "skills") || { warn "Cannot list remote skills directories."; return 0; }
|
||||||
|
|
||||||
|
local auth_header=""
|
||||||
|
[[ -n "$REPO_TOKEN" ]] && auth_header="Authorization: Bearer $REPO_TOKEN"
|
||||||
|
|
||||||
|
local response
|
||||||
|
response=$(curl -fsSL ${auth_header:+-H "$auth_header"} "$api_url" 2>/dev/null) || { warn "Could not list remote skills."; return 0; }
|
||||||
|
|
||||||
|
# GitLab uses "type":"tree" for dirs, GitHub uses "type":"dir"
|
||||||
|
skill_dirs=$(echo "$response" \
|
||||||
|
| grep -o '"name":"[^"]*"[^}]*"type":"\(tree\|dir\)"' \
|
||||||
|
| grep -o '"name":"[^"]*"' \
|
||||||
|
| sed 's/"name":"//;s/"//' || true)
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "$skill_dirs" ]]; then
|
||||||
|
warn "No custom skill folders found in assets/skills/."
|
||||||
|
else
|
||||||
|
while IFS= read -r skill; do
|
||||||
|
[[ -z "$skill" ]] && continue
|
||||||
|
info "$skill"
|
||||||
|
download_dir_to "skills/$skill" "$SKILLS_DIR/$skill"
|
||||||
|
count=$((count + 1))
|
||||||
|
done <<< "$skill_dirs"
|
||||||
|
ok "$count custom skill(s) installed."
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf "\n"
|
||||||
|
ok "Restart your editor if skills don't appear."
|
||||||
}
|
}
|
||||||
|
|
||||||
# -- agents ───────────────────────────────────────────────────────────
|
# -- agents ───────────────────────────────────────────────────────────
|
||||||
@ -243,7 +309,7 @@ ${BOLD}USAGE${NC}
|
|||||||
setup.sh <command> [platform]
|
setup.sh <command> [platform]
|
||||||
|
|
||||||
${BOLD}COMMANDS${NC}
|
${BOLD}COMMANDS${NC}
|
||||||
skills [platform] Install skills from a curated list
|
skills [platform] Install registry + custom skills (auto-discovered)
|
||||||
agents Install all agent prompt files (auto-discovered)
|
agents Install all agent prompt files (auto-discovered)
|
||||||
instructions Install all instruction files (auto-discovered)
|
instructions Install all instruction files (auto-discovered)
|
||||||
all [platform] Install everything at once
|
all [platform] Install everything at once
|
||||||
@ -269,6 +335,7 @@ ${BOLD}EXAMPLES${NC}
|
|||||||
${BOLD}ENVIRONMENT VARIABLES${NC}
|
${BOLD}ENVIRONMENT VARIABLES${NC}
|
||||||
ASSETS_BASE_URL Base URL for remote downloads (required without clone)
|
ASSETS_BASE_URL Base URL for remote downloads (required without clone)
|
||||||
AGENTS_DIR Install location for agents (default: ~/.copilot/agents)
|
AGENTS_DIR Install location for agents (default: ~/.copilot/agents)
|
||||||
|
SKILLS_DIR Install location for custom skills (default: ~/.copilot/skills)
|
||||||
INSTRUCTIONS_DIR Install location for instructions (default: ./instructions)
|
INSTRUCTIONS_DIR Install location for instructions (default: ./instructions)
|
||||||
REPO_TOKEN Auth token for private repos (optional)
|
REPO_TOKEN Auth token for private repos (optional)
|
||||||
|
|
||||||
|
|||||||
15
assets/skills/README.md
Normal file
15
assets/skills/README.md
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# Custom Skills
|
||||||
|
|
||||||
|
Drop skill folders here. Each folder should contain a `SKILL.md` file.
|
||||||
|
|
||||||
|
```
|
||||||
|
assets/skills/
|
||||||
|
my-custom-skill/
|
||||||
|
SKILL.md
|
||||||
|
references/ (optional)
|
||||||
|
another-skill/
|
||||||
|
SKILL.md
|
||||||
|
```
|
||||||
|
|
||||||
|
The setup script auto-discovers and installs every folder in this directory.
|
||||||
|
No manifest to update — just add the folder and push.
|
||||||
@ -46,10 +46,11 @@ Keep the approved list in a single repo and organize by platform. This repo alre
|
|||||||
|
|
||||||
```text
|
```text
|
||||||
/assets/
|
/assets/
|
||||||
setup.sh ← the installer (auto-discovers agents & instructions)
|
setup.sh ← the installer (auto-discovers everything)
|
||||||
ios-skills.txt ← curated iOS skills (one per line)
|
ios-skills.txt ← curated iOS skills (one per line)
|
||||||
android-skills.txt ← curated Android skills
|
android-skills.txt ← curated Android skills
|
||||||
shared-skills.txt ← curated cross-platform skills
|
shared-skills.txt ← curated cross-platform skills
|
||||||
|
skills/ ← custom skill folders (auto-discovered)
|
||||||
agents/ ← agent prompt files (auto-discovered)
|
agents/ ← agent prompt files (auto-discovered)
|
||||||
instructions/ ← instruction rule files (auto-discovered)
|
instructions/ ← instruction rule files (auto-discovered)
|
||||||
```
|
```
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user