100 lines
3.1 KiB
Bash
Executable File
100 lines
3.1 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
SKILL_NAME="${1:-}"
|
|
VERSION="${2:-latest}"
|
|
REPO_URL="${OMNICLAW_SKILLS_REPO:-https://git.omniclaw.store/zsb/omniclaw-skills.git}"
|
|
RAW_BASE_URL="${OMNICLAW_SKILLS_RAW_BASE_URL:-https://git.omniclaw.store/zsb/omniclaw-skills/raw/branch/main}"
|
|
DEST_DIR="${CODEX_HOME:-$HOME/.codex}/skills"
|
|
|
|
if [[ -z "$SKILL_NAME" ]]; then
|
|
echo "Usage: install.sh <skill-name> [version]" >&2
|
|
exit 2
|
|
fi
|
|
|
|
require_cmd() {
|
|
if ! command -v "$1" >/dev/null 2>&1; then
|
|
echo "Missing required command: $1" >&2
|
|
exit 2
|
|
fi
|
|
}
|
|
|
|
require_cmd mktemp
|
|
require_cmd node
|
|
require_cmd tar
|
|
require_cmd shasum
|
|
|
|
tmp_dir="$(mktemp -d)"
|
|
cleanup() {
|
|
rm -rf "$tmp_dir"
|
|
}
|
|
trap cleanup EXIT
|
|
|
|
manifest="$tmp_dir/manifest.json"
|
|
if [[ -d "$RAW_BASE_URL" && -f "$RAW_BASE_URL/registry/manifest.json" ]]; then
|
|
cp "$RAW_BASE_URL/registry/manifest.json" "$manifest"
|
|
elif command -v curl >/dev/null 2>&1; then
|
|
curl -fsSL "$RAW_BASE_URL/registry/manifest.json" -o "$manifest" || true
|
|
elif command -v wget >/dev/null 2>&1; then
|
|
wget -qO "$manifest" "$RAW_BASE_URL/registry/manifest.json" || true
|
|
else
|
|
: > "$manifest"
|
|
fi
|
|
|
|
if [[ ! -s "$manifest" ]]; then
|
|
require_cmd git
|
|
git clone --depth 1 "$REPO_URL" "$tmp_dir/repo"
|
|
if [[ ! -f "$tmp_dir/repo/registry/manifest.json" ]]; then
|
|
echo "Unable to find registry/manifest.json from $REPO_URL" >&2
|
|
exit 1
|
|
fi
|
|
cp "$tmp_dir/repo/registry/manifest.json" "$manifest"
|
|
RAW_BASE_URL="$tmp_dir/repo"
|
|
fi
|
|
|
|
node_script='
|
|
const fs = require("fs");
|
|
const manifest = JSON.parse(fs.readFileSync(process.argv[1], "utf8"));
|
|
const name = process.argv[2];
|
|
const version = process.argv[3];
|
|
const skill = manifest.skills.find((item) => item.name === name && (version === "latest" || item.version === version));
|
|
if (!skill) {
|
|
console.error(`Skill not found: ${name}@${version}`);
|
|
process.exit(1);
|
|
}
|
|
console.log(JSON.stringify(skill));
|
|
'
|
|
|
|
skill_json="$(node -e "$node_script" "$manifest" "$SKILL_NAME" "$VERSION")"
|
|
package_path="$(printf '%s' "$skill_json" | node -e 'let s="";process.stdin.on("data",c=>s+=c);process.stdin.on("end",()=>console.log(JSON.parse(s).package));')"
|
|
expected_sha="$(printf '%s' "$skill_json" | node -e 'let s="";process.stdin.on("data",c=>s+=c);process.stdin.on("end",()=>console.log(JSON.parse(s).sha256));')"
|
|
|
|
archive="$tmp_dir/skill.tar.gz"
|
|
if [[ -d "$RAW_BASE_URL" ]]; then
|
|
cp "$RAW_BASE_URL/$package_path" "$archive"
|
|
elif command -v curl >/dev/null 2>&1; then
|
|
curl -fsSL "$RAW_BASE_URL/$package_path" -o "$archive"
|
|
else
|
|
wget -qO "$archive" "$RAW_BASE_URL/$package_path"
|
|
fi
|
|
|
|
actual_sha="$(shasum -a 256 "$archive" | awk '{print $1}')"
|
|
if [[ "$actual_sha" != "$expected_sha" ]]; then
|
|
echo "Checksum mismatch for $package_path" >&2
|
|
echo "expected: $expected_sha" >&2
|
|
echo "actual: $actual_sha" >&2
|
|
exit 1
|
|
fi
|
|
|
|
mkdir -p "$DEST_DIR"
|
|
target="$DEST_DIR/$SKILL_NAME"
|
|
if [[ -e "$target" ]]; then
|
|
backup="$target.backup.$(date +%Y%m%d%H%M%S)"
|
|
mv "$target" "$backup"
|
|
echo "Existing skill moved to $backup"
|
|
fi
|
|
|
|
tar -xzf "$archive" -C "$DEST_DIR"
|
|
echo "Installed $SKILL_NAME to $DEST_DIR/$SKILL_NAME"
|
|
echo "Restart Codex to pick up new skills."
|