#!/bin/sh # FaceNinja skill installer 1.0.0 (macOS, Linux, WSL). It copies the skill folder (SKILL.md, scripts/faceninja.py, # reference/api.md, README.md) into the skills folder of each AI agent it finds and changes nothing else. # # curl -fsSL https://faceninja.net/skill/install.sh | sh every agent found here # curl -fsSL https://faceninja.net/skill/install.sh | sh -s -- --claude only Claude Code (~/.claude/skills) # --codex (~/.codex/skills, $CODEX_HOME/skills) --cursor (./.cursor/skills) --agents (./.agents/skills) # --dir PATH (any skills folder) --agents-md (also add one line to ./AGENTS.md; otherwise it only asks) set -eu BASE="${FACENINJA_API_BASE:-https://faceninja.net}" BASE="${BASE%/}" # SHA-256 of each file, written by tools/skill/build.mjs; a download that does not match is refused SUMS=' e5042de77212ea11a0e93954d4e6733fe828481c270d0570d478792f982f9fdd SKILL.md 817bb11ae1244a32ff55d8ac10e0f19ab5e33565b7842dec3a0b3fece27a1bbb README.md 561461d99e29f4251ac76e31cee0f1fcbe7112c829c0481d52fd8505a60e6135 scripts/faceninja.py 5ba682b2b97c4144ccf20d1ed447e96dd5abf3742c47f00642b0ed083d4caba6 reference/api.md ' targets='' agents_md='' add() { case "$targets" in *"|$1|"*) ;; *) targets="$targets|$1|" ;; esac; } while [ $# -gt 0 ]; do case "$1" in --claude) add "${CLAUDE_CONFIG_DIR:-$HOME/.claude}/skills" ;; --codex) add "${CODEX_HOME:-$HOME/.codex}/skills" ;; --cursor) add "$PWD/.cursor/skills" ;; --agents) add "$PWD/.agents/skills" ;; --dir) shift; add "${1:?--dir needs a folder}" ;; --agents-md) agents_md=yes ;; -h|--help) sed -n '2,9p' "$0" 2>/dev/null || true; exit 0 ;; *) echo "Unknown option: $1" >&2; exit 2 ;; esac shift done if [ -z "$targets" ]; then if [ -n "${CLAUDE_CONFIG_DIR:-}" ]; then add "$CLAUDE_CONFIG_DIR/skills"; elif [ -d "$HOME/.claude" ]; then add "$HOME/.claude/skills"; fi if [ -n "${CODEX_HOME:-}" ]; then add "$CODEX_HOME/skills"; fi if [ -d "$HOME/.codex" ]; then add "$HOME/.codex/skills"; fi if [ -d "$PWD/.cursor" ]; then add "$PWD/.cursor/skills"; fi if [ -d "$PWD/.agents" ] || [ -z "$targets" ]; then add "$PWD/.agents/skills"; fi fi if command -v sha256sum >/dev/null 2>&1; then sha() { sha256sum "$1" | cut -d' ' -f1; } elif command -v shasum >/dev/null 2>&1; then sha() { shasum -a 256 "$1" | cut -d' ' -f1; } else sha() { echo unchecked; }; echo "Note: no sha256sum or shasum here; the downloads are not checked." >&2; fi tmp=$(mktemp -d) trap 'rm -rf "$tmp"' EXIT mkdir -p "$tmp/scripts" "$tmp/reference" echo "$SUMS" | while read -r want file; do [ -n "$file" ] || continue curl -fsSL "$BASE/skill/$file" -o "$tmp/$file" got=$(sha "$tmp/$file") if [ "$got" != unchecked ] && [ "$got" != "$want" ]; then echo "Checksum mismatch for $file; nothing was installed." >&2; exit 1; fi done chmod 755 "$tmp/scripts/faceninja.py" echo "Installed the FaceNinja skill 1.0.0 to:" printf '%s' "$targets" | tr '|' '\n' | while read -r dir; do [ -n "$dir" ] || continue mkdir -p "$dir/faceninja/scripts" "$dir/faceninja/reference" for file in SKILL.md README.md scripts/faceninja.py reference/api.md; do cp "$tmp/$file" "$dir/faceninja/$file"; done echo " $dir/faceninja" done case "$targets" in *"|$PWD/.agents/skills|"*) line='- FaceNinja (photos to MetaHuman heads): read .agents/skills/faceninja/SKILL.md' if [ -f AGENTS.md ] && grep -qF '.agents/skills/faceninja/SKILL.md' AGENTS.md; then : else if [ -z "$agents_md" ] && [ -t 1 ] && [ -r /dev/tty ]; then printf 'Add a line to ./AGENTS.md so agents find the skill? [y/N] ' read -r answer > AGENTS.md; echo "Added a line to ./AGENTS.md." else echo "Agents that read AGENTS.md find the skill if you add this line there (or rerun with --agents-md):"; echo " $line"; fi fi ;; esac py=$(command -v python3 || command -v python || true) [ -n "$py" ] || echo "Note: the skill needs Python 3.9 or newer, which was not found." >&2 echo "Next: ask your agent to use the FaceNinja skill, or run: ${py:-python3} /scripts/faceninja.py login"