Files
claude-skills/scripts/build.sh
vitya 074cbe9065 fix(scripts): make install.sh / build.sh work on stock macOS
Stock macOS ships bash 3.2 (frozen 2007 due to GPLv3) and BSD find.
Both scripts used `mapfile` (bash 4+) and `find -printf` (GNU only),
so a fresh Mac user running `bash scripts/install.sh` died on line 11
before copying anything. Replace with a portable shell glob — same
sort order, no `find` dependency, works on bash 3.2 and 4+.

Verified on git-bash: 16 skills discovered, install dry-run copies all,
`build.sh` produces a valid archive.

See .wiki/concepts/install-portability.md for the full gotcha.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 20:41:11 +03:00

62 lines
2.0 KiB
Bash

#!/usr/bin/env bash
# Build .skill archives from skills/<name>/ into dist/<name>.skill
# Usage: build.sh [name...] (no args = all)
#
# Uses `zip` if available; otherwise delegates to scripts/build.ps1
# (so the script works on Linux, macOS, and Windows-with-git-bash without
# requiring `zip` on Windows).
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
SRC="$ROOT/skills"
DIST="$ROOT/dist"
if command -v zip >/dev/null 2>&1; then
mkdir -p "$DIST"
if [ "$#" -eq 0 ]; then
# Portable across bash 3.2 (stock macOS) and bash 4+ (Linux, git-bash):
# avoid `mapfile` (bash 4+) and `find -printf` (GNU find only).
names=()
for d in "$SRC"/*/; do
[ -d "$d" ] || continue
names+=("$(basename "$d")")
done
IFS=$'\n' names=($(printf '%s\n' "${names[@]}" | sort))
unset IFS
else
names=("$@")
fi
for name in "${names[@]}"; do
src_dir="$SRC/$name"
if [ ! -d "$src_dir" ]; then
echo "skip: $name (not found in skills/)" >&2
continue
fi
if [ ! -f "$src_dir/SKILL.md" ]; then
echo "skip: $name (missing SKILL.md)" >&2
continue
fi
out="$DIST/$name.skill"
rm -f "$out"
( cd "$SRC" && zip -qr "$out" "$name" )
echo "built: dist/$name.skill"
done
elif command -v powershell.exe >/dev/null 2>&1; then
# Windows fallback: delegate to build.ps1 (proper ZIP via .NET API).
# PS array binding via -File is fragile (commas don't always split into [string[]]),
# so call build.ps1 once per skill and let the bash loop do the work.
ps1="$SCRIPT_DIR/build.ps1"
ps1_win="$(cygpath -w "$ps1" 2>/dev/null || echo "$ps1")"
if [ "$#" -eq 0 ]; then
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "$ps1_win"
else
for name in "$@"; do
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "$ps1_win" -Names "$name"
done
fi
else
echo "error: need either 'zip' (Linux/macOS) or PowerShell (Windows) to build .skill archives" >&2
exit 1
fi