also copy sibling files

This commit is contained in:
Jone 2026-04-07 16:48:47 +02:00
parent 014c3c3016
commit 78a3104bae
Signed by: Jone
GPG key ID: 0D98FD3896C39E90
2 changed files with 63 additions and 5 deletions

View file

@ -22,7 +22,7 @@ Use this skill to install another skill from a local path, a directory, or a Git
- Local `SKILL.md` file - Local `SKILL.md` file
- Local skill directory - Local skill directory
- GitHub blob URL to a `SKILL.md` file - GitHub blob URL to a `SKILL.md` file, including sibling supporting files
## Install script ## Install script
@ -50,5 +50,7 @@ The installer prompts for:
1. Source path or URL 1. Source path or URL
2. Target scope: repo or global 2. Target scope: repo or global
3. Skill name if it cannot be inferred 3. Skill name if it cannot be inferred
4. Whether to copy supporting files 4. Whether to copy supporting files for a local directory source
5. Whether to overwrite an existing install 5. Whether to overwrite an existing install
For GitHub blob URLs, supporting files in the same skill directory are downloaded automatically.

View file

@ -35,6 +35,16 @@ rewrite_github_blob_url() {
fi fi
} }
parse_github_blob_url() {
local url="$1"
if [[ "$url" =~ ^https://github\.com/([^/]+)/([^/]+)/blob/([^/]+)/(.*)$ ]]; then
printf '%s\t%s\t%s\t%s\n' "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}" "${BASH_REMATCH[3]}" "${BASH_REMATCH[4]}"
return 0
fi
return 1
}
extract_skill_name() { extract_skill_name() {
local file="$1" local file="$1"
sed -n 's/^name:[[:space:]]*//p' "$file" | head -n 1 sed -n 's/^name:[[:space:]]*//p' "$file" | head -n 1
@ -46,6 +56,45 @@ download_source() {
curl -fsSL "$url" -o "$out" curl -fsSL "$url" -o "$out"
} }
list_github_contents() {
local owner="$1"
local repo="$2"
local ref="$3"
local path="$4"
curl -fsSL -H 'Accept: application/vnd.github+json' \
"https://api.github.com/repos/${owner}/${repo}/contents/${path}?ref=${ref}" | \
python3 -c $'import json,sys\ndata = json.load(sys.stdin)\nitems = data if isinstance(data, list) else [data]\nfor item in items:\n print("%s\\t%s\\t%s" % (item.get("type", ""), item.get("path", ""), item.get("download_url", "")))'
}
download_github_contents() {
local owner="$1"
local repo="$2"
local ref="$3"
local path="$4"
local target_root="$5"
while IFS=$'\t' read -r item_type item_path download_url; do
[[ -z "$item_type" ]] && continue
local relative_path="${item_path#${path}/}"
local destination_path="$target_root/$relative_path"
case "$item_type" in
dir)
download_github_contents "$owner" "$repo" "$ref" "$item_path" "$target_root"
;;
file)
mkdir -p "$(dirname "$destination_path")"
download_source "$download_url" "$destination_path"
;;
*)
printf 'Skipping unsupported GitHub content type: %s (%s)\n' "$item_type" "$item_path" >&2
;;
esac
done < <(list_github_contents "$owner" "$repo" "$ref" "$path")
}
copy_skill_dir() { copy_skill_dir() {
local source_dir="$1" local source_dir="$1"
local target_dir="$2" local target_dir="$2"
@ -82,9 +131,16 @@ source_kind=""
source_path="$source_input" source_path="$source_input"
if [[ "$source_input" =~ ^https?:// ]]; then if [[ "$source_input" =~ ^https?:// ]]; then
source_kind="url" if github_blob_parts="$(parse_github_blob_url "$source_input")"; then
source_path="$(rewrite_github_blob_url "$source_input")" source_kind="github-blob-url"
download_source "$source_path" "$staging_dir/SKILL.md" IFS=$'\t' read -r github_owner github_repo github_ref github_path <<<"$github_blob_parts"
github_skill_dir="$(dirname "$github_path")"
download_github_contents "$github_owner" "$github_repo" "$github_ref" "$github_skill_dir" "$staging_dir"
else
source_kind="url"
source_path="$(rewrite_github_blob_url "$source_input")"
download_source "$source_path" "$staging_dir/SKILL.md"
fi
elif [[ -d "$source_input" ]]; then elif [[ -d "$source_input" ]]; then
source_kind="directory" source_kind="directory"
skill_file="$source_input/SKILL.md" skill_file="$source_input/SKILL.md"